content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * 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 android.view.shadow;
  
  import android.graphics.Bitmap;
  import android.graphics.Bitmap.Config;
  
  import java.util.Arrays;
  
  import static android.view.math.Math3DHelper.max;
  import static android.view.math.Math3DHelper.min;
  
  /**
   * 2D Triangle buffer element that colours using z value. (z scale set).
   */
  class TriangleBuffer {
      int mWidth;
      int mHeight;
      int mImgWidth;
      int mImgHeight;
      int mBorder;
      Bitmap mBitmap;
      int mData[];
      private float mMinX;
      private float mMaxX;
      private float mMinY;
      private float mMaxY;
  
      public void setSize(int width, int height, int border) {
          if (mWidth == width && mHeight == height) {
              return;
          }
          mWidth = width-2*border;
          mHeight = height-2*border;
          mBorder = border;
          mImgWidth = width;
          mImgHeight = height;
  
          setScale(0, width, 0, height);
  
          mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
          mData = new int[width * height];
      }
  
      public void drawTriangles(int[] index, float[] vert, float[] color,float scale) {
          int indexSize = index.length / 3;
          for (int i = 0; i < indexSize; i++) {
              int vIndex = index[i * 3 + 0];
              float vx = vert[vIndex * 2 + 0];
              float vy = vert[vIndex * 2 + 1];
              float c =  scale*color[vIndex * 4 + 3];
              float fx3 = vx, fy3 = vy, fz3 = c;
  
              vIndex = index[i * 3 + 1];
              vx = vert[vIndex * 2 + 0];
              vy = vert[vIndex * 2 + 1];
              c =  scale*color[vIndex * 4 + 3];
              float fx2 = vx, fy2 = vy, fz2 = c;
  
              vIndex = index[i * 3 + 2];
              vx = vert[vIndex * 2 + 0];
              vy = vert[vIndex * 2 + 1];
              c =  scale*color[vIndex * 4 + 3];
              float fx1 = vx, fy1 = vy, fz1 = c;
  
              triangleZBuffMin(mData, mImgWidth, mImgHeight, fx3, fy3, fz3, fx2, fy2,
                      fz2, fx1, fy1, fz1);
              triangleZBuffMin(mData, mImgWidth, mImgHeight, fx1, fy1, fz1, fx2, fy2,
                      fz2, fx3, fy3, fz3);
          }
          mBitmap.setPixels(mData, 0, mWidth, 0, 0, mWidth, mHeight);
      }
  
      public void drawTriangles(float[] strip,float scale) {
          for (int i = 0; i < strip.length-8; i+=3) {
              float fx3 = strip[i], fy3 = strip[i+1], fz3 = scale* strip[i+2];
              float fx2 = strip[i+3], fy2 = strip[i+4], fz2 = scale* strip[i+5];
              float fx1 = strip[i+6], fy1 = strip[i+7], fz1 = scale* strip[i+8];
  
              if (fx1*(fy2-fy3)+fx2*(fy3-fy1)+fx3*(fy1-fy2) ==0) {
                  continue;
              }
              triangleZBuffMin(mData, mImgWidth, mImgHeight, fx3, fy3, fz3, fx2, fy2,
                      fz2, fx1, fy1, fz1);
          }
          mBitmap.setPixels(mData, 0, mWidth, 0, 0, mWidth, mHeight);
      }
  
      public Bitmap getImage() {
          return mBitmap;
      }
  
      private static void triangleZBuffMin(int[] buff, int w, int h, float fx3,
              float fy3, float fz3, float fx2, float fy2, float fz2, float fx1,
              float fy1, float fz1) {
          if (((fx1 - fx2) * (fy3 - fy2) - (fy1 - fy2) * (fx3 - fx2)) < 0) {
              float tmpx = fx1;
              float tmpy = fy1;
              float tmpz = fz1;
              fx1 = fx2;
              fy1 = fy2;
              fz1 = fz2;
              fx2 = tmpx;
              fy2 = tmpy;
              fz2 = tmpz;
          }
          // using maxmima
          // solve([x1*dx+y1*dy+zoff=z1,x2*dx+y2*dy+zoff=z2,x3*dx+y3*dy+zoff=z3],[dx,dy,zoff]);
          double d = (fx1 * (fy3 - fy2) - fx2 * fy3 + fx3 * fy2 + (fx2 - fx3) * fy1);
          if (d == 0) {
              return;
          }
          float dx = (float) (-(fy1 * (fz3 - fz2) - fy2 * fz3 + fy3 * fz2 + (fy2 - fy3)
                  * fz1) / d);
          float dy = (float) ((fx1 * (fz3 - fz2) - fx2 * fz3 + fx3 * fz2 + (fx2 - fx3)
                  * fz1) / d);
          float zoff = (float) ((fx1 * (fy3 * fz2 - fy2 * fz3) + fy1
                  * (fx2 * fz3 - fx3 * fz2) + (fx3 * fy2 - fx2 * fy3) * fz1) / d);
  
          // 28.4 fixed-point coordinates
          int y1 = (int) (16.0f * fy1 + .5f);
          int y2 = (int) (16.0f * fy2 + .5f);
          int y3 = (int) (16.0f * fy3 + .5f);
  
          int x1 = (int) (16.0f * fx1 + .5f);
          int x2 = (int) (16.0f * fx2 + .5f);
          int x3 = (int) (16.0f * fx3 + .5f);
  
          int dx12 = x1 - x2;
          int dx23 = x2 - x3;
          int dx31 = x3 - x1;
  
          int dy12 = y1 - y2;
          int dy23 = y2 - y3;
          int dy31 = y3 - y1;
  
          int fdx12 = dx12 << 4;
          int fdx23 = dx23 << 4;
          int fdx31 = dx31 << 4;
  
          int fdy12 = dy12 << 4;
          int fdy23 = dy23 << 4;
          int fdy31 = dy31 << 4;
  
          int minx = (min(x1, x2, x3) + 0xF) >> 4;
          int maxx = (max(x1, x2, x3) + 0xF) >> 4;
          int miny = (min(y1, y2, y3) + 0xF) >> 4;
          int maxy = (max(y1, y2, y3) + 0xF) >> 4;
  
          if (miny < 0) {
              miny = 0;
          }
          if (minx < 0) {
              minx = 0;
          }
          if (maxx > w) {
              maxx = w;
          }
          if (maxy > h) {
              maxy = h;
          }
          int off = miny * w;
  
          int c1 = dy12 * x1 - dx12 * y1;
          int c2 = dy23 * x2 - dx23 * y2;
          int c3 = dy31 * x3 - dx31 * y3;
  
          if (dy12 < 0 || (dy12 == 0 && dx12 > 0)) {
              c1++;
          }
          if (dy23 < 0 || (dy23 == 0 && dx23 > 0)) {
              c2++;
          }
          if (dy31 < 0 || (dy31 == 0 && dx31 > 0)) {
              c3++;
          }
          int cy1 = c1 + dx12 * (miny << 4) - dy12 * (minx << 4);
          int cy2 = c2 + dx23 * (miny << 4) - dy23 * (minx << 4);
          int cy3 = c3 + dx31 * (miny << 4) - dy31 * (minx << 4);
  
          for (int y = miny; y < maxy; y++) {
              int cx1 = cy1;
              int cx2 = cy2;
              int cx3 = cy3;
              float p = zoff + dy * y;
              for (int x = minx; x < maxx; x++) {
                  if (cx1 > 0 && cx2 > 0 && cx3 > 0) {
                      int point = x + off;
                      float zval = p + dx * x;
                      buff[point] = ((int) (zval * 255)) << 24;
                  }
                  cx1 -= fdy12;
                  cx2 -= fdy23;
                  cx3 -= fdy31;
              }
              cy1 += fdx12;
              cy2 += fdx23;
              cy3 += fdx31;
              off += w;
          }
      }
  
      private void setScale(float minx, float maxx, float miny, float maxy) {
          mMinX = minx;
          mMaxX = maxx;
          mMinY = miny;
          mMaxY = maxy;
      }
  
      public void clear() {
          Arrays.fill(mData, 0);
      }
  }