[
  {
    "path": ".gitignore",
    "content": ".gradle\n.idea\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n*.iml\n*.apk\n*.jobf"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability."
  },
  {
    "path": "README.md",
    "content": "# CameraFilter\n[![Apache 2.0 License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0.html)\n\nRealtime camera filters. Process frames by OpenGL shaders.\n\n**[Download the apk](https://github.com/nekocode/CameraFilter/releases)** to have a try.\n\n## Filters\n\nThanks to the original authors of the shader codes. I just port them from webgl to opengl es.\n\n| Filter | Preview | Filter | Preview |\n| :----- | :------ | :----- | :------ |\n| [Edge Detection](https://www.shadertoy.com/view/Xtd3W7) | ![](art/1.png) | [Pixelize](https://www.shadertoy.com/view/4lXXDH) | ![](art/2.png)|\n| [EM Interference](https://www.shadertoy.com/view/lsXSWl) | ![](art/3.png)| [Triangles Mosaic](https://www.shadertoy.com/view/4d2SWy) | ![](art/4.png) |\n| [Legofied](https://www.shadertoy.com/view/XtBSzy) | ![](art/5.png) | [Tile Mosaic](https://www.shadertoy.com/view/MtfXRN) | ![](art/6.png) |\n| [Blueorange](https://www.shadertoy.com/view/MslGzr) | ![](art/7.png) | [Chromatic Aberration](https://www.shadertoy.com/view/Mds3zn) | ![](art/8.png) |\n| [Basic Deform](https://www.shadertoy.com/view/XdsGzH) | ![](art/9.png) | [Contrast](https://www.shadertoy.com/view/Xdf3RN) | ![](art/10.png) |\n| [NoiseWarp](https://www.shadertoy.com/view/4sX3RN) | ![](art/11.png) | [Refraction](https://www.shadertoy.com/view/MsX3zN) | ![](art/12.png) |\n| [Mapping](https://www.shadertoy.com/view/XsX3R7) | ![](art/13.png) | [Crosshatch](https://www.shadertoy.com/view/MdX3Dr) | ![](art/14.png) |\n| [Lichtenstein-esque](https://www.shadertoy.com/view/Mdf3zS) | ![](art/15.png) | [Ascii Art](https://www.shadertoy.com/view/lssGDj) | ![](art/16.png) |\n| [Money Filter](https://www.shadertoy.com/view/XlsXDN) | ![](art/17.png) | [Cracked](https://www.shadertoy.com/view/XdBSzW) | ![](art/18.png) |\n| [Polygonization](https://www.shadertoy.com/view/4lsXR7) | ![](art/19.png) | [JFA Voronoi](https://www.shadertoy.com/view/4sy3W3) | ![](art/20.png) |\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion \"28.0.3\"\n\n    defaultConfig {\n        applicationId \"cn.nekocode.camerafilter\"\n        minSdkVersion 15\n        targetSdkVersion 27\n        versionCode 212\n        versionName \"2.4\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \"libs\", include: [\"*.jar\"])\n    implementation \"com.android.support:appcompat-v7:27.1.1\"\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /usr/local/opt/android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"cn.nekocode.camerafilter\">\n\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n\n    <uses-feature\n        android:name=\"android.hardware.camera\"\n        android:required=\"true\"/>\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\"\n            >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/CameraRenderer.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter;\n\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Camera;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\nimport android.util.Log;\nimport android.util.Pair;\nimport android.util.SparseArray;\nimport android.view.TextureView;\n\nimport java.io.IOException;\n\nimport javax.microedition.khronos.egl.EGL10;\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.egl.EGLContext;\nimport javax.microedition.khronos.egl.EGLDisplay;\nimport javax.microedition.khronos.egl.EGLSurface;\n\nimport cn.nekocode.camerafilter.filter.AsciiArtFilter;\nimport cn.nekocode.camerafilter.filter.BasicDeformFilter;\nimport cn.nekocode.camerafilter.filter.BlackAndWhiteFilter;\nimport cn.nekocode.camerafilter.filter.BlueorangeFilter;\nimport cn.nekocode.camerafilter.filter.CameraFilter;\nimport cn.nekocode.camerafilter.filter.CartoonFilter;\nimport cn.nekocode.camerafilter.filter.CastingFilter;\nimport cn.nekocode.camerafilter.filter.ChromaticAberrationFilter;\nimport cn.nekocode.camerafilter.filter.ContrastFilter;\nimport cn.nekocode.camerafilter.filter.CrackedFilter;\nimport cn.nekocode.camerafilter.filter.CrosshatchFilter;\nimport cn.nekocode.camerafilter.filter.EMInterferenceFilter;\nimport cn.nekocode.camerafilter.filter.EdgeDetectionFilter;\nimport cn.nekocode.camerafilter.filter.GrayFilter;\nimport cn.nekocode.camerafilter.filter.HexagonMosaicFilter;\nimport cn.nekocode.camerafilter.filter.JFAVoronoiFilter;\nimport cn.nekocode.camerafilter.filter.LegofiedFilter;\nimport cn.nekocode.camerafilter.filter.LichtensteinEsqueFilter;\nimport cn.nekocode.camerafilter.filter.MappingFilter;\nimport cn.nekocode.camerafilter.filter.MirrorFilter;\nimport cn.nekocode.camerafilter.filter.MoneyFilter;\nimport cn.nekocode.camerafilter.filter.NegativeFilter;\nimport cn.nekocode.camerafilter.filter.NoiseWarpFilter;\nimport cn.nekocode.camerafilter.filter.NostalgiaFilter;\nimport cn.nekocode.camerafilter.filter.OriginalFilter;\nimport cn.nekocode.camerafilter.filter.PixelizeFilter;\nimport cn.nekocode.camerafilter.filter.PolygonizationFilter;\nimport cn.nekocode.camerafilter.filter.RefractionFilter;\nimport cn.nekocode.camerafilter.filter.ReliefFilter;\nimport cn.nekocode.camerafilter.filter.SwirlFilter;\nimport cn.nekocode.camerafilter.filter.TileMosaicFilter;\nimport cn.nekocode.camerafilter.filter.TrianglesMosaicFilter;\nimport cn.nekocode.camerafilter.filter.TripleFilter;\nimport cn.nekocode.camerafilter.filter.WaterReflectionFilter;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class CameraRenderer implements Runnable, TextureView.SurfaceTextureListener {\n    private static final String TAG = \"CameraRenderer\";\n    private static final int EGL_OPENGL_ES2_BIT = 4;\n    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;\n    private static final int DRAW_INTERVAL = 1000 / 30;\n\n    private Thread renderThread;\n    private Context context;\n    private SurfaceTexture surfaceTexture;\n    private int gwidth, gheight;\n\n    private EGLDisplay eglDisplay;\n    private EGLSurface eglSurface;\n    private EGLContext eglContext;\n    private EGL10 egl10;\n\n    private Camera camera;\n    private SurfaceTexture cameraSurfaceTexture;\n    private int cameraTextureId;\n    private CameraFilter selectedFilter;\n    private int selectedFilterId = R.id.filter0;\n    private SparseArray<CameraFilter> cameraFilterMap = new SparseArray<>();\n\n    public CameraRenderer(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void onSurfaceTextureUpdated(SurfaceTexture surface) {\n    }\n\n    @Override\n    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {\n        gwidth = -width;\n        gheight = -height;\n    }\n\n    @Override\n    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {\n        if (camera != null) {\n            camera.stopPreview();\n            camera.release();\n        }\n        if (renderThread != null && renderThread.isAlive()) {\n            renderThread.interrupt();\n        }\n        CameraFilter.release();\n\n        return true;\n    }\n\n    @Override\n    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {\n        if (renderThread != null && renderThread.isAlive()) {\n            renderThread.interrupt();\n        }\n        renderThread = new Thread(this);\n\n        surfaceTexture = surface;\n        gwidth = -width;\n        gheight = -height;\n\n        // Open camera\n        Pair<Camera.CameraInfo, Integer> backCamera = getBackCamera();\n        final int backCameraId = backCamera.second;\n        camera = Camera.open(backCameraId);\n\n        // Start rendering\n        renderThread.start();\n    }\n\n    public void setSelectedFilter(int id) {\n        selectedFilterId = id;\n        selectedFilter = cameraFilterMap.get(id);\n        if (selectedFilter != null)\n            selectedFilter.onAttach();\n    }\n\n    @Override\n    public void run() {\n        initGL(surfaceTexture);\n\n        // Setup camera filters map\n        cameraFilterMap.append(R.id.filter0, new OriginalFilter(context));\n        cameraFilterMap.append(R.id.filter1, new EdgeDetectionFilter(context));\n        cameraFilterMap.append(R.id.filter2, new PixelizeFilter(context));\n        cameraFilterMap.append(R.id.filter3, new EMInterferenceFilter(context));\n        cameraFilterMap.append(R.id.filter4, new TrianglesMosaicFilter(context));\n        cameraFilterMap.append(R.id.filter5, new LegofiedFilter(context));\n        cameraFilterMap.append(R.id.filter6, new TileMosaicFilter(context));\n        cameraFilterMap.append(R.id.filter7, new BlueorangeFilter(context));\n        cameraFilterMap.append(R.id.filter8, new ChromaticAberrationFilter(context));\n        cameraFilterMap.append(R.id.filter9, new BasicDeformFilter(context));\n        cameraFilterMap.append(R.id.filter10, new ContrastFilter(context));\n        cameraFilterMap.append(R.id.filter11, new NoiseWarpFilter(context));\n        cameraFilterMap.append(R.id.filter12, new RefractionFilter(context));\n        cameraFilterMap.append(R.id.filter13, new MappingFilter(context));\n        cameraFilterMap.append(R.id.filter14, new CrosshatchFilter(context));\n        cameraFilterMap.append(R.id.filter15, new LichtensteinEsqueFilter(context));\n        cameraFilterMap.append(R.id.filter16, new AsciiArtFilter(context));\n        cameraFilterMap.append(R.id.filter17, new MoneyFilter(context));\n        cameraFilterMap.append(R.id.filter18, new CrackedFilter(context));\n        cameraFilterMap.append(R.id.filter19, new PolygonizationFilter(context));\n        cameraFilterMap.append(R.id.filter20, new JFAVoronoiFilter(context));\n        cameraFilterMap.append(R.id.filter21, new BlackAndWhiteFilter(context));\n        cameraFilterMap.append(R.id.filter22, new GrayFilter(context));\n        cameraFilterMap.append(R.id.filter23, new NegativeFilter(context));\n        cameraFilterMap.append(R.id.filter24, new NostalgiaFilter(context));\n        cameraFilterMap.append(R.id.filter25, new CastingFilter(context));\n        cameraFilterMap.append(R.id.filter26, new ReliefFilter(context));\n        cameraFilterMap.append(R.id.filter27, new SwirlFilter(context));\n        cameraFilterMap.append(R.id.filter28, new HexagonMosaicFilter(context));\n        cameraFilterMap.append(R.id.filter29, new MirrorFilter(context));\n        cameraFilterMap.append(R.id.filter30, new TripleFilter(context));\n        cameraFilterMap.append(R.id.filter31, new CartoonFilter(context));\n        cameraFilterMap.append(R.id.filter32, new WaterReflectionFilter(context));\n        setSelectedFilter(selectedFilterId);\n\n        // Create texture for camera preview\n        cameraTextureId = MyGLUtils.genTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);\n        cameraSurfaceTexture = new SurfaceTexture(cameraTextureId);\n\n        // Start camera preview\n        try {\n            camera.setPreviewTexture(cameraSurfaceTexture);\n            camera.startPreview();\n        } catch (IOException ioe) {\n            // Something bad happened\n        }\n\n        // Render loop\n        while (!Thread.currentThread().isInterrupted()) {\n            try {\n                if (gwidth < 0 && gheight < 0)\n                    GLES20.glViewport(0, 0, gwidth = -gwidth, gheight = -gheight);\n\n                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n\n                // Update the camera preview texture\n                synchronized (this) {\n                    cameraSurfaceTexture.updateTexImage();\n                }\n\n                // Draw camera preview\n                selectedFilter.draw(cameraTextureId, gwidth, gheight);\n\n                // Flush\n                GLES20.glFlush();\n                egl10.eglSwapBuffers(eglDisplay, eglSurface);\n\n                Thread.sleep(DRAW_INTERVAL);\n\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        cameraSurfaceTexture.release();\n        GLES20.glDeleteTextures(1, new int[]{cameraTextureId}, 0);\n    }\n\n    private void initGL(SurfaceTexture texture) {\n        egl10 = (EGL10) EGLContext.getEGL();\n\n        eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);\n        if (eglDisplay == EGL10.EGL_NO_DISPLAY) {\n            throw new RuntimeException(\"eglGetDisplay failed \" +\n                    android.opengl.GLUtils.getEGLErrorString(egl10.eglGetError()));\n        }\n\n        int[] version = new int[2];\n        if (!egl10.eglInitialize(eglDisplay, version)) {\n            throw new RuntimeException(\"eglInitialize failed \" +\n                    android.opengl.GLUtils.getEGLErrorString(egl10.eglGetError()));\n        }\n\n        int[] configsCount = new int[1];\n        EGLConfig[] configs = new EGLConfig[1];\n        int[] configSpec = {\n                EGL10.EGL_RENDERABLE_TYPE,\n                EGL_OPENGL_ES2_BIT,\n                EGL10.EGL_RED_SIZE, 8,\n                EGL10.EGL_GREEN_SIZE, 8,\n                EGL10.EGL_BLUE_SIZE, 8,\n                EGL10.EGL_ALPHA_SIZE, 8,\n                EGL10.EGL_DEPTH_SIZE, 0,\n                EGL10.EGL_STENCIL_SIZE, 0,\n                EGL10.EGL_NONE\n        };\n\n        EGLConfig eglConfig = null;\n        if (!egl10.eglChooseConfig(eglDisplay, configSpec, configs, 1, configsCount)) {\n            throw new IllegalArgumentException(\"eglChooseConfig failed \" +\n                    android.opengl.GLUtils.getEGLErrorString(egl10.eglGetError()));\n        } else if (configsCount[0] > 0) {\n            eglConfig = configs[0];\n        }\n        if (eglConfig == null) {\n            throw new RuntimeException(\"eglConfig not initialized\");\n        }\n\n        int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};\n        eglContext = egl10.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);\n        eglSurface = egl10.eglCreateWindowSurface(eglDisplay, eglConfig, texture, null);\n\n        if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {\n            int error = egl10.eglGetError();\n            if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {\n                Log.e(TAG, \"eglCreateWindowSurface returned EGL10.EGL_BAD_NATIVE_WINDOW\");\n                return;\n            }\n            throw new RuntimeException(\"eglCreateWindowSurface failed \" +\n                    android.opengl.GLUtils.getEGLErrorString(error));\n        }\n\n        if (!egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {\n            throw new RuntimeException(\"eglMakeCurrent failed \" +\n                    android.opengl.GLUtils.getEGLErrorString(egl10.eglGetError()));\n        }\n    }\n\n    private Pair<Camera.CameraInfo, Integer> getBackCamera() {\n        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();\n        final int numberOfCameras = Camera.getNumberOfCameras();\n\n        for (int i = 0; i < numberOfCameras; ++i) {\n            Camera.getCameraInfo(i, cameraInfo);\n            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {\n                return new Pair<>(cameraInfo, i);\n            }\n        }\n        return null;\n    }\n}"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/MainActivity.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter;\n\nimport android.Manifest;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.GestureDetector;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.MotionEvent;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.Toast;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {\n    private static final int REQUEST_CAMERA_PERMISSION = 101;\n    private FrameLayout container;\n    private CameraRenderer renderer;\n    private TextureView textureView;\n    private int filterId = R.id.filter0;\n    private int mCurrentFilterId = 0;\n\n    String[] TITLES = {\"Original\", \"EdgeDectection\", \"Pixelize\",\n            \"EMInterference\", \"TrianglesMosaic\", \"Legofied\",\n            \"TileMosaic\", \"Blueorange\", \"ChromaticAberration\",\n            \"BasicDeform\", \"Contrast\", \"NoiseWarp\", \"Refraction\",\n            \"Mapping\", \"Crosshatch\", \"LichtensteinEsque\",\n            \"AsciiArt\", \"MoneyFilter\", \"Cracked\", \"Polygonization\",\n            \"JFAVoronoi\", \"BlackAndWhite\", \"Gray\", \"Negative\",\n            \"Nostalgia\", \"Casting\", \"Relief\", \"Swirl\", \"HexagonMosaic\",\n            \"Mirror\", \"Triple\", \"Cartoon\", \"WaterReflection\"\n    };\n\n    Integer[] FILTER_RES_IDS = {R.id.filter0, R.id.filter1, R.id.filter2, R.id.filter3, R.id.filter4,\n            R.id.filter5, R.id.filter6, R.id.filter7, R.id.filter8, R.id.filter9, R.id.filter10,\n            R.id.filter11, R.id.filter12, R.id.filter13, R.id.filter14, R.id.filter15, R.id.filter16,\n            R.id.filter17, R.id.filter18, R.id.filter19, R.id.filter20,\n            R.id.filter21, R.id.filter22, R.id.filter23, R.id.filter24,\n            R.id.filter25, R.id.filter26, R.id.filter27, R.id.filter28,\n            R.id.filter29, R.id.filter30, R.id.filter31, R.id.filter32};\n\n    ArrayList<Integer> mFilterArray = new ArrayList<>(Arrays.asList(FILTER_RES_IDS));\n\n    GestureDetector mGestureDetector;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(container = new FrameLayout(this));\n        setTitle(TITLES[mCurrentFilterId]);\n\n\n        if (ContextCompat.checkSelfPermission(this,\n                Manifest.permission.CAMERA)\n                != PackageManager.PERMISSION_GRANTED) {\n\n            // Should we show an explanation?\n            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {\n                Toast.makeText(this, \"Camera access is required.\", Toast.LENGTH_SHORT).show();\n\n            } else {\n                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},\n                        REQUEST_CAMERA_PERMISSION);\n            }\n\n        } else {\n            setupCameraPreviewView();\n        }\n\n        mGestureDetector = new GestureDetector(this, this);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {\n        switch (requestCode) {\n            case REQUEST_CAMERA_PERMISSION: {\n                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    setupCameraPreviewView();\n                }\n            }\n        }\n    }\n\n    void setupCameraPreviewView() {\n        renderer = new CameraRenderer(this);\n        textureView = new TextureView(this);\n        container.addView(textureView);\n        textureView.setSurfaceTextureListener(renderer);\n\n//        textureView.setOnTouchListener(this);\n        textureView.setOnTouchListener(new View.OnTouchListener() {\n            @Override\n            public boolean onTouch(View view, MotionEvent motionEvent) {\n                mGestureDetector.onTouchEvent(motionEvent);\n                return true;\n            }\n        });\n\n        textureView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {\n            @Override\n            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {\n                renderer.onSurfaceTextureSizeChanged(null, v.getWidth(), v.getHeight());\n            }\n        });\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.filter, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        filterId = item.getItemId();\n\n        // TODO: need tidy up\n        if (filterId == R.id.capture) {\n            Toast.makeText(this,\n                    capture() ? \"The capture has been saved to your sdcard root path.\" :\n                            \"Save failed!\",\n                    Toast.LENGTH_SHORT).show();\n            return true;\n        }\n\n        setTitle(item.getTitle());\n\n        if (renderer != null)\n            renderer.setSelectedFilter(filterId);\n        mCurrentFilterId = mFilterArray.indexOf(filterId);\n        return true;\n    }\n\n    private boolean capture() {\n        String mPath = genSaveFileName(getTitle().toString() + \"_\", \".png\");\n        File imageFile = new File(mPath);\n        if (imageFile.exists()) {\n            imageFile.delete();\n        }\n\n        // create bitmap screen capture\n        Bitmap bitmap = textureView.getBitmap();\n        OutputStream outputStream = null;\n\n        try {\n            outputStream = new FileOutputStream(imageFile);\n            bitmap.compress(Bitmap.CompressFormat.PNG, 90, outputStream);\n            outputStream.flush();\n            outputStream.close();\n\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n            return false;\n        } catch (IOException e) {\n            e.printStackTrace();\n            return false;\n        }\n\n        return true;\n    }\n\n    private String genSaveFileName(String prefix, String suffix) {\n        Date date = new Date();\n        SimpleDateFormat dateformat1 = new SimpleDateFormat(\"yyyyMMdd_hhmmss\");\n        String timeString = dateformat1.format(date);\n        String externalPath = Environment.getExternalStorageDirectory().toString();\n        return externalPath + \"/\" + prefix + timeString + suffix;\n    }\n\n    @Override\n    public boolean onDown(MotionEvent motionEvent) {\n\n        return false;\n    }\n\n    @Override\n    public void onShowPress(MotionEvent motionEvent) {\n\n    }\n\n    @Override\n    public boolean onSingleTapUp(MotionEvent motionEvent) {\n        return false;\n    }\n\n    @Override\n    public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {\n        return false;\n    }\n\n    @Override\n    public void onLongPress(MotionEvent motionEvent) {\n\n    }\n\n    @Override\n    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n        float velocity = Math.abs(velocityX) > Math.abs(velocityY) ? velocityX : velocityY;\n        int step = velocity > 0 ? -1 : 1;\n        mCurrentFilterId = circleLoop(TITLES.length, mCurrentFilterId, step);\n        setTitle(TITLES[mCurrentFilterId]);\n        if (renderer != null) {\n            renderer.setSelectedFilter(FILTER_RES_IDS[mCurrentFilterId]);\n        }\n        return true;\n    }\n\n    private int circleLoop(int size, int currentPos, int step) {\n        if (step == 0) {\n            return currentPos;\n        }\n\n        if (step > 0) {\n            if (currentPos + step >= size) {\n                return (currentPos + step) % size;\n            } else {\n                return currentPos + step;\n            }\n        } else {\n            if (currentPos + step < 0) {\n                return currentPos + step + size;\n            } else {\n                return currentPos + step;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/MyGLUtils.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\nimport android.opengl.GLUtils;\nimport android.util.Log;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.microedition.khronos.opengles.GL10;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class MyGLUtils {\n    private static final String TAG = \"MyGLUtils\";\n\n    public static int genTexture() {\n        return genTexture(GLES20.GL_TEXTURE_2D);\n    }\n\n    public static int genTexture(int textureType) {\n        int[] genBuf = new int[1];\n        GLES20.glGenTextures(1, genBuf, 0);\n        GLES20.glBindTexture(textureType, genBuf[0]);\n\n        // Set texture default draw parameters\n        if (textureType == GLES11Ext.GL_TEXTURE_EXTERNAL_OES) {\n            GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);\n            GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);\n            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);\n            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);\n\n        } else {\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);\n            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);\n            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);\n        }\n\n        return genBuf[0];\n    }\n\n    public static int loadTexture(final Context context, final int resourceId, int[] size) {\n        final int texId = genTexture();\n\n        if (texId != 0) {\n            final BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inScaled = false;   // No pre-scaling\n            options.inJustDecodeBounds = true;\n\n            // Just decode bounds\n            BitmapFactory.decodeResource(context.getResources(), resourceId, options);\n\n            // Set return size\n            size[0] = options.outWidth;\n            size[1] = options.outHeight;\n\n            // Decode\n            options.inJustDecodeBounds = false;\n            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);\n\n            // Load the bitmap into the bound texture.\n            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);\n\n            // Recycle the bitmap, since its data has been loaded into OpenGL.\n            bitmap.recycle();\n        }\n\n        return texId;\n    }\n\n    public static int buildProgram(Context context, int vertexSourceRawId, int fragmentSourceRawId) {\n        return buildProgram(getStringFromRaw(context, vertexSourceRawId),\n                getStringFromRaw(context, fragmentSourceRawId));\n    }\n\n    public static int buildProgram(String vertexSource, String fragmentSource) {\n        final int vertexShader = buildShader(GLES20.GL_VERTEX_SHADER, vertexSource);\n        if (vertexShader == 0) {\n            return 0;\n        }\n\n        final int fragmentShader = buildShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);\n        if (fragmentShader == 0) {\n            return 0;\n        }\n\n        final int program = GLES20.glCreateProgram();\n        if (program == 0) {\n            return 0;\n        }\n\n        GLES20.glAttachShader(program, vertexShader);\n        GLES20.glAttachShader(program, fragmentShader);\n        GLES20.glLinkProgram(program);\n\n        return program;\n    }\n\n    public static int buildShader(int type, String shaderSource) {\n        final int shader = GLES20.glCreateShader(type);\n        if (shader == 0) {\n            return 0;\n        }\n\n        GLES20.glShaderSource(shader, shaderSource);\n        GLES20.glCompileShader(shader);\n\n        int[] status = new int[1];\n        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, status, 0);\n        if (status[0] == 0) {\n            Log.e(TAG, GLES20.glGetShaderInfoLog(shader));\n            GLES20.glDeleteShader(shader);\n            return 0;\n        }\n\n        return shader;\n    }\n\n    private static String getStringFromRaw(Context context, int id) {\n        String str;\n        try {\n            Resources r = context.getResources();\n            InputStream is = r.openRawResource(id);\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            int i = is.read();\n            while (i != -1) {\n                baos.write(i);\n                i = is.read();\n            }\n\n            str = baos.toString();\n            is.close();\n        } catch (IOException e) {\n            str = \"\";\n        }\n\n        return str;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/RenderBuffer.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter;\n\nimport android.opengl.GLES20;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.IntBuffer;\n\nimport javax.microedition.khronos.opengles.GL10;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class RenderBuffer {\n    private int texId = 0;\n    private int activeTexUnit = 0;\n    private int renderBufferId = 0;\n    private int frameBufferId = 0;\n\n    private int width, height;\n\n    public RenderBuffer(int width, int height, int activeTexUnit) {\n        this.width = width;\n        this.height = height;\n        this.activeTexUnit = activeTexUnit;\n        int[] genbuf = new int[1];\n\n        // Generate and bind 2d texture\n        GLES20.glActiveTexture(activeTexUnit);\n        texId = MyGLUtils.genTexture();\n        IntBuffer texBuffer =\n                ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder()).asIntBuffer();\n        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, texBuffer);\n\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);\n\n        // Generate frame buffer\n        GLES20.glGenFramebuffers(1, genbuf, 0);\n        frameBufferId = genbuf[0];\n        // Bind frame buffer\n        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);\n\n        // Generate render buffer\n        GLES20.glGenRenderbuffers(1, genbuf, 0);\n        renderBufferId = genbuf[0];\n        // Bind render buffer\n        GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferId);\n        GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height);\n\n        unbind();\n    }\n\n    public int getTexId() {\n        return texId;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public int getActiveTexUnit() {\n        return activeTexUnit;\n    }\n\n    public void bind() {\n        GLES20.glViewport(0, 0, width, height);\n\n        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);\n        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,\n                GLES20.GL_TEXTURE_2D, texId, 0);\n        GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,\n                GLES20.GL_RENDERBUFFER, renderBufferId);\n    }\n\n    public void unbind() {\n        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/AsciiArtFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class AsciiArtFilter extends CameraFilter {\n    private int program;\n\n    public AsciiArtFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.ascii_art);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/BasicDeformFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class BasicDeformFilter extends CameraFilter {\n    private int program;\n\n    public BasicDeformFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.basic_deform);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/BlackAndWhiteFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class BlackAndWhiteFilter extends CameraFilter {\n    private int program;\n\n    public BlackAndWhiteFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.black_and_white);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/BlueorangeFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class BlueorangeFilter extends CameraFilter {\n    private int program;\n\n    public BlueorangeFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.blue_orange);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/CameraFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\nimport android.support.annotation.CallSuper;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\nimport cn.nekocode.camerafilter.RenderBuffer;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic abstract class CameraFilter {\n    static final float SQUARE_COORDS[] = {\n            1.0f, -1.0f,\n            -1.0f, -1.0f,\n            1.0f, 1.0f,\n            -1.0f, 1.0f,\n    };\n    static final float TEXTURE_COORDS[] = {\n            1.0f, 0.0f,\n            0.0f, 0.0f,\n            1.0f, 1.0f,\n            0.0f, 1.0f,\n    };\n    static FloatBuffer VERTEX_BUF, TEXTURE_COORD_BUF;\n    static int PROGRAM = 0;\n\n    private static final int BUF_ACTIVE_TEX_UNIT = GLES20.GL_TEXTURE8;\n    private static RenderBuffer CAMERA_RENDER_BUF;\n\n    private static final float ROATED_TEXTURE_COORDS[] = {\n            1.0f, 0.0f,\n            1.0f, 1.0f,\n            0.0f, 0.0f,\n            0.0f, 1.0f,\n    };\n    private static FloatBuffer ROATED_TEXTURE_COORD_BUF;\n\n    final long START_TIME = System.currentTimeMillis();\n    int iFrame = 0;\n\n    public CameraFilter(Context context) {\n        // Setup default Buffers\n        if (VERTEX_BUF == null) {\n            VERTEX_BUF = ByteBuffer.allocateDirect(SQUARE_COORDS.length * 4)\n                    .order(ByteOrder.nativeOrder()).asFloatBuffer();\n            VERTEX_BUF.put(SQUARE_COORDS);\n            VERTEX_BUF.position(0);\n        }\n\n        if (TEXTURE_COORD_BUF == null) {\n            TEXTURE_COORD_BUF = ByteBuffer.allocateDirect(TEXTURE_COORDS.length * 4)\n                    .order(ByteOrder.nativeOrder()).asFloatBuffer();\n            TEXTURE_COORD_BUF.put(TEXTURE_COORDS);\n            TEXTURE_COORD_BUF.position(0);\n        }\n\n        if (ROATED_TEXTURE_COORD_BUF == null) {\n            ROATED_TEXTURE_COORD_BUF = ByteBuffer.allocateDirect(ROATED_TEXTURE_COORDS.length * 4)\n                    .order(ByteOrder.nativeOrder()).asFloatBuffer();\n            ROATED_TEXTURE_COORD_BUF.put(ROATED_TEXTURE_COORDS);\n            ROATED_TEXTURE_COORD_BUF.position(0);\n        }\n\n        if (PROGRAM == 0) {\n            PROGRAM = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.original_rtt);\n        }\n    }\n\n    @CallSuper\n    public void onAttach() {\n        iFrame = 0;\n    }\n\n    final public void draw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        // TODO move?\n        // Create camera render buffer\n        if (CAMERA_RENDER_BUF == null ||\n                CAMERA_RENDER_BUF.getWidth() != canvasWidth ||\n                CAMERA_RENDER_BUF.getHeight() != canvasHeight) {\n            CAMERA_RENDER_BUF = new RenderBuffer(canvasWidth, canvasHeight, BUF_ACTIVE_TEX_UNIT);\n        }\n\n        // Use shaders\n        GLES20.glUseProgram(PROGRAM);\n\n        int iChannel0Location = GLES20.glGetUniformLocation(PROGRAM, \"iChannel0\");\n        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);\n        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTexId);\n        GLES20.glUniform1i(iChannel0Location, 0);\n\n        int vPositionLocation = GLES20.glGetAttribLocation(PROGRAM, \"vPosition\");\n        GLES20.glEnableVertexAttribArray(vPositionLocation);\n        GLES20.glVertexAttribPointer(vPositionLocation, 2, GLES20.GL_FLOAT, false, 4 * 2, VERTEX_BUF);\n\n        int vTexCoordLocation = GLES20.glGetAttribLocation(PROGRAM, \"vTexCoord\");\n        GLES20.glEnableVertexAttribArray(vTexCoordLocation);\n        GLES20.glVertexAttribPointer(vTexCoordLocation, 2, GLES20.GL_FLOAT, false, 4 * 2, ROATED_TEXTURE_COORD_BUF);\n\n        // Render to texture\n        CAMERA_RENDER_BUF.bind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n        CAMERA_RENDER_BUF.unbind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n\n        onDraw(CAMERA_RENDER_BUF.getTexId(), canvasWidth, canvasHeight);\n\n        iFrame++;\n    }\n\n    abstract void onDraw(int cameraTexId, int canvasWidth, int canvasHeight);\n\n    void setupShaderInputs(int program, int[] iResolution, int[] iChannels, int[][] iChannelResolutions) {\n        setupShaderInputs(program, VERTEX_BUF, TEXTURE_COORD_BUF, iResolution, iChannels, iChannelResolutions);\n    }\n\n    void setupShaderInputs(int program, FloatBuffer vertex, FloatBuffer textureCoord, int[] iResolution, int[] iChannels, int[][] iChannelResolutions) {\n        GLES20.glUseProgram(program);\n\n        int iResolutionLocation = GLES20.glGetUniformLocation(program, \"iResolution\");\n        GLES20.glUniform3fv(iResolutionLocation, 1,\n                FloatBuffer.wrap(new float[]{(float) iResolution[0], (float) iResolution[1], 1.0f}));\n\n        float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;\n        int iGlobalTimeLocation = GLES20.glGetUniformLocation(program, \"iGlobalTime\");\n        GLES20.glUniform1f(iGlobalTimeLocation, time);\n\n        int iFrameLocation = GLES20.glGetUniformLocation(program, \"iFrame\");\n        GLES20.glUniform1i(iFrameLocation, iFrame);\n\n        int vPositionLocation = GLES20.glGetAttribLocation(program, \"vPosition\");\n        GLES20.glEnableVertexAttribArray(vPositionLocation);\n        GLES20.glVertexAttribPointer(vPositionLocation, 2, GLES20.GL_FLOAT, false, 4 * 2, vertex);\n\n        int vTexCoordLocation = GLES20.glGetAttribLocation(program, \"vTexCoord\");\n        GLES20.glEnableVertexAttribArray(vTexCoordLocation);\n        GLES20.glVertexAttribPointer(vTexCoordLocation, 2, GLES20.GL_FLOAT, false, 4 * 2, textureCoord);\n\n        for (int i = 0; i < iChannels.length; i++) {\n            int sTextureLocation = GLES20.glGetUniformLocation(program, \"iChannel\" + i);\n            GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iChannels[i]);\n            GLES20.glUniform1i(sTextureLocation, i);\n        }\n\n        float _iChannelResolutions[] = new float[iChannelResolutions.length * 3];\n        for (int i = 0; i < iChannelResolutions.length; i++) {\n            _iChannelResolutions[i * 3] = iChannelResolutions[i][0];\n            _iChannelResolutions[i * 3 + 1] = iChannelResolutions[i][1];\n            _iChannelResolutions[i * 3 + 2] = 1.0f;\n        }\n\n        int iChannelResolutionLocation = GLES20.glGetUniformLocation(program, \"iChannelResolution\");\n        GLES20.glUniform3fv(iChannelResolutionLocation,\n                _iChannelResolutions.length, FloatBuffer.wrap(_iChannelResolutions));\n    }\n\n    public static void release() {\n        PROGRAM = 0;\n        CAMERA_RENDER_BUF = null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/CartoonFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class CartoonFilter extends CameraFilter {\n    private int program;\n\n    public CartoonFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.cartoon);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/CastingFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class CastingFilter extends CameraFilter {\n    private int program;\n\n    public CastingFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.casting);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/ChromaticAberrationFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class ChromaticAberrationFilter extends CameraFilter {\n    private int program;\n\n    public ChromaticAberrationFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.chromatic_aberration);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/ContrastFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class ContrastFilter extends CameraFilter {\n    private int program;\n\n    public ContrastFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.contrast);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/CrackedFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class CrackedFilter extends CameraFilter {\n    private int program;\n\n    public CrackedFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.cracked);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/CrosshatchFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class CrosshatchFilter extends CameraFilter {\n    private int program;\n\n    public CrosshatchFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.crosshatch);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/EMInterferenceFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class EMInterferenceFilter extends CameraFilter {\n    private int program;\n\n    public EMInterferenceFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.em_interference);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/EdgeDetectionFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class EdgeDetectionFilter extends CameraFilter {\n    private int program;\n\n    public EdgeDetectionFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.edge_detection);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/GrayFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class GrayFilter extends CameraFilter {\n    private int program;\n\n    public GrayFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.gray);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/HexagonMosaicFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class HexagonMosaicFilter extends CameraFilter {\n    private int program;\n\n    public HexagonMosaicFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.hexagon_mosaic);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/JFAVoronoiFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\nimport cn.nekocode.camerafilter.RenderBuffer;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class JFAVoronoiFilter extends CameraFilter {\n    private int programImg;\n    private int programA;\n    private int programB;\n    private int programC;\n\n    private RenderBuffer bufA;\n    private RenderBuffer bufB;\n    private RenderBuffer bufC;\n\n    public JFAVoronoiFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        programImg = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi);\n        programA = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_a);\n        programB = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_b);\n        programC = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_c);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        // TODO move?\n        if (bufA == null || bufA.getWidth() != canvasWidth || bufB.getHeight() != canvasHeight) {\n            // Create new textures for buffering\n            bufA = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE4);\n            bufB = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE5);\n            bufC = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE6);\n        }\n\n        // Render to buf a\n        setupShaderInputs(programA,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId, bufA.getTexId()},\n                new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}});\n        bufA.bind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n        bufA.unbind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n\n\n        // Render to buf b\n        setupShaderInputs(programB,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{bufB.getTexId(), bufA.getTexId()},\n                new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}});\n        bufB.bind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n        bufB.unbind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n\n\n        // Render to buf c\n        setupShaderInputs(programC,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{bufC.getTexId(), bufB.getTexId()},\n                new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}});\n        bufC.bind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n        bufC.unbind();\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);\n\n\n        // Render to screen\n        setupShaderInputs(programImg,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{bufC.getTexId(), bufA.getTexId()},\n                new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/LegofiedFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class LegofiedFilter extends CameraFilter {\n    private int program;\n\n    public LegofiedFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.legofied);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/LichtensteinEsqueFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class LichtensteinEsqueFilter extends CameraFilter {\n    private int program;\n\n    public LichtensteinEsqueFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.lichtenstein_esque);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/MappingFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class MappingFilter extends CameraFilter {\n    private int program;\n    private int texture2Id;\n\n    public MappingFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.mapping);\n\n        // Load the texture will need for the shader\n        texture2Id = MyGLUtils.loadTexture(context, R.raw.tex00, new int[2]);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId, texture2Id},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/MirrorFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class MirrorFilter extends CameraFilter {\n    private int program;\n\n    public MirrorFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.mirror);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/MoneyFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class MoneyFilter extends CameraFilter {\n    private int program;\n\n    public MoneyFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.money_filter);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/NegativeFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class NegativeFilter extends CameraFilter {\n    private int program;\n\n    public NegativeFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.negative);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/NoiseWarpFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class NoiseWarpFilter extends CameraFilter {\n    private int program;\n\n    public NoiseWarpFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.noise_warp);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/NostalgiaFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class NostalgiaFilter extends CameraFilter {\n    private int program;\n\n    public NostalgiaFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.nostalgia);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/OriginalFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class OriginalFilter extends CameraFilter {\n    private int program;\n\n    public OriginalFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.original);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/PixelizeFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class PixelizeFilter extends CameraFilter {\n    private int program;\n\n    public PixelizeFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.pixelize);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/PolygonizationFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class PolygonizationFilter extends CameraFilter {\n    private int program;\n\n    public PolygonizationFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.polygonization);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/RefractionFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class RefractionFilter extends CameraFilter {\n    private int program;\n    private int texture2Id;\n\n    public RefractionFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.refraction);\n\n        // Load the texture will need for the shader\n        texture2Id = MyGLUtils.loadTexture(context, R.raw.tex11, new int[2]);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId, texture2Id},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/ReliefFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class ReliefFilter extends CameraFilter {\n    private int program;\n\n    public ReliefFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.relief);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/SwirlFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class SwirlFilter extends CameraFilter {\n    private int program;\n\n    public SwirlFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.swirl);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/TileMosaicFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class TileMosaicFilter extends CameraFilter {\n    private int program;\n\n    public TileMosaicFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.tile_mosaic);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/TrianglesMosaicFilter.java",
    "content": "/*\n * Copyright 2016 nekocode\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author nekocode (nekocode.cn@gmail.com)\n */\npublic class TrianglesMosaicFilter extends CameraFilter {\n    private int program;\n\n    public TrianglesMosaicFilter(Context context) {\n        super(context);\n\n        // Build shaders\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.triangles_mosaic);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/TripleFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class TripleFilter extends CameraFilter {\n    private int program;\n\n    public TripleFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.triple);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/cn/nekocode/camerafilter/filter/WaterReflectionFilter.java",
    "content": "/*\n * Copyright 2016 winston\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.nekocode.camerafilter.filter;\n\nimport android.content.Context;\nimport android.opengl.GLES20;\n\nimport cn.nekocode.camerafilter.MyGLUtils;\nimport cn.nekocode.camerafilter.R;\n\n/**\n * @author winston (1054669137@qq.com)\n */\npublic class WaterReflectionFilter extends CameraFilter {\n    private int program;\n\n    public WaterReflectionFilter(Context context) {\n        super(context);\n        program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.water_reflection);\n    }\n\n    @Override\n    public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) {\n        setupShaderInputs(program,\n                new int[]{canvasWidth, canvasHeight},\n                new int[]{cameraTexId},\n                new int[][]{});\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/menu/filter.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/capture\"\n        android:icon=\"@android:drawable/ic_menu_camera\"\n        android:title=\"Capture\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/filter0\"\n        android:title=\"Original\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter1\"\n        android:title=\"EdgeDectection\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter2\"\n        android:title=\"Pixelize\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter3\"\n        android:title=\"EMInterference\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter4\"\n        android:title=\"TrianglesMosaic\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter5\"\n        android:title=\"Legofied\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter6\"\n        android:title=\"TileMosaic\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter7\"\n        android:title=\"Blueorange\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter8\"\n        android:title=\"ChromaticAberration\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter9\"\n        android:title=\"BasicDeform\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter10\"\n        android:title=\"Contrast\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter11\"\n        android:title=\"NoiseWarp\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter12\"\n        android:title=\"Refraction\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter13\"\n        android:title=\"Mapping\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter14\"\n        android:title=\"Crosshatch\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter15\"\n        android:title=\"LichtensteinEsque\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter16\"\n        android:title=\"AsciiArt\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter17\"\n        android:title=\"MoneyFilter\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter18\"\n        android:title=\"Cracked\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter19\"\n        android:title=\"Polygonization\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter20\"\n        android:title=\"JFAVoronoi\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter21\"\n        android:title=\"BlackAndWhite\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter22\"\n        android:title=\"Gray\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter23\"\n        android:title=\"Negative\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter24\"\n        android:title=\"Nostalgia\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter25\"\n        android:title=\"Casting\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter26\"\n        android:title=\"Relief\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter27\"\n        android:title=\"Swirl\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter28\"\n        android:title=\"HexagonMosaic\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter29\"\n        android:title=\"Mirror\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter30\"\n        android:title=\"Triple\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter31\"\n        android:title=\"Cartoon\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/filter32\"\n        android:title=\"WaterReflection\"\n        app:showAsAction=\"never\" />\n\n</menu>\n"
  },
  {
    "path": "app/src/main/res/raw/ascii_art.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n// referenced the method of bitmap of iq : https://www.shadertoy.com/view/4dfXWj\n\n#define r iResolution.xy\n#define t iGlobalTime\n\n#define zoom 2.\n\n#define P(id,a,b,c,d,e,f,g,h) if( id == int(pos.y) ){ int pa = a+2*(b+2*(c+2*(d+2*(e+2*(f+2*(g+2*(h))))))); cha = floor(mod(float(pa)/pow(2.,float(pos.x)-1.),2.)); }\n\nfloat gray(vec3 _i)\n{\n    return (_i.x+_i.y+_i.z)/3.;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 uv = vec2(floor(fragCoord.x/8./zoom)*8.*zoom,floor(fragCoord.y/12./zoom)*12.*zoom)/r;\n    ivec2 pos = ivec2(mod(fragCoord.x/zoom,8.),mod(fragCoord.y/zoom,12.));\n    vec4 tex = texture2D(iChannel0,uv);\n    float cha = 0.;\n\n    {\n        float g = gray(tex.xyz);\n        if( g < .125 )\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,0,0,0,0,0);\n            P(9,0,0,0,0,0,0,0,0);\n            P(8,0,0,0,0,0,0,0,0);\n            P(7,0,0,0,0,0,0,0,0);\n            P(6,0,0,0,0,0,0,0,0);\n            P(5,0,0,0,0,0,0,0,0);\n            P(4,0,0,0,0,0,0,0,0);\n            P(3,0,0,0,0,0,0,0,0);\n            P(2,0,0,0,0,0,0,0,0);\n            P(1,0,0,0,0,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if( g < .25 ) // .\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,0,0,0,0,0);\n            P(9,0,0,0,0,0,0,0,0);\n            P(8,0,0,0,0,0,0,0,0);\n            P(7,0,0,0,0,0,0,0,0);\n            P(6,0,0,0,0,0,0,0,0);\n            P(5,0,0,0,0,0,0,0,0);\n            P(4,0,0,0,1,1,0,0,0);\n            P(3,0,0,0,1,1,0,0,0);\n            P(2,0,0,0,0,0,0,0,0);\n            P(1,0,0,0,0,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if( g < .375 ) // ,\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,0,0,0,0,0);\n            P(9,0,0,0,0,0,0,0,0);\n            P(8,0,0,0,0,0,0,0,0);\n            P(7,0,0,0,0,0,0,0,0);\n            P(6,0,0,0,0,0,0,0,0);\n            P(5,0,0,0,0,0,0,0,0);\n            P(4,0,0,0,1,1,0,0,0);\n            P(3,0,0,0,1,1,0,0,0);\n            P(2,0,0,0,0,1,0,0,0);\n            P(1,0,0,0,1,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if( g < .5 ) // -\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,0,0,0,0,0);\n            P(9,0,0,0,0,0,0,0,0);\n            P(8,0,0,0,0,0,0,0,0);\n            P(7,0,0,0,0,0,0,0,0);\n            P(6,1,1,1,1,1,1,1,0);\n            P(5,0,0,0,0,0,0,0,0);\n            P(4,0,0,0,0,0,0,0,0);\n            P(3,0,0,0,0,0,0,0,0);\n            P(2,0,0,0,0,0,0,0,0);\n            P(1,0,0,0,0,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if(g < .625 ) // +\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,0,0,0,0,0);\n            P(9,0,0,0,1,0,0,0,0);\n            P(8,0,0,0,1,0,0,0,0);\n            P(7,0,0,0,1,0,0,0,0);\n            P(6,1,1,1,1,1,1,1,0);\n            P(5,0,0,0,1,0,0,0,0);\n            P(4,0,0,0,1,0,0,0,0);\n            P(3,0,0,0,1,0,0,0,0);\n            P(2,0,0,0,0,0,0,0,0);\n            P(1,0,0,0,0,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if(g < .75 ) // *\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,0,1,0,0,0,0);\n            P(9,1,0,0,1,0,0,1,0);\n            P(8,0,1,0,1,0,1,0,0);\n            P(7,0,0,1,1,1,0,0,0);\n            P(6,0,0,0,1,0,0,0,0);\n            P(5,0,0,1,1,1,0,0,0);\n            P(4,0,1,0,1,0,1,0,0);\n            P(3,1,0,0,1,0,0,1,0);\n            P(2,0,0,0,1,0,0,0,0);\n            P(1,0,0,0,0,0,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else if(g < .875 ) // #\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,1,0,0,1,0,0);\n            P(9,0,0,1,0,0,1,0,0);\n            P(8,1,1,1,1,1,1,1,0);\n            P(7,0,0,1,0,0,1,0,0);\n            P(6,0,0,1,0,0,1,0,0);\n            P(5,0,1,0,0,1,0,0,0);\n            P(4,0,1,0,0,1,0,0,0);\n            P(3,1,1,1,1,1,1,1,0);\n            P(2,0,1,0,0,1,0,0,0);\n            P(1,0,1,0,0,1,0,0,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n        else // @\n        {\n            P(11,0,0,0,0,0,0,0,0);\n            P(10,0,0,1,1,1,1,0,0);\n            P(9,0,1,0,0,0,0,1,0);\n            P(8,1,0,0,0,1,1,1,0);\n            P(7,1,0,0,1,0,0,1,0);\n            P(6,1,0,0,1,0,0,1,0);\n            P(5,1,0,0,1,0,0,1,0);\n            P(4,1,0,0,1,0,0,1,0);\n            P(3,1,0,0,1,1,1,1,0);\n            P(2,0,1,0,0,0,0,0,0);\n            P(1,0,0,1,1,1,1,1,0);\n            P(0,0,0,0,0,0,0,0,0);\n        }\n\t}\n\n    vec3 col = vec3(1.);\n    fragColor = vec4(cha*col,1.);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord * iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/basic_deform.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\t\n\tfloat stongth = 0.3;\n\tvec2 uv = fragCoord.xy;\n\tfloat waveu = sin((uv.y + iGlobalTime) * 20.0) * 0.5 * 0.05 * stongth;\n\tfragColor = texture2D(iChannel0, uv + vec2(waveu, 0));\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/black_and_white.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec4 mask = texture2D(iChannel0, fragCoord);\n    float color = (mask.r + mask.g + mask.b) / 3.0;\n    color = step(0.5, color);\n    vec4 tempColor = vec4(color, color, color, 1.0);\n    fragColor = tempColor;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/blue_orange.fsh",
    "content": "precision mediump float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 uv = fragCoord.xy;\n\t\n\tvec3 tex = texture2D( iChannel0, uv ).rgb;\n\tfloat shade = dot(tex, vec3(0.333333));\n\n\tvec3 col = mix(vec3(0.1, 0.36, 0.8) * (1.0-2.0*abs(shade-0.5)), vec3(1.06, 0.8, 0.55), 1.0-shade);\n\t\n    fragColor = vec4(col,1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/cartoon.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n    vec4 color = texture2D(iChannel0, fragCoord);\n    float newR = abs(color.r + color.g * 2.0 - color.b) * color.r;\n    float newG = abs(color.r + color.b * 2.0 - color.g) * color.r;\n    float newB = abs(color.r + color.b * 2.0 - color.g) * color.g;\n\tvec4 newColor = vec4(newR, newG, newB, 1.0);\n\tfragColor = newColor;\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }"
  },
  {
    "path": "app/src/main/res/raw/casting.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec4 mask = texture2D(iChannel0, fragCoord);\n    vec4 tempColor = vec4(mask.r*0.5/(mask.g + mask.b + 0.01),\n     mask.g*0.5/(mask.r + mask.b + 0.01),\n     mask.b*0.5/(mask.r + mask.g + 0.01),\n       1.0);\n    fragColor = tempColor;\n}\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }"
  },
  {
    "path": "app/src/main/res/raw/chromatic_aberration.fsh",
    "content": "precision mediump float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 uv = fragCoord.xy;\n\n\tfloat amount = 0.0;\n\t\n\tamount = (1.0 + sin(iGlobalTime*6.0)) * 0.5;\n\tamount *= 1.0 + sin(iGlobalTime*16.0) * 0.5;\n\tamount *= 1.0 + sin(iGlobalTime*19.0) * 0.5;\n\tamount *= 1.0 + sin(iGlobalTime*27.0) * 0.5;\n\tamount = pow(amount, 3.0);\n\n\tamount *= 0.05;\n\t\n    vec3 col;\n    col.r = texture2D( iChannel0, vec2(uv.x+amount,uv.y) ).r;\n    col.g = texture2D( iChannel0, uv ).g;\n    col.b = texture2D( iChannel0, vec2(uv.x-amount,uv.y) ).b;\n\n\tcol *= (1.0 - amount * 0.5);\n\t\n    fragColor = vec4(col,1.0);\n}\n\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/contrast.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat remap(float value, float inputMin, float inputMax, float outputMin, float outputMax)\n{\n    return (value - inputMin) * ((outputMax - outputMin) / (inputMax - inputMin)) + outputMin;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy;\n\tfloat normalizedContrast = 1.0;\n\tfloat contrast = remap(normalizedContrast, 0.0, 1.0, 0.2 /*min*/, 4.0 /*max*/);\n\t\n    vec4 srcColor = texture2D(iChannel0, uv);\n    vec4 dstColor = vec4((srcColor.rgb - vec3(0.5)) * contrast + vec3(0.5), 1.0);\n    fragColor = clamp(dstColor, 0.0, 1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/cracked.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat rnd(vec2 s)\n{\n    return 1.-2.*fract(sin(s.x*253.13+s.y*341.41)*589.19);\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 p=(fragCoord.xy*2.-iResolution.xy)/iResolution.x;\n\n    vec2 v=vec2(1E3);\n    vec2 v2=vec2(1E4);\n    vec2 center=vec2(.1,-.5);\n    for(int c=0;c<30;c++)\n    {\n        float angle=floor(rnd(vec2(float(c),387.44))*16.)*3.1415*.4-.5;\n        float dist=pow(rnd(vec2(float(c),78.21)),2.)*.5;\n        vec2 vc=vec2(center.x+cos(angle)*dist+rnd(vec2(float(c),349.3))*7E-3,\n                     center.y+sin(angle)*dist+rnd(vec2(float(c),912.7))*7E-3);\n        if(length(vc-p)<length(v-p))\n        {\n\t        v2=v;\n\t        v=vc;\n        }\n        else if(length(vc-p)<length(v2-p))\n        {\n            v2=vc;\n        }\n    }\n\n    float col=abs(length(dot(p-v,normalize(v-v2)))-length(dot(p-v2,normalize(v-v2))))+.002*length(p-center);\n    col=7E-4/col;\n    if(length(v-v2)<4E-3)col=0.;\n//    if(length(v-p)<4E-3)col=1E-6;\n    if(col<.3)col=0.;\n    vec4 tex=texture2D(iChannel0,(fragCoord.xy)/iResolution.xy+rnd(v)*.02);\n    fragColor=col*vec4(vec3(1.-tex.xyz),1.)+(1.-col)*tex;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord * iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/crosshatch.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n// The brightnesses at which different hatch lines appear\nfloat hatch_1 = 0.8;\nfloat hatch_2 = 0.6;\nfloat hatch_3 = 0.3;\nfloat hatch_4 = 0.15;\n\n// How close together hatch lines should be placed\nfloat density = 10.0;\n\n// How wide hatch lines are drawn.\nfloat width = 1.0;\n\n// enable GREY_HATCHES for greyscale hatch lines\n#define GREY_HATCHES\n\n// enable COLOUR_HATCHES for coloured hatch lines\n#define COLOUR_HATCHES\n\n#ifdef GREY_HATCHES\nfloat hatch_1_brightness = 0.8;\nfloat hatch_2_brightness = 0.6;\nfloat hatch_3_brightness = 0.3;\nfloat hatch_4_brightness = 0.0;\n#else\nfloat hatch_1_brightness = 0.0;\nfloat hatch_2_brightness = 0.0;\nfloat hatch_3_brightness = 0.0;\nfloat hatch_4_brightness = 0.0;\n#endif\n\nfloat d = 1.0; // kernel offset\n\nfloat lookup(vec2 p, float dx, float dy)\n{\n    vec2 uv = (p.xy + vec2(dx * d, dy * d)) / iResolution.xy;\n    vec4 c = texture2D(iChannel0, uv.xy);\n\n\t// return as luma\n    return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n}\n\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\t//\n\t// Inspired by the technique illustrated at\n\t// http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/\n\t//\n\tfloat ratio = iResolution.y / iResolution.x;\n\tfloat coordX = fragCoord.x / iResolution.x;\n\tfloat coordY = fragCoord.y / iResolution.x;\n\tvec2 dstCoord = vec2(coordX, coordY);\n\tvec2 srcCoord = vec2(coordX, coordY / ratio);\n\tvec2 uv = srcCoord.xy;\n\n\tvec3 res = vec3(1.0, 1.0, 1.0);\n    vec4 tex = texture2D(iChannel0, uv);\n    float brightness = (0.2126*tex.x) + (0.7152*tex.y) + (0.0722*tex.z);\n#ifdef COLOUR_HATCHES\n\t// check whether we have enough of a hue to warrant coloring our\n\t// hatch strokes.  If not, just use greyscale for our hatch color.\n\tfloat dimmestChannel = min( min( tex.r, tex.g ), tex.b );\n\tfloat brightestChannel = max( max( tex.r, tex.g ), tex.b );\n\tfloat delta = brightestChannel - dimmestChannel;\n\tif ( delta > 0.1 )\n\t\ttex = tex * ( 1.0 / brightestChannel );\n\telse\n\t\ttex.rgb = vec3(1.0,1.0,1.0);\n#endif // COLOUR_HATCHES\n\n    if (brightness < hatch_1)\n    {\n\t\tif (mod(fragCoord.x + fragCoord.y, density) <= width)\n\t\t{\n#ifdef COLOUR_HATCHES\n\t\t\tres = vec3(tex.rgb * hatch_1_brightness);\n#else\n\t\t\tres = vec3(hatch_1_brightness);\n#endif\n\t\t}\n    }\n\n    if (brightness < hatch_2)\n    {\n\t\tif (mod(fragCoord.x - fragCoord.y, density) <= width)\n\t\t{\n#ifdef COLOUR_HATCHES\n\t\t\tres = vec3(tex.rgb * hatch_2_brightness);\n#else\n\t\t\tres = vec3(hatch_2_brightness);\n#endif\n\t\t}\n    }\n\n    if (brightness < hatch_3)\n    {\n\t\tif (mod(fragCoord.x + fragCoord.y - (density*0.5), density) <= width)\n\t\t{\n#ifdef COLOUR_HATCHES\n\t\t\tres = vec3(tex.rgb * hatch_3_brightness);\n#else\n\t\t\tres = vec3(hatch_3_brightness);\n#endif\n\t\t}\n    }\n\n    if (brightness < hatch_4)\n    {\n\t\tif (mod(fragCoord.x - fragCoord.y - (density*0.5), density) <= width)\n\t\t{\n#ifdef COLOUR_HATCHES\n\t\t\tres = vec3(tex.rgb * hatch_4_brightness);\n#else\n\t\t\tres = vec3(hatch_4_brightness);\n#endif\n\t\t}\n    }\n\n\tvec2 p = fragCoord.xy;\n\n\t// simple sobel edge detection,\n\t// borrowed and tweaked from jmk's \"edge glow\" filter, here:\n\t// https://www.shadertoy.com/view/Mdf3zr\n    float gx = 0.0;\n    gx += -1.0 * lookup(p, -1.0, -1.0);\n    gx += -2.0 * lookup(p, -1.0,  0.0);\n    gx += -1.0 * lookup(p, -1.0,  1.0);\n    gx +=  1.0 * lookup(p,  1.0, -1.0);\n    gx +=  2.0 * lookup(p,  1.0,  0.0);\n    gx +=  1.0 * lookup(p,  1.0,  1.0);\n\n    float gy = 0.0;\n    gy += -1.0 * lookup(p, -1.0, -1.0);\n    gy += -2.0 * lookup(p,  0.0, -1.0);\n    gy += -1.0 * lookup(p,  1.0, -1.0);\n    gy +=  1.0 * lookup(p, -1.0,  1.0);\n    gy +=  2.0 * lookup(p,  0.0,  1.0);\n    gy +=  1.0 * lookup(p,  1.0,  1.0);\n\n\t// hack: use g^2 to conceal noise in the video\n    float g = gx*gx + gy*gy;\n\tres *= (1.0-g);\n\n\tfragColor = vec4(res, 1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord * iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/edge_detection.fsh",
    "content": "#extension GL_OES_standard_derivatives : enable\nprecision mediump float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 uv = fragCoord.xy;\n    vec4 color =  texture2D(iChannel0, fragCoord);\n    float gray = length(color.rgb);\n    fragColor = vec4(vec3(step(0.06, length(vec2(dFdx(gray), dFdy(gray))))), 1.0);\n}\n\nvoid main() {\n    mainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/em_interference.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat rng2(vec2 seed)\n{\n    return fract(sin(dot(seed * floor(iGlobalTime * 12.), vec2(127.1,311.7))) * 43758.5453123);\n}\n\nfloat rng(float seed)\n{\n    return rng2(vec2(seed, 1.0));\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy;\n    vec2 blockS = floor(uv * vec2(24., 9.));\n    vec2 blockL = floor(uv * vec2(8., 4.));\n\n    float r = rng2(uv);\n    vec3 noise = (vec3(r, 1. - r, r / 2. + 0.5) * 1.0 - 2.0) * 0.08;\n\n    float lineNoise = pow(rng2(blockS), 8.0) * pow(rng2(blockL), 3.0) - pow(rng(7.2341), 17.0) * 2.;\n\n    vec4 col1 = texture2D(iChannel0, uv);\n    vec4 col2 = texture2D(iChannel0, uv + vec2(lineNoise * 0.05 * rng(5.0), 0));\n    vec4 col3 = texture2D(iChannel0, uv - vec2(lineNoise * 0.05 * rng(31.0), 0));\n\n\tfragColor = vec4(vec3(col1.x, col2.y, col3.z) + noise, 1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/gray.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec4 mask = texture2D(iChannel0, fragCoord);\n    float color = (mask.r + mask.g + mask.b) /3.0;\n    vec4 tempColor =vec4(color, color, color,1.0);\n    fragColor = tempColor;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/hexagon_mosaic.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nconst float mosaicSize = 0.03;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n    float length = mosaicSize;\n    float TR = 0.866025;\n\n    float x = texCoord.x;\n    float y = texCoord.y;\n\n    int wx = int(x / 1.5 / length);\n    int wy = int(y / TR / length);\n    vec2 v1, v2, vn;\n\n    if (wx/2 * 2 == wx) {\n        if (wy/2 * 2 == wy) {\n            //(0,0),(1,1)\n            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));\n            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));\n        } else {\n            //(0,1),(1,0)\n            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));\n            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));\n        }\n    }else {\n        if (wy/2 * 2 == wy) {\n            //(0,1),(1,0)\n            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));\n            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));\n        } else {\n            //(0,0),(1,1)\n            v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));\n            v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));\n        }\n    }\n\n    float s1 = sqrt(pow(v1.x - x, 2.0) + pow(v1.y - y, 2.0));\n    float s2 = sqrt(pow(v2.x - x, 2.0) + pow(v2.y - y, 2.0));\n    if (s1 < s2) {\n        vn = v1;\n    } else {\n        vn = v2;\n    }\n    vec4 color = texture2D(iChannel0, vn);\n\n    fragColor = color;\n   }\n\nvoid main () {\n    mainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/legofied.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat c = 0.02; //amout of blocks = c*iResolution.x\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord ){\n    //blocked pixel coordinate\n    vec2 middle = floor(fragCoord*c+.5)/c;\n\n    vec3 color = texture2D(iChannel0, middle/iResolution.xy).rgb;\n\n    //lego block effects\n        //stud\n        float dis = distance(fragCoord,middle)*c*2.;\n        if(dis<.65&&dis>.55){\n            color *= dot(vec2(0.707),normalize(fragCoord-middle))*.5+1.;\n        }\n\n        //side shadow\n        vec2 delta = abs(fragCoord-middle)*c*2.;\n        float sdis = max(delta.x,delta.y);\n        if(sdis>.9){\n            color *= .8;\n        }\n\n\tfragColor = vec4(color,1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/lichtenstein_esque.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n// Size of the quad in pixels\nconst float size = 15.0;\n\n// Radius of the circle\nconst float radius = size * 0.5;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\t// Current quad in pixels\n\tvec2 quadPos = floor(fragCoord.xy / size) * size;\n\t// Normalized quad position\n\tvec2 quad = quadPos/iResolution.xy;\n\t// Center of the quad\n\tvec2 quadCenter = (quadPos + size/2.0);\n\t// Distance to quad center\n\tfloat dist = length(quadCenter - fragCoord.xy);\n\n\tvec4 texel = texture2D(iChannel0, quad);\n\tif (dist > radius)\n\t{\n\t\tfragColor = vec4(0.25);\n\t}\n\telse\n\t{\n\t\tfragColor = texel;\n\t}\n}\n\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/mapping.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\n\tvec2 pos = fragCoord.xy;\n\tvec2 uv2 = vec2( fragCoord.xy / iResolution.xy );\n\tvec4 sound = texture2D( iChannel0, uv2 );\n\tpos.x = pos.x + 150.0 * sound.r;\n\tpos.y = pos.y + 150.0 * sound.b;\n\tvec2 uv = pos / iResolution.xy;\n\n\tvec4 col = texture2D( iChannel1, uv );\n\n\tcol.a += 1.0 - sin( col.x - col.y + iGlobalTime * 0.1 );\n\n\tfragColor =  col * sound.r;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord * iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/mirror.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n    vec2 flipCoord = vec2(1.0-fragCoord.x, fragCoord.y);\n    if(flipCoord.x >= 0.5){\n    \tfragColor = texture2D(iChannel0, vec2( flipCoord.x - 0.5, flipCoord.y ));\n    } else {\n    \tfragColor = texture2D(iChannel0, vec2(  0.5 - flipCoord.x,flipCoord.y ));\n    }\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }\n"
  },
  {
    "path": "app/src/main/res/raw/money_filter.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n\n// Money filter by Giacomo Preciado\n// Based on: \"Free Engraved Illustration Effect Action for Photoshop\" - http://snip.ly/j0gq\n// e-mail: giacomo@kyrie.pe\n// website: http://kyrie.pe\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 xy = fragCoord.xy / iResolution.yy;\n\n    float amplitud = 0.03;\n    float frecuencia = 10.0;\n    float gris = 1.0;\n    float divisor = 8.0 / iResolution.y;\n    float grosorInicial = divisor * 0.2;\n\n    const int kNumPatrones = 6;\n\n    // x: seno del angulo, y: coseno del angulo, z: factor de suavizado\n\tvec3 datosPatron[kNumPatrones];\n    datosPatron[0] = vec3(-0.7071, 0.7071, 3.0); // -45\n    datosPatron[1] = vec3(0.0, 1.0, 0.6); // 0\n    datosPatron[2] = vec3(0.0, 1.0, 0.5); // 0\n    datosPatron[3] = vec3(1.0, 0.0, 0.4); // 90\n    datosPatron[4] = vec3(1.0, 0.0, 0.3); // 90\n    datosPatron[5] = vec3(0.0, 1.0, 0.2); // 0\n\n    vec4 color = texture2D(iChannel0, vec2(fragCoord.x / iResolution.x, xy.y));\n    fragColor = color;\n\n    for(int i = 0; i < kNumPatrones; i++)\n    {\n        float coseno = datosPatron[i].x;\n        float seno = datosPatron[i].y;\n\n        vec2 punto = vec2(\n            xy.x * coseno - xy.y * seno,\n            xy.x * seno + xy.y * coseno\n        );\n\n        float grosor = grosorInicial * float(i + 1);\n        float dist = mod(punto.y + grosor * 0.5 - sin(punto.x * frecuencia) * amplitud, divisor);\n        float brillo = 0.3 * color.r + 0.4 * color.g + 0.3 * color.b;\n\n        if(dist < grosor && brillo < 0.75 - 0.12 * float(i))\n        {\n            // Suavizado\n            float k = datosPatron[i].z;\n            float x = (grosor - dist) / grosor;\n            float fx = abs((x - 0.5) / k) - (0.5 - k) / k;\n            gris = min(fx, gris);\n        }\n    }\n\n    fragColor = vec4(gris, gris, gris, 1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/negative.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec4 mask = texture2D(iChannel0, fragCoord);\n    vec4 color =vec4(1.0-mask.r, 1.0-mask.g, 1.0-mask.r,1.0);\n    fragColor = color;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/noise_warp.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat mod289(float x)\n{\n    return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 mod289(vec4 x)\n{\n    return x - floor(x * (1.0 / 289.0)) * 289.0;\n}\n\nvec4 perm(vec4 x)\n{\n    return mod289(((x * 34.0) + 1.0) * x);\n}\n\nfloat noise3d(vec3 p)\n{\n    vec3 a = floor(p);\n    vec3 d = p - a;\n    d = d * d * (3.0 - 2.0 * d);\n\n    vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);\n    vec4 k1 = perm(b.xyxy);\n    vec4 k2 = perm(k1.xyxy + b.zzww);\n\n    vec4 c = k2 + a.zzzz;\n    vec4 k3 = perm(c);\n    vec4 k4 = perm(c + 1.0);\n\n    vec4 o1 = fract(k3 * (1.0 / 41.0));\n    vec4 o2 = fract(k4 * (1.0 / 41.0));\n\n    vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);\n    vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);\n\n    return o4.y * d.y + o4.x * (1.0 - d.y);\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy;\n\tfloat v1 = noise3d(vec3(uv * 10.0, 0.0));\n\tfloat v2 = noise3d(vec3(uv * 10.0, 1.0));\n\n\tvec4 color  = texture2D(iChannel0, uv + vec2(v1, v2) * 0.1);\n\tfragColor = color;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/nostalgia.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec4 mask = texture2D(iChannel0, fragCoord);\n    vec4 tempColor = vec4(0.393 * mask.r + 0.769 * mask.g + 0.189 * mask.b,\n     0.349 * mask.r + 0.686 * mask.g + 0.168 * mask.b,\n      0.272 * mask.r + 0.534 * mask.g + 0.131 * mask.b, 1.0);\n    fragColor = tempColor;\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/original.fsh",
    "content": "precision mediump float;\n\nvarying vec2                texCoord;\nuniform sampler2D           iChannel0;\n\nvoid main() {\n    gl_FragColor = texture2D(iChannel0, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/original_rtt.fsh",
    "content": "#extension GL_OES_EGL_image_external : require\nprecision mediump float;\n\nvarying vec2                texCoord;\nuniform samplerExternalOES  iChannel0;\n\nvoid main() {\n    gl_FragColor = texture2D(iChannel0, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/pixelize.fsh",
    "content": "precision mediump float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\n#define S (iResolution.x / 6e1) // The cell size.\n\nvoid mainImage(out vec4 c, vec2 p)\n{\n    c = texture2D(iChannel0, floor((p + .5) / S) * S / iResolution.xy);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/polygonization.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvec2 hash2( vec2 p )\n{\n    // procedural white noise\n\treturn fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);\n}\n\nvec2 voronoi( in vec2 x )\n{\n    vec2 n = floor(x);\n    vec2 f = fract(x);\n\n    //----------------------------------\n    // regular voronoi\n    //----------------------------------\n\tvec2 mg, mr;\n\n    float md = 8.0;\n    for( int j=-1; j<=1; j++ )\n    for( int i=-1; i<=1; i++ )\n    {\n        vec2 g = vec2(float(i),float(j));\n\t\tvec2 o = hash2( n + g );\n        vec2 r = g + o - f;\n        float d = dot(r,r);\n\n        if( d<md )\n        {\n            md = d;\n            mr = r;\n            mg = g;\n        }\n    }\n\n    return mr;\n}\n\nvec3 VoronoiColor(float steps, vec2 p, vec2 uv)\n{\n    vec2 c = voronoi( steps*p );\n\n    vec2 uv1 = uv;\n    uv1.x += c.x/steps;\n    uv1.y += c.y/steps *  iResolution.x/iResolution.y;\n\n    return texture2D(iChannel0, vec2(uv1.x, uv1.y)).xyz;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 p = fragCoord.xy/iResolution.xx;\n    vec2 uv = fragCoord.xy / iResolution.xy;\n\n    vec3 color = vec3(0.0,0.0,0.0);\n    for (float i=0.0; i<4.0; i+=1.0)\n    {\n        float steps = 30.0*pow(2.0,i);\n        color += VoronoiColor(steps, p, uv);\n    }\n\n\tfragColor = vec4(color*0.25,1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord * iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/refraction.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy;\n\n\tvec4 bump = texture2D(iChannel1, uv + iGlobalTime * 0.05);\n\n\tvec2 vScale = vec2 (0.01, 0.01);\n\tvec2 newUV = uv + bump.xy * vScale.xy;\n\n\tvec4 col = texture2D(iChannel0, newUV);\n\n\tfragColor = vec4(col.xyz, 1.0);\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/relief.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nconst highp vec3 transMatrix = vec3(0.2125, 0.7154, 0.0721);\nconst vec4 bgColor = vec4(0.5, 0.5, 0.5, 1.0);\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n      vec2 currentUV = fragCoord;\n      vec2 preUV = vec2(currentUV.x-5.0/iResolution.x, currentUV.y-5.0/iResolution.y);\n      vec4 currentMask = texture2D(iChannel0, currentUV);\n      vec4 preMask = texture2D(iChannel0, preUV);\n      vec4 delColor = currentMask - preMask;\n      float luminance = dot(delColor.rgb, transMatrix);\n      fragColor = vec4(vec3(luminance), 0.0) + bgColor;\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }\n"
  },
  {
    "path": "app/src/main/res/raw/swirl.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nconst float PI = 3.14159265;\nconst float rotateRadian = PI/3.0;\nconst float radiusRatio = 0.8;\nconst float center = 0.5;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n    float radius = min(iResolution.x,iResolution.y)*radiusRatio/2.0;\n    vec2 texCoord = fragCoord;\n    vec2 currentUV = texCoord;\n    currentUV.x *= iResolution.x;\n    currentUV.y *= iResolution.y;\n    vec2 centerUV = iResolution.xy * center;\n    vec2 deltaUV = currentUV - centerUV;\n\n    float deltaR = length(deltaUV);\n    float beta = atan(deltaUV.y, deltaUV.x) + rotateRadian * 2.0 * (-(deltaR/radius)*(deltaR/radius) + 1.0);\n\n    vec2 dstUV = currentUV;\n    if(deltaR <= radius){\n        dstUV = centerUV + deltaR*vec2(cos(beta), sin(beta));\n    }\n    dstUV.x /=iResolution.x;\n    dstUV.y /=iResolution.y;\n    fragColor = texture2D(iChannel0, dstUV);\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }\n"
  },
  {
    "path": "app/src/main/res/raw/tile_mosaic.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvec2 tile_num = vec2(40.0, 20.0);\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tconst float minTileSize = 1.0;\n\tconst float maxTileSize = 32.0;\n\tconst float textureSamplesCount = 3.0;\n\tconst float textureEdgeOffset = 0.005;\n\tconst float borderSize = 1.0;\n\tconst float size = 0.5;\n\n\tfloat tileSize = minTileSize + floor(size * (maxTileSize - minTileSize));\n\ttileSize += mod(tileSize, 2.0);\n\tvec2 tileNumber = floor(fragCoord / tileSize);\n\n\tvec4 accumulator = vec4(0.0);\n\tfor (float y = 0.0; y < textureSamplesCount; ++y)\n\t{\n\t\tfor (float x = 0.0; x < textureSamplesCount; ++x)\n\t\t{\n\t\t\tvec2 textureCoordinates = (tileNumber + vec2((x + 0.5)/textureSamplesCount, (y + 0.5)/textureSamplesCount)) * tileSize / iResolution.xy;\n\t\t\ttextureCoordinates = clamp(textureCoordinates, 0.0 + textureEdgeOffset, 1.0 - textureEdgeOffset);\n\t\t\taccumulator += texture2D(iChannel0, textureCoordinates);\n\t   }\n\t}\n\n\tfragColor = accumulator / vec4(textureSamplesCount * textureSamplesCount);\n\n\tvec2 pixelNumber = floor(fragCoord - (tileNumber * tileSize));\n\tpixelNumber = mod(pixelNumber + borderSize, tileSize);\n\n    float pixelBorder = step(min(pixelNumber.x, pixelNumber.y), borderSize) * step(borderSize * 2.0 + 1.0, tileSize);\n\t//float pixelBorder = step(pixelNumber.x, borderSize) * step(pixelNumber.y, borderSize) * step(borderSize * 2.0 + 1.0, tileSize);\n\n\tfragColor *= pow(fragColor, vec4(pixelBorder));\n}\n\nvoid main() {\n    mainImage(gl_FragColor, texCoord.xy*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/triangles_mosaic.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nvec2 tile_num = vec2(40.0,20.0);\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy;\n\tvec2 uv2 = floor(uv*tile_num)/tile_num;\n    uv -= uv2;\n    uv *= tile_num;\n\tfragColor = texture2D( iChannel0, uv2 + vec2(step(1.0-uv.y,uv.x)/(2.0*tile_num.x),\n        \t\t\t\t\t\t\t\t\t\t\t//0,\n        \t\t\t\t\t\t\t\t\t\t\tstep(uv.x,uv.y)/(2.0*tile_num.y)\n                                                    //0\n                                                   ) );\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord);\n}"
  },
  {
    "path": "app/src/main/res/raw/triple.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nuniform float u_time;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n    if (fragCoord.y <=  0.333){\n       fragColor = texture2D(iChannel0, vec2(fragCoord.x,fragCoord.y + 0.333));\n    }else if(fragCoord.y > 0.333 && fragCoord.y<= 0.666){\n       fragColor = texture2D(iChannel0, fragCoord);\n    }else{\n       fragColor = texture2D(iChannel0, vec2(fragCoord.x,fragCoord.y - 0.333));\n    }\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }"
  },
  {
    "path": "app/src/main/res/raw/vertext.vsh",
    "content": "attribute vec2  vPosition;\nattribute vec2  vTexCoord;\nvarying vec2    texCoord;\n\nvoid main() {\n    texCoord = vTexCoord;\n    gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n}"
  },
  {
    "path": "app/src/main/res/raw/voronoi.fsh",
    "content": "precision highp float;\n\nuniform int                 iFrame;\nuniform vec3                iResolution;\nuniform vec3                iChannelResolution[2];\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\tvec2 uv = fragCoord.xy / iResolution.xy;\n\n#if 0 // debug feature extraction\n\n    fragColor = texture2D(iChannel1, uv).wwww;\n\n#else\n\n\tvec4 cell = texture2D(iChannel0, uv);\n    vec2 cell_uv = cell.xy;\n    vec4 video = texture2D(iChannel1, cell_uv);\n    vec2 dcell = cell_uv * iChannelResolution[0].xy - fragCoord.xy;\n    float len = length(dcell);\n    vec3 color = video.xyz * (.9 + len*.005);\n    fragColor = vec4(color, 1.);\n\n#endif\n}\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/voronoi_buf_a.fsh",
    "content": "precision highp float;\n\nuniform int                 iFrame;\nuniform vec3                iResolution;\nuniform vec3                iChannelResolution[2];\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\n// A super simple video source with feature detection\n\nfloat grayScale(vec4 c) { return c.x*.29 + c.y*.58 + c.z*.13; }\n\n//============================================================\nvec4 GenerateSeed (in vec2 fragCoord)\n{\n    vec2 uv = fragCoord / iResolution.xy;\n    vec3 dataStep = vec3( vec2(1.) / iChannelResolution[0].xy, 0.);\n\n    vec4 fragColor = texture2D( iChannel0, uv );\n\n    float d = grayScale(fragColor);\n    float dL = grayScale(texture2D( iChannel0, uv - dataStep.xz ));\n    float dR = grayScale(texture2D( iChannel0, uv + dataStep.xz ));\n    float dU = grayScale(texture2D( iChannel0, uv - dataStep.zy ));\n    float dD = grayScale(texture2D( iChannel0, uv + dataStep.zy ));\n    float w = float( d*0.99 > max(max(dL, dR), max(dU, dD)) );\n\n    w = max(w, texture2D( iChannel1, uv ).w*.9); // get some from previous frame\n\n    fragColor.w = w;\n\n    return fragColor;\n}\n\n//============================================================\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    fragColor = GenerateSeed(fragCoord);\n}\n\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/voronoi_buf_b.fsh",
    "content": "precision highp float;\n\nuniform int                 iFrame;\nuniform vec3                iResolution;\nuniform vec3                iChannelResolution[2];\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\n\n// how many JFA steps to do.  2^c_maxSteps is max image size on x and y\nconst float c_maxSteps = 10.0;\n\n//============================================================\nvec4 StepJFA (in vec2 fragCoord, in float level)\n{\n    float stepwidth = floor(exp2(c_maxSteps - 1. - level)+0.5);\n\n    float bestDistance = 9999.0;\n    vec2 bestCoord = vec2(0.0);\n\n    for (int y = -1; y <= 1; ++y) {\n        for (int x = -1; x <= 1; ++x) {\n            vec2 sampleCoord = fragCoord + vec2(x,y) * stepwidth;\n\n            vec4 data = texture2D( iChannel0, sampleCoord / iChannelResolution[0].xy);\n            vec2 seedCoord = data.xy * iChannelResolution[0].xy;\n            float dist = length(seedCoord - fragCoord);\n            if ((seedCoord.x != 0.0 || seedCoord.y != 0.0) && dist < bestDistance)\n            {\n                bestDistance = dist;\n                bestCoord = seedCoord;\n            }\n        }\n    }\n\n    return vec4(bestCoord / iChannelResolution[0].xy, 0.0, 0.0);\n}\n\n//============================================================\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    float fFrame = float(iFrame);\n    float level = mod(fFrame,c_maxSteps);\n    if (level < .5) {\n        if (texture2D(iChannel1, fragCoord / iResolution.xy).w > .5)\n        \tfragColor = vec4(fragCoord / iChannelResolution[0].xy, 0.0, 0.0);\n        else\n            fragColor = vec4(0.0);\n        return;\n    }\n\n    fragColor = StepJFA(fragCoord, level);\n}\n\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/voronoi_buf_c.fsh",
    "content": "precision highp float;\n\nuniform int                 iFrame;\nuniform vec3                iResolution;\nuniform vec3                iChannelResolution[2];\nuniform float               iGlobalTime;\nuniform sampler2D           iChannel0;\nuniform sampler2D           iChannel1;\nvarying vec2                texCoord;\n\n// A secondary buffer to get clean Voronoi every N-th frame\n\n// this must be in sync with JFA algorithm constant\nconst float c_maxSteps = 10.0;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n   \tvec2 uv = fragCoord.xy / iResolution.xy;\n    if (mod(float(iFrame+1),c_maxSteps) < .5) {\n        fragColor = texture2D(iChannel1, uv); // update to new voronoi cell\n    } else {\n        fragColor = texture2D(iChannel0, uv); // no change\n    }\n}\n\n\nvoid main() {\n\tmainImage(gl_FragColor, texCoord*iResolution.xy);\n}"
  },
  {
    "path": "app/src/main/res/raw/water_reflection.fsh",
    "content": "precision highp float;\n\nuniform vec3                iResolution;\nuniform sampler2D           iChannel0;\nvarying vec2                texCoord;\n\nfloat waterLevel = 0.5;\nfloat waveAmplitude = 0.01;\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n  {\n     if(fragCoord.y >= waterLevel){\n        fragColor = texture2D(iChannel0, fragCoord);\n     }else{\n        fragColor = texture2D(iChannel0,vec2(fragCoord.x + fract(sin(dot(fragCoord.xy ,vec2(12.9898,78.233))) * 43758.5453) * waveAmplitude,\n       \t\t\t\t2.0 * waterLevel - fragCoord.y));\n     }\n   }\n\nvoid main() {\n \tmainImage(gl_FragColor, texCoord);\n }"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#646464</color>\n    <color name=\"colorPrimaryDark\">#646464</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">CameraFilter</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.4.0'\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sat Jun 01 14:43:03 CST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.1.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "## Project-wide Gradle settings.\n#\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n#\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n#\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]