public void calcShadows(int pX, int pY, RasterPoint pDestRasterPoint) {
   pDestRasterPoint.hasShadows = true;
   for (int i = 0; i < shadowZBuf.length; i++) {
     pDestRasterPoint.visibility[i] = 1.0;
     if (shadowZBuf[i] != null) {
       if (shadowSoften) {
         calcSmoothShadowIntensity(
             pX, pY, pDestRasterPoint, i, shadowSmoothRadius, shadowSmoothKernel);
       } else {
         calcFastShadowIntensity(pX, pY, pDestRasterPoint, i);
       }
       pDestRasterPoint.visibility[i] =
           GfxMathLib.clamp(pDestRasterPoint.visibility[i] + shadowIntensity[i]);
     }
   }
 }
 public void accelerateShadows() {
   if (withAcceleration) {
     accLightProjectionZBuf = new float[lightCount][][];
     for (int i = 0; i < lightCount; i++) {
       if (shadowZBuf[i] != null) {
         accLightProjectionZBuf[i] = new float[rasterWidth][rasterHeight];
         for (int pX = 0; pX < rasterWidth; pX++) {
           for (int pY = 0; pY < rasterHeight; pY++) {
             accLightProjectionZBuf[i][pX][pY] = NormalsCalculator.ZBUF_ZMIN;
             float originX = originXBuf[pX][pY];
             if (originX != NormalsCalculator.ZBUF_ZMIN) {
               float originY = originYBuf[pX][pY];
               if (originY != NormalsCalculator.ZBUF_ZMIN) {
                 float originZ = originZBuf[pX][pY];
                 if (originZ != NormalsCalculator.ZBUF_ZMIN) {
                   int x =
                       projectPointToLightMapX(
                           i,
                           lightViewCalculator.applyLightProjectionX(
                               i, originX, originY, originZ));
                   int y =
                       projectPointToLightMapY(
                           i,
                           lightViewCalculator.applyLightProjectionY(
                               i, originX, originY, originZ));
                   if (x >= 0
                       && x < shadowZBuf[i].length
                       && y >= 0
                       && y < shadowZBuf[i][0].length) {
                     double lightZ =
                         lightViewCalculator.applyLightProjectionZ(i, originX, originY, originZ);
                     accLightProjectionZBuf[i][pX][pY] =
                         (float) GfxMathLib.step(shadowZBuf[i][x][y] - shadowDistBias, lightZ);
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
 }
  public ShadowCalculator(
      int rasterWidth,
      int rasterHeight,
      float[][] originXBuf,
      float[][] originYBuf,
      float[][] originZBuf,
      double imgSize,
      Flame flame) {
    this.rasterWidth = rasterWidth;
    this.rasterHeight = rasterHeight;
    this.originXBuf = originXBuf;
    this.originYBuf = originYBuf;
    this.originZBuf = originZBuf;

    lightCount = flame.getSolidRenderSettings().getLights().size();
    shadowZBuf = new float[lightCount][][];

    pre_shadowIndex = new int[lightCount];
    pre_shadowXBuf = new float[lightCount][];
    pre_shadowYBuf = new float[lightCount][];
    pre_shadowZBuf = new float[lightCount][];
    shadowMapXCentre = new double[lightCount];
    shadowMapYCentre = new double[lightCount];
    shadowMapXScale = new double[lightCount];
    shadowMapYScale = new double[lightCount];

    lightX = new double[lightCount];
    lightY = new double[lightCount];
    shadowIntensity = new double[lightCount];

    shadowMapSize = flame.getSolidRenderSettings().getShadowmapSize();
    if (shadowMapSize < 64) {
      shadowMapSize = 64;
    }
    shadowDistBias = flame.getSolidRenderSettings().getShadowmapBias();

    for (int i = 0; i < lightCount; i++) {
      DistantLight light = flame.getSolidRenderSettings().getLights().get(i);
      if (light.isCastShadows()) {
        shadowZBuf[i] = new float[shadowMapSize][shadowMapSize];
        pre_shadowXBuf[i] = new float[PRE_SHADOWMAP_SIZE];
        pre_shadowYBuf[i] = new float[PRE_SHADOWMAP_SIZE];
        pre_shadowZBuf[i] = new float[PRE_SHADOWMAP_SIZE];
        for (int k = 0; k < shadowZBuf[i].length; k++) {
          for (int l = 0; l < shadowZBuf[i][0].length; l++) {
            shadowZBuf[i][k][l] = NormalsCalculator.ZBUF_ZMIN;
          }
        }
        lightX[i] = light.getAltitude();
        lightY[i] = light.getAzimuth();
        shadowIntensity[i] = 1.0 - GfxMathLib.clamp(light.getShadowIntensity(), 0.0, 1.0);
      } else {
        shadowZBuf[i] = null;
        pre_shadowXBuf[i] = pre_shadowYBuf[i] = pre_shadowZBuf[i] = null;
      }
    }

    shadowSoften = ShadowType.SMOOTH.equals(flame.getSolidRenderSettings().getShadowType());

    double rawSmoothRadius = flame.getSolidRenderSettings().getShadowSmoothRadius();
    if (rawSmoothRadius < MathLib.EPSILON) {
      rawSmoothRadius = 0.0;
    }

    shadowSmoothRadius = clipSmoothRadius(Tools.FTOI(rawSmoothRadius * 6.0 * imgSize / 1000.0));
    if (shadowSmoothRadius < 1.0) {
      shadowSoften = false;
      shadowSmoothKernel = null;
    } else {
      shadowSmoothKernel = getShadowSmoothKernel(shadowSmoothRadius);
    }
  }
  private void calcSmoothShadowIntensity(
      int pX,
      int pY,
      RasterPoint pDestRasterPoint,
      int i,
      int shadowSmoothRadius,
      double[][] shadowSmoothKernel) {
    pDestRasterPoint.visibility[i] = 1.0;
    double totalIntensity = 0.0;

    if (accLightProjectionZBuf != null && accLightProjectionZBuf[i] != null) {
      int dl = shadowSmoothRadius / 8 + 1;
      for (int k = -shadowSmoothRadius; k <= shadowSmoothRadius; k += dl) {
        int dstX = pX + k;
        if (dstX >= 0 && dstX < originXBuf.length) {
          for (int l = -shadowSmoothRadius; l <= shadowSmoothRadius; l += dl) {
            int dstY = pY + l;
            if (dstY >= 0 && dstY < originXBuf[0].length) {
              if (accLightProjectionZBuf[i][dstX][dstY] > NormalsCalculator.ZBUF_ZMIN) {
                double intensity =
                    shadowSmoothKernel[k + shadowSmoothRadius][l + shadowSmoothRadius];
                totalIntensity += intensity;
                pDestRasterPoint.visibility[i] += accLightProjectionZBuf[i][dstX][dstY] * intensity;
              }
            }
          }
        }
      }
    } else {

      for (int k = -shadowSmoothRadius; k <= shadowSmoothRadius; k++) {
        int dstX = pX + k;
        if (dstX >= 0 && dstX < originXBuf.length) {
          for (int l = -shadowSmoothRadius; l <= shadowSmoothRadius; l++) {
            int dstY = pY + l;
            if (dstY >= 0 && dstY < originXBuf[0].length) {
              float originX = originXBuf[dstX][dstY];
              if (originX != NormalsCalculator.ZBUF_ZMIN) {
                float originY = originYBuf[dstX][dstY];
                if (originY != NormalsCalculator.ZBUF_ZMIN) {
                  float originZ = originZBuf[dstX][dstY];
                  if (originZ != NormalsCalculator.ZBUF_ZMIN) {
                    int x =
                        projectPointToLightMapX(
                            i,
                            lightViewCalculator.applyLightProjectionX(
                                i, originX, originY, originZ));
                    int y =
                        projectPointToLightMapY(
                            i,
                            lightViewCalculator.applyLightProjectionY(
                                i, originX, originY, originZ));
                    if (x >= 0
                        && x < shadowZBuf[i].length
                        && y >= 0
                        && y < shadowZBuf[i][0].length) {
                      double intensity =
                          shadowSmoothKernel[k + shadowSmoothRadius][l + shadowSmoothRadius];
                      totalIntensity += intensity;
                      double lightZ =
                          lightViewCalculator.applyLightProjectionZ(i, originX, originY, originZ);
                      pDestRasterPoint.visibility[i] +=
                          GfxMathLib.step(shadowZBuf[i][x][y] - shadowDistBias, lightZ) * intensity;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

    if (totalIntensity > MathLib.EPSILON) {
      pDestRasterPoint.visibility[i] /= totalIntensity;
    }
  }