public DistortionMesh(
     final Distortion distortionRed,
     final Distortion distortionGreen,
     final Distortion distortionBlue,
     final float screenWidth,
     final float screenHeight,
     final float xEyeOffsetScreen,
     final float yEyeOffsetScreen,
     final float textureWidth,
     final float textureHeight,
     final float xEyeOffsetTexture,
     final float yEyeOffsetTexture,
     final float viewportXTexture,
     final float viewportYTexture,
     final float viewportWidthTexture,
     final float viewportHeightTexture) {
   super();
   this.mArrayBufferId = -1;
   this.mElementBufferId = -1;
   final float[] vertexData = new float[14400];
   short vertexOffset = 0;
   for (int row = 0; row < ROWS; ++row) {
     for (int col = 0; col < COLS; ++col) {
       final float uTextureBlue =
           col / 39.0f * (viewportWidthTexture / textureWidth) + viewportXTexture / textureWidth;
       final float vTextureBlue =
           row / 39.0f * (viewportHeightTexture / textureHeight)
               + viewportYTexture / textureHeight;
       final float xTexture = uTextureBlue * textureWidth - xEyeOffsetTexture;
       final float yTexture = vTextureBlue * textureHeight - yEyeOffsetTexture;
       final float rTexture = (float) Math.sqrt(xTexture * xTexture + yTexture * yTexture);
       final float textureToScreenBlue =
           (rTexture > 0.0f) ? (distortionBlue.distortInverse(rTexture) / rTexture) : 1.0f;
       final float xScreen = xTexture * textureToScreenBlue;
       final float yScreen = yTexture * textureToScreenBlue;
       final float uScreen = (xScreen + xEyeOffsetScreen) / screenWidth;
       final float vScreen = (yScreen + yEyeOffsetScreen) / screenHeight;
       final float rScreen = rTexture * textureToScreenBlue;
       final float screenToTextureGreen =
           (rScreen > 0.0f) ? distortionGreen.distortionFactor(rScreen) : 1.0f;
       final float uTextureGreen =
           (xScreen * screenToTextureGreen + xEyeOffsetTexture) / textureWidth;
       final float vTextureGreen =
           (yScreen * screenToTextureGreen + yEyeOffsetTexture) / textureHeight;
       final float screenToTextureRed =
           (rScreen > 0.0f) ? distortionRed.distortionFactor(rScreen) : 1.0f;
       final float uTextureRed =
           (xScreen * screenToTextureRed + xEyeOffsetTexture) / textureWidth;
       final float vTextureRed =
           (yScreen * screenToTextureRed + yEyeOffsetTexture) / textureHeight;
       final float vignetteSizeTexture = VIGNETTE_SIZE_TAN_ANGLE / textureToScreenBlue;
       final float dxTexture =
           xTexture
               + xEyeOffsetTexture
               - clamp(
                   xTexture + xEyeOffsetTexture,
                   viewportXTexture + vignetteSizeTexture,
                   viewportXTexture + viewportWidthTexture - vignetteSizeTexture);
       final float dyTexture =
           yTexture
               + yEyeOffsetTexture
               - clamp(
                   yTexture + yEyeOffsetTexture,
                   viewportYTexture + vignetteSizeTexture,
                   viewportYTexture + viewportHeightTexture - vignetteSizeTexture);
       final float drTexture = (float) Math.sqrt(dxTexture * dxTexture + dyTexture * dyTexture);
       float vignette;
       if (DistortionRenderer.this.mVignetteEnabled) {
         vignette = 1.0f - clamp(drTexture / vignetteSizeTexture, 0.0f, 1.0f);
       } else {
         vignette = 1.0f;
       }
       vertexData[vertexOffset + 0] = 2.0f * uScreen - 1.0f;
       vertexData[vertexOffset + 1] = 2.0f * vScreen - 1.0f;
       vertexData[vertexOffset + 2] = vignette;
       vertexData[vertexOffset + 3] = uTextureRed;
       vertexData[vertexOffset + 4] = vTextureRed;
       vertexData[vertexOffset + 5] = uTextureGreen;
       vertexData[vertexOffset + 6] = vTextureGreen;
       vertexData[vertexOffset + 7] = uTextureBlue;
       vertexData[vertexOffset + 8] = vTextureBlue;
       vertexOffset += COMPONENTS_PER_VERT;
     }
   }
   this.nIndices = 3158;
   final short[] indexData = new short[this.nIndices];
   short indexOffset = 0;
   vertexOffset = 0;
   for (int row2 = 0; row2 < 39; ++row2) {
     if (row2 > 0) {
       indexData[indexOffset] = indexData[indexOffset - 1];
       ++indexOffset;
     }
     for (int col2 = 0; col2 < 40; ++col2) {
       if (col2 > 0) {
         if (row2 % 2 == 0) {
           ++vertexOffset;
         } else {
           --vertexOffset;
         }
       }
       indexData[indexOffset] = vertexOffset;
       ++indexOffset;
       indexData[indexOffset] = (short) (vertexOffset + 40);
       ++indexOffset;
     }
     vertexOffset += 40;
   }
   final FloatBuffer vertexBuffer =
       ByteBuffer.allocateDirect(vertexData.length * BYTES_PER_FLOAT)
           .order(ByteOrder.nativeOrder())
           .asFloatBuffer();
   vertexBuffer.put(vertexData).position(0);
   final ShortBuffer indexBuffer =
       ByteBuffer.allocateDirect(indexData.length * BYTES_PER_SHORT)
           .order(ByteOrder.nativeOrder())
           .asShortBuffer();
   indexBuffer.put(indexData).position(0);
   final int[] bufferIds = new int[2];
   GLES20.glGenBuffers(2, bufferIds, 0);
   this.mArrayBufferId = bufferIds[0];
   this.mElementBufferId = bufferIds[1];
   GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.mArrayBufferId);
   GLES20.glBufferData(
       GLES20.GL_ARRAY_BUFFER,
       vertexData.length * BYTES_PER_FLOAT,
       (Buffer) vertexBuffer,
       GLES20.GL_STATIC_DRAW);
   GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, this.mElementBufferId);
   GLES20.glBufferData(
       GLES20.GL_ELEMENT_ARRAY_BUFFER,
       indexData.length * BYTES_PER_SHORT,
       (Buffer) indexBuffer,
       GLES20.GL_STATIC_DRAW);
   GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
   GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
 }
 private float computeDistortionScale(
     final Distortion distortion, final float screenWidthM, final float interpupillaryDistanceM) {
   return distortion.distortionFactor(
       (screenWidthM / 2.0f - interpupillaryDistanceM / 2.0f) / (screenWidthM / 4.0f));
 }