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;
  
  import android.graphics.PointF;
  import android.opengl.GLES20;
  
  public class GPUImageSphereRefractionFilter extends GPUImageFilter {
      public static final String SPHERE_FRAGMENT_SHADER = "" +
              "varying highp vec2 textureCoordinate;\n" +
              "\n" +
              "uniform sampler2D inputImageTexture;\n" +
              "\n" +
              "uniform highp vec2 center;\n" +
              "uniform highp float radius;\n" +
              "uniform highp float aspectRatio;\n" +
              "uniform highp float refractiveIndex;\n" +
              "\n" +
              "void main()\n" +
              "{\n" +
              "highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" +
              "highp float distanceFromCenter = distance(center, textureCoordinateToUse);\n" +
              "lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);\n" +
              "\n" +
              "distanceFromCenter = distanceFromCenter / radius;\n" +
              "\n" +
              "highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);\n" +
              "highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));\n" +
              "\n" +
              "highp vec3 refractedVector = refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);\n" +
              "\n" +
              "gl_FragColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5) * checkForPresenceWithinSphere;     \n" +
              "}\n";
  
      private PointF mCenter;
      private int mCenterLocation;
      private float mRadius;
      private int mRadiusLocation;
      private float mAspectRatio;
      private int mAspectRatioLocation;
      private float mRefractiveIndex;
      private int mRefractiveIndexLocation;
  
      public GPUImageSphereRefractionFilter() {
          this(new PointF(0.5f, 0.5f), 0.25f, 0.71f);
      }
  
      public GPUImageSphereRefractionFilter(PointF center, float radius, float refractiveIndex) {
          super(NO_FILTER_VERTEX_SHADER, SPHERE_FRAGMENT_SHADER);
          mCenter = center;
          mRadius = radius;
          mRefractiveIndex = refractiveIndex;
      }
  
      @Override
      public void onInit() {
          super.onInit();
          mCenterLocation = GLES20.glGetUniformLocation(getProgram(), "center");
          mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius");
          mAspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), "aspectRatio");
          mRefractiveIndexLocation = GLES20.glGetUniformLocation(getProgram(), "refractiveIndex");
      }
  
      @Override
      public void onInitialized() {
          super.onInitialized();
          setRadius(mRadius);
          setCenter(mCenter);
          setRefractiveIndex(mRefractiveIndex);
      }
  
      @Override
      public void onOutputSizeChanged(int width, int height) {
          mAspectRatio = (float) height / width;
          setAspectRatio(mAspectRatio);
          super.onOutputSizeChanged(width, height);
      }
  
      private void setAspectRatio(float aspectRatio) {
          mAspectRatio = aspectRatio;
          setFloat(mAspectRatioLocation, aspectRatio);
      }
  
      /**
       * The index of refraction for the sphere, with a default of 0.71
       *
       * @param refractiveIndex default 0.71
       */
      public void setRefractiveIndex(float refractiveIndex) {
          mRefractiveIndex = refractiveIndex;
          setFloat(mRefractiveIndexLocation, refractiveIndex);
      }
  
      /**
       * The center about which to apply the distortion, with a default of (0.5, 0.5)
       *
       * @param center default (0.5, 0.5)
       */
      public void setCenter(PointF center) {
          mCenter = center;
          setPoint(mCenterLocation, center);
      }
  
      /**
       * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25
       *
       * @param radius from 0.0 to 1.0, default 0.25
       */
      public void setRadius(float radius) {
          mRadius = radius;
          setFloat(mRadiusLocation, radius);
      }
  }
  