content: /*
   * Copyright (C) 2012 CyberAgent
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package jp.co.cyberagent.android.gpuimage;
  
  /**
   * For each pixel, this sets it to the maximum value of the red channel in a rectangular neighborhood extending
   * out dilationRadius pixels from the center.
   * This extends out bright features, and is most commonly used with black-and-white thresholded images.
   */
  public class GPUImageDilationFilter extends GPUImageTwoPassTextureSamplingFilter {
      public static final String VERTEX_SHADER_1 =
              "attribute vec4 position;\n" +
                      "attribute vec2 inputTextureCoordinate;\n" +
                      "\n" +
                      "uniform float texelWidthOffset; \n" +
                      "uniform float texelHeightOffset; \n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "gl_Position = position;\n" +
                      "\n" +
                      "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" +
                      "\n" +
                      "centerTextureCoordinate = inputTextureCoordinate;\n" +
                      "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" +
                      "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" +
                      "}\n";
  
      public static final String VERTEX_SHADER_2 =
              "attribute vec4 position;\n" +
                      "attribute vec2 inputTextureCoordinate;\n" +
                      "\n" +
                      "uniform float texelWidthOffset;\n" +
                      "uniform float texelHeightOffset;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "gl_Position = position;\n" +
                      "\n" +
                      "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" +
                      "\n" +
                      "centerTextureCoordinate = inputTextureCoordinate;\n" +
                      "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" +
                      "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" +
                      "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" +
                      "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" +
                      "}\n";
  
      public static final String VERTEX_SHADER_3 =
              "attribute vec4 position;\n" +
                      "attribute vec2 inputTextureCoordinate;\n" +
                      "\n" +
                      "uniform float texelWidthOffset;\n" +
                      "uniform float texelHeightOffset;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 threeStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 threeStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "gl_Position = position;\n" +
                      "\n" +
                      "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" +
                      "\n" +
                      "centerTextureCoordinate = inputTextureCoordinate;\n" +
                      "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" +
                      "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" +
                      "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" +
                      "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" +
                      "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" +
                      "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" +
                      "}\n";
  
      public static final String VERTEX_SHADER_4 =
  
              "attribute vec4 position;\n" +
                      "attribute vec2 inputTextureCoordinate;\n" +
                      "\n" +
                      "uniform float texelWidthOffset;\n" +
                      "uniform float texelHeightOffset;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 threeStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 threeStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 fourStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 fourStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "gl_Position = position;\n" +
                      "\n" +
                      "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" +
                      "\n" +
                      "centerTextureCoordinate = inputTextureCoordinate;\n" +
                      "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" +
                      "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" +
                      "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" +
                      "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" +
                      "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" +
                      "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" +
                      "fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);\n" +
                      "fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);\n" +
                      "}\n";
  
  
      public static final String FRAGMENT_SHADER_1 =
              "precision lowp float;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "\n" +
                      "uniform sampler2D inputImageTexture;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" +
                      "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" +
                      "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" +
                      "\n" +
                      "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" +
                      "maxValue = max(maxValue, oneStepNegativeIntensity);\n" +
                      "\n" +
                      "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" +
                      "}\n";
  
      public static final String FRAGMENT_SHADER_2 =
              "precision lowp float;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "uniform sampler2D inputImageTexture;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" +
                      "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" +
                      "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" +
                      "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" +
                      "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" +
                      "\n" +
                      "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" +
                      "maxValue = max(maxValue, oneStepNegativeIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" +
                      "\n" +
                      "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" +
                      "}\n";
  
      public static final String FRAGMENT_SHADER_3 =
              "precision lowp float;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 threeStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 threeStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "uniform sampler2D inputImageTexture;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" +
                      "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" +
                      "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" +
                      "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" +
                      "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" +
                      "float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\n" +
                      "float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\n" +
                      "\n" +
                      "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" +
                      "maxValue = max(maxValue, oneStepNegativeIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" +
                      "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, threeStepsNegativeIntensity);\n" +
                      "\n" +
                      "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" +
                      "}\n";
  
      public static final String FRAGMENT_SHADER_4 =
              "precision lowp float;\n" +
                      "\n" +
                      "varying vec2 centerTextureCoordinate;\n" +
                      "varying vec2 oneStepPositiveTextureCoordinate;\n" +
                      "varying vec2 oneStepNegativeTextureCoordinate;\n" +
                      "varying vec2 twoStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 twoStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 threeStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 threeStepsNegativeTextureCoordinate;\n" +
                      "varying vec2 fourStepsPositiveTextureCoordinate;\n" +
                      "varying vec2 fourStepsNegativeTextureCoordinate;\n" +
                      "\n" +
                      "uniform sampler2D inputImageTexture;\n" +
                      "\n" +
                      "void main()\n" +
                      "{\n" +
                      "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" +
                      "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" +
                      "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" +
                      "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" +
                      "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" +
                      "float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\n" +
                      "float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\n" +
                      "float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;\n" +
                      "float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;\n" +
                      "\n" +
                      "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" +
                      "maxValue = max(maxValue, oneStepNegativeIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" +
                      "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, threeStepsNegativeIntensity);\n" +
                      "maxValue = max(maxValue, fourStepsPositiveIntensity);\n" +
                      "maxValue = max(maxValue, fourStepsNegativeIntensity);\n" +
                      "\n" +
                      "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" +
                      "}\n";
  
  
      public GPUImageDilationFilter() {
          this(1);
      }
  
      /**
       * Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center,
       * are 1, 2, 3, and 4.
       *
       * @param radius 1, 2, 3 or 4
       */
      public GPUImageDilationFilter(int radius) {
          this(getVertexShader(radius), getFragmentShader(radius));
      }
  
      private GPUImageDilationFilter(String vertexShader, String fragmentShader) {
          super(vertexShader, fragmentShader, vertexShader, fragmentShader);
      }
  
      private static String getVertexShader(int radius) {
          switch (radius) {
              case 0:
              case 1:
                  return VERTEX_SHADER_1;
              case 2:
                  return VERTEX_SHADER_2;
              case 3:
                  return VERTEX_SHADER_3;
              default:
                  return VERTEX_SHADER_4;
          }
      }
  
      private static String getFragmentShader(int radius) {
          switch (radius) {
              case 0:
              case 1:
                  return FRAGMENT_SHADER_1;
              case 2:
                  return FRAGMENT_SHADER_2;
              case 3:
                  return FRAGMENT_SHADER_3;
              default:
                  return FRAGMENT_SHADER_4;
          }
      }
  }
  