public void refreshFlameImage(
      Flame flame, boolean pDrawTriangles, double pFPS, long pFrame, boolean pDrawFPS) {
    FlamePanel imgPanel = getFlamePanel();
    if (imgPanel == null) return;
    Rectangle bounds = imgPanel.getImageBounds();
    int width = bounds.width;
    int height = bounds.height;
    if (width >= 16 && height >= 16) {
      RenderInfo info = new RenderInfo(width, height, RenderMode.PREVIEW);
      if (flame != null) {
        double oldSpatialFilterRadius = flame.getSpatialFilterRadius();
        double oldSampleDensity = flame.getSampleDensity();
        imgPanel.setDrawTriangles(pDrawTriangles);
        try {
          double wScl = (double) info.getImageWidth() / (double) flame.getWidth();
          double hScl = (double) info.getImageHeight() / (double) flame.getHeight();
          flame.setPixelsPerUnit((wScl + hScl) * 0.5 * flame.getPixelsPerUnit());
          flame.setWidth(info.getImageWidth());
          flame.setHeight(info.getImageHeight());

          Flame renderFlame = new FlamePreparer(prefs).createRenderFlame(flame);
          FlameRenderer renderer = new FlameRenderer(renderFlame, prefs, false, false);
          renderer.setProgressUpdater(null);
          RenderedFlame res = renderer.renderFlame(info);
          SimpleImage img = res.getImage();
          if (pDrawFPS) {
            TextTransformer txt = new TextTransformer();
            txt.setText1(
                "fps: "
                    + Tools.doubleToString(pFPS)
                    + ", time: "
                    + Tools.doubleToString(pFrame / 1000.0)
                    + "s");
            txt.setAntialiasing(false);
            txt.setColor(Color.LIGHT_GRAY);
            txt.setMode(Mode.NORMAL);
            txt.setFontStyle(FontStyle.PLAIN);
            txt.setFontName("Arial");
            txt.setFontSize(10);
            txt.setHAlign(HAlignment.LEFT);
            txt.setVAlign(VAlignment.BOTTOM);
            txt.transformImage(img);
          }
          imgPanel.setImage(img);
        } finally {
          flame.setSpatialFilterRadius(oldSpatialFilterRadius);
          flame.setSampleDensity(oldSampleDensity);
        }
      }
    } else {
      try {
        imgPanel.setImage(new SimpleImage(width, height));
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    flameRootPanel.repaint();
  }
Beispiel #2
0
  public Flame createRenderFlame(Flame pSrc) {
    Flame res = pSrc.makeCopy();

    //    res.setBGTransparency(false);
    //    res.setGamma(1.5);
    //    res.setBrightness(3.36);
    //    res.getPalette().setModRed(90);
    //    res.getPalette().setModRed(60);
    //    res.getPalette().setModBlue(-60);
    //    res.setSampleDensity(2 * prefs.getTinaRenderRealtimeQuality());
    //    res.setSpatialFilterRadius(0.75);

    res.setBGTransparency(false);
    //    res.setGamma(res.getGamma() - 0.5);
    //    res.getPalette().setModSaturation(-24);
    //    res.setGamma(2.5);
    //    res.setBrightness(5.0);
    //    res.getPalette().setModRed(30);
    // res.getPalette().setModSaturation(-160);
    //    res.getPalette().setModRed(20);
    //    res.getPalette().setModBlue(-20);
    if (res.getSolidRenderSettings().isSolidRenderingEnabled()) {
      res.getSolidRenderSettings().setAoEnabled(false);
      res.getSolidRenderSettings().setShadowType(ShadowType.OFF);
      res.setCamDOF(0.0);
      res.setSampleDensity(prefs.getTinaRenderRealtimeQuality());
    } else {
      res.setSampleDensity(2 * prefs.getTinaRenderRealtimeQuality());
    }

    return res;
  }
 public void importFlame(Flame pFlame) {
   if (pFlame != null) {
     project.getFlames().add(validateDancingFlame(pFlame.makeCopy()));
     refreshProjectFlames();
     enableControls();
   }
 }
  public void replaceFlameFromEditorBtn_clicked(Flame pFlame) {
    if (pFlame != null) {
      Flame flame = poolFlameHolder.getFlame();
      if (flame != null) {
        int idx = flamePropertiesTree.getSelectionRows()[0];
        // cant remove the flame by object reference because its a clone
        Flame newFlame = validateDancingFlame(pFlame.makeCopy());
        Flame oldFlame = project.getFlames().get(idx);
        for (Motion motion : project.getMotions()) {
          for (MotionLink link : motion.getMotionLinks()) {
            if (link.getProperyPath().getFlame().isEqual(oldFlame)) {
              link.getProperyPath().setFlame(newFlame);
            }
          }
        }

        project.getFlames().set(idx, newFlame);
        refreshProjectFlames();
        if (project.getFlames().size() == 0) {
          flamePropertiesTree_changed(null);
        } else {
          try {
            flamePropertiesTree.setSelectionRow(idx);
          } catch (Exception ex) {

          }
        }
        enableControls();
      }
    }
  }
 private void refreshFlamesCmb() {
   Flame selFlame =
       flamesCmb.getSelectedIndex() >= 0
               && flamesCmb.getSelectedIndex() < project.getFlames().size()
           ? project.getFlames().get(flamesCmb.getSelectedIndex())
           : null;
   int newSelIdx = -1;
   flamesCmb.removeAllItems();
   for (int i = 0; i < project.getFlames().size(); i++) {
     Flame flame = project.getFlames().get(i);
     if (newSelIdx < 0 && flame.equals(selFlame)) {
       newSelIdx = i;
     }
     flamesCmb.addItem(flamePropertiesTreeService.getFlameCaption(flame));
   }
   flamesCmb.setSelectedIndex(
       newSelIdx >= 0 ? newSelIdx : project.getFlames().size() > 0 ? 0 : -1);
 }
 private Flame validateDancingFlame(Flame pFlame) {
   for (Layer layer : pFlame.getLayers()) {
     if (layer.getFinalXForms().size() == 0) {
       XForm xForm = new XForm();
       xForm.addVariation(1.0, new Linear3DFunc());
       layer.getFinalXForms().add(xForm);
     }
   }
   return pFlame;
 }
 public void refreshPoolPreviewFlameImage(Flame flame) {
   FlamePanel imgPanel = getPoolPreviewFlamePanel();
   if (imgPanel == null) return;
   Rectangle bounds = imgPanel.getImageBounds();
   int width = bounds.width;
   int height = bounds.height;
   if (width >= 16 && height >= 16) {
     RenderInfo info = new RenderInfo(width, height, RenderMode.PREVIEW);
     if (flame != null) {
       imgPanel.setDrawTriangles(false);
       double wScl = (double) info.getImageWidth() / (double) flame.getWidth();
       double hScl = (double) info.getImageHeight() / (double) flame.getHeight();
       flame.setPixelsPerUnit((wScl + hScl) * 0.5 * flame.getPixelsPerUnit());
       flame.setWidth(info.getImageWidth());
       flame.setHeight(info.getImageHeight());
       Flame renderFlame = new FlamePreparer(prefs).createRenderFlame(flame);
       FlameRenderer renderer = new FlameRenderer(renderFlame, prefs, false, false);
       renderer.setProgressUpdater(null);
       RenderedFlame res = renderer.renderFlame(info);
       imgPanel.setImage(res.getImage());
     } else {
       imgPanel.setImage(new SimpleImage(width, height));
     }
   } else {
     imgPanel.setImage(new SimpleImage(width, height));
   }
   poolFlamePreviewPnl.repaint();
 }
  public void renameFlameBtn_clicked() {
    try {
      Flame flame = poolFlameHolder.getFlame();
      if (flame != null) {
        int idx = flamePropertiesTree.getSelectionRows()[0];
        String s =
            StandardDialogs.promptForText(
                rootTabbedPane, "Please enter the new title:", flame.getName());
        if (s != null) {
          for (Flame tFlame : project.getFlames()) {
            if (!tFlame.isEqual(flame) && s.equals(tFlame.getName())) {
              throw new RuntimeException(
                  "A different flame with the name \"" + s + "\" alread exists");
            }
          }
          flame.setName(s);
          refreshProjectFlames();
          if (project.getFlames().size() == 0) {
            flamePropertiesTree_changed(null);
          } else {
            try {
              flamePropertiesTree.setSelectionRow(idx);
            } catch (Exception ex) {

            }
          }
          enableControls();
        }
      }
    } catch (Exception ex) {
      errorHandler.handleError(ex);
    }
  }
 private static Flame morphFlames_fade(
     Prefs pPrefs, Flame pFlame1, Flame pFlame2, int pFrame, int pFrames) {
   if (pFrame < 1 || pFrames < 2) return pFlame1;
   double fScl = (double) (pFrame - 1) / (pFrames - 1);
   if (fScl <= MathLib.EPSILON) {
     return pFlame1;
   } else if (fScl >= 1.0 - MathLib.EPSILON) {
     return pFlame2;
   }
   // fade out layerz of the source flame
   Flame res = pFlame1.makeCopy();
   morphFlameValues(pFlame1, pFlame2, fScl, res);
   for (Layer layer : res.getLayers()) {
     layer.setWeight(layer.getWeight() * (1.0 - fScl));
   }
   // add and fade in layerz of the dest flame
   for (Layer layer : pFlame2.getLayers()) {
     Layer copy = layer.makeCopy();
     copy.setWeight(copy.getWeight() * fScl);
     res.getLayers().add(copy);
   }
   return res;
 }
  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);
    }
  }
  protected void parseFlameAttributes(Flame pFlame, String pXML) {
    XMLAttributes atts = Tools.parseAttributes(pXML);
    String hs;
    if ((hs = atts.get(ATTR_NAME)) != null) {
      pFlame.setName(hs);
    }
    if ((hs = atts.get(ATTR_SIZE)) != null) {
      String s[] = hs.split(" ");
      pFlame.setWidth(Integer.parseInt(s[0]));
      pFlame.setHeight(Integer.parseInt(s[1]));
    }
    if ((hs = atts.get(ATTR_CENTER)) != null) {
      String s[] = hs.split(" ");
      pFlame.setCentreX(Double.parseDouble(s[0]));
      pFlame.setCentreY(Double.parseDouble(s[1]));
    }
    if ((hs = atts.get(ATTR_SCALE)) != null) {
      pFlame.setPixelsPerUnit(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_ROTATE)) != null) {
      //      pFlame.setCamRoll(-Double.parseDouble(hs) * 180.0 / Math.PI);
      pFlame.setCamRoll(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_FILTER)) != null) {
      pFlame.setSpatialFilterRadius(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_FILTER_KERNEL)) != null) {
      try {
        FilterKernelType kernel = FilterKernelType.valueOf(hs);
        pFlame.setSpatialFilterKernel(kernel);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    // Disable DE filter and check if it is set explicitely on. There are lots of Apo flames out
    // there
    // which are carrying DE settings, but they were never used and may look terrible (e. g. DE max
    // radius 9.0)
    pFlame.setDeFilterEnabled(false);
    if ((hs = atts.get(ATTR_DE_FILTER_ENABLED)) != null) {
      pFlame.setDeFilterEnabled(Integer.parseInt(hs) == 1);
    }
    if ((hs = atts.get(ATTR_DE_FILTER_MAX_RADIUS)) != null) {
      pFlame.setDeFilterMaxRadius(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_DE_FILTER_MIN_RADIUS)) != null) {
      pFlame.setDeFilterMinRadius(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_DE_FILTER_CURVE)) != null) {
      pFlame.setDeFilterCurve(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_DE_FILTER_KERNEL)) != null) {
      try {
        FilterKernelType kernel = FilterKernelType.valueOf(hs);
        pFlame.setDeFilterKernel(kernel);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
    if ((hs = atts.get(ATTR_QUALITY)) != null) {
      pFlame.setSampleDensity(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_BACKGROUND)) != null) {
      String s[] = hs.split(" ");
      pFlame.setBGColorRed(Tools.roundColor(255.0 * Double.parseDouble(s[0])));
      pFlame.setBGColorGreen(Tools.roundColor(255.0 * Double.parseDouble(s[1])));
      pFlame.setBGColorBlue(Tools.roundColor(255.0 * Double.parseDouble(s[2])));
    }
    if ((hs = atts.get(ATTR_BRIGHTNESS)) != null) {
      pFlame.setBrightness(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_BG_TRANSPARENCY)) != null) {
      pFlame.setBGTransparency(Integer.parseInt(hs) == 1);
    } else {
      pFlame.setBGTransparency(prefs.isTinaDefaultBGTransparency());
    }
    if ((hs = atts.get(ATTR_GAMMA)) != null) {
      pFlame.setGamma(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_GAMMA_THRESHOLD)) != null) {
      pFlame.setGammaThreshold(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_VIBRANCY)) != null) {
      pFlame.setVibrancy(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CONTRAST)) != null) {
      pFlame.setContrast(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_PERSP)) != null) {
      pFlame.setCamPerspective(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_PERSPECTIVE)) != null) {
      pFlame.setCamPerspective(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_ZPOS)) != null) {
      pFlame.setCamZ(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_XFOCUS)) != null) {
      pFlame.setFocusX(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_YFOCUS)) != null) {
      pFlame.setFocusY(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_ZFOCUS)) != null) {
      pFlame.setFocusZ(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_ZDIMISH)) != null) {
      pFlame.setDimishZ(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_DOF)) != null) {
      pFlame.setCamDOF(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_DOF_AREA)) != null) {
      pFlame.setCamDOFArea(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_DOF_EXPONENT)) != null) {
      pFlame.setCamDOFExponent(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_CAM_PITCH)) != null) {
      pFlame.setCamPitch(Double.parseDouble(hs) * 180.0 / Math.PI);
    }
    if ((hs = atts.get(ATTR_CAM_YAW)) != null) {
      pFlame.setCamYaw(Double.parseDouble(hs) * 180.0 / Math.PI);
    }
    if ((hs = atts.get(ATTR_CAM_ZOOM)) != null) {
      pFlame.setCamZoom(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_NEW_DOF)) != null) {
      pFlame.setNewCamDOF("1".equals(hs));
    }
    // preserve-z
    if ((hs = atts.get(ATTR_PRESERVE_Z)) != null) {
      pFlame.setPreserveZ("1".equals(hs));
    }
    // profiles
    if ((hs = atts.get(ATTR_RESOLUTION_PROFILE)) != null) {
      pFlame.setResolutionProfile(hs);
    }
    if ((hs = atts.get(ATTR_QUALITY_PROFILE)) != null) {
      pFlame.setQualityProfile(hs);
    }
    // Shading
    if ((hs = atts.get(ATTR_SHADING_SHADING)) != null) {
      try {
        pFlame.getShadingInfo().setShading(Shading.valueOf(hs));
      } catch (Exception ex) {
        pFlame.getShadingInfo().setShading(Shading.FLAT);
        ex.printStackTrace();
      }
    }
    if ((hs = atts.get(ATTR_SHADING_AMBIENT)) != null) {
      pFlame.getShadingInfo().setAmbient(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DIFFUSE)) != null) {
      pFlame.getShadingInfo().setDiffuse(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_PHONG)) != null) {
      pFlame.getShadingInfo().setPhong(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_PHONGSIZE)) != null) {
      pFlame.getShadingInfo().setPhongSize(Double.parseDouble(hs));
    }
    int lightCount;
    if ((hs = atts.get(ATTR_SHADING_LIGHTCOUNT)) != null) {
      lightCount = Integer.parseInt(hs);
    } else {
      lightCount = 0;
    }
    for (int i = 0; i < lightCount; i++) {
      if ((hs = atts.get(ATTR_SHADING_LIGHTPOSX_ + i)) != null) {
        pFlame.getShadingInfo().setLightPosX(i, Double.parseDouble(hs));
      }
      if ((hs = atts.get(ATTR_SHADING_LIGHTPOSY_ + i)) != null) {
        pFlame.getShadingInfo().setLightPosY(i, Double.parseDouble(hs));
      }
      if ((hs = atts.get(ATTR_SHADING_LIGHTPOSZ_ + i)) != null) {
        pFlame.getShadingInfo().setLightPosZ(i, Double.parseDouble(hs));
      }
      if ((hs = atts.get(ATTR_SHADING_LIGHTRED_ + i)) != null) {
        pFlame.getShadingInfo().setLightRed(i, Integer.parseInt(hs));
      }
      if ((hs = atts.get(ATTR_SHADING_LIGHTGREEN_ + i)) != null) {
        pFlame.getShadingInfo().setLightGreen(i, Integer.parseInt(hs));
      }
      if ((hs = atts.get(ATTR_SHADING_LIGHTBLUE_ + i)) != null) {
        pFlame.getShadingInfo().setLightBlue(i, Integer.parseInt(hs));
      }
    }
    if ((hs = atts.get(ATTR_SHADING_BLUR_RADIUS)) != null) {
      pFlame.getShadingInfo().setBlurRadius(Integer.parseInt(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_BLUR_FADE)) != null) {
      pFlame.getShadingInfo().setBlurFade(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_BLUR_FALLOFF)) != null) {
      pFlame.getShadingInfo().setBlurFallOff(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_NEW_LINEAR)) != null) {
      pFlame.setPreserveZ(hs.length() > 0 && Integer.parseInt(hs) == 1);
    }

    if ((hs = atts.get(ATTR_ANTIALIAS_AMOUNT)) != null) {
      pFlame.setAntialiasAmount(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_ANTIALIAS_RADIUS)) != null) {
      pFlame.setAntialiasRadius(Double.parseDouble(hs));
    }

    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_RADIUS)) != null) {
      pFlame.getShadingInfo().setDistanceColorRadius(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_SCALE)) != null) {
      pFlame.getShadingInfo().setDistanceColorScale(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_EXPONENT)) != null) {
      pFlame.getShadingInfo().setDistanceColorExponent(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_OFFSETX)) != null) {
      pFlame.getShadingInfo().setDistanceColorOffsetX(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_OFFSETY)) != null) {
      pFlame.getShadingInfo().setDistanceColorOffsetY(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_OFFSETZ)) != null) {
      pFlame.getShadingInfo().setDistanceColorOffsetZ(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_STYLE)) != null) {
      pFlame.getShadingInfo().setDistanceColorStyle(Integer.parseInt(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_COORDINATE)) != null) {
      pFlame.getShadingInfo().setDistanceColorCoordinate(Integer.parseInt(hs));
    }
    if ((hs = atts.get(ATTR_SHADING_DISTANCE_COLOR_SHIFT)) != null) {
      pFlame.getShadingInfo().setDistanceColorShift(Double.parseDouble(hs));
    }
  }
  protected void parseXFormAttributes(Flame pFlame, XForm pXForm, String pXML) {
    XMLAttributes atts = Tools.parseAttributes(pXML);
    String hs;
    if ((hs = atts.get(ATTR_NAME)) != null) {
      pXForm.setName(hs);
    }
    if ((hs = atts.get(ATTR_WEIGHT)) != null) {
      pXForm.setWeight(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_COLOR)) != null) {
      pXForm.setColor(Double.parseDouble(hs));
    }
    // legacy
    if ((hs = atts.get(ATTR_ANTIALIAS_AMOUNT)) != null) {
      double value = Double.parseDouble(hs);
      if (value > 0) pFlame.setAntialiasAmount(value);
    }
    // legacy
    if ((hs = atts.get(ATTR_ANTIALIAS_RADIUS)) != null) {
      double value = Double.parseDouble(hs);
      if (value > 0) pFlame.setAntialiasRadius(value);
    }
    if ((hs = atts.get(ATTR_OPACITY)) != null) {
      double opacity = Double.parseDouble(hs);
      pXForm.setOpacity(opacity);
      if (Math.abs(opacity) <= MathLib.EPSILON) {
        pXForm.setDrawMode(DrawMode.HIDDEN);
      } else if (Math.abs(opacity - 1.0) > MathLib.EPSILON) {
        pXForm.setDrawMode(DrawMode.OPAQUE);
      } else {
        pXForm.setDrawMode(DrawMode.NORMAL);
      }
    }
    if ((hs = atts.get(ATTR_SYMMETRY)) != null) {
      pXForm.setColorSymmetry(Double.parseDouble(hs));
    }
    if ((hs = atts.get(ATTR_COEFS)) != null) {
      String s[] = hs.split(" ");
      pXForm.setCoeff00(Double.parseDouble(s[0]));
      pXForm.setCoeff01(Double.parseDouble(s[1]));
      pXForm.setCoeff10(Double.parseDouble(s[2]));
      pXForm.setCoeff11(Double.parseDouble(s[3]));
      pXForm.setCoeff20(Double.parseDouble(s[4]));
      pXForm.setCoeff21(Double.parseDouble(s[5]));
    }
    if ((hs = atts.get(ATTR_POST)) != null) {
      String s[] = hs.split(" ");
      pXForm.setPostCoeff00(Double.parseDouble(s[0]));
      pXForm.setPostCoeff01(Double.parseDouble(s[1]));
      pXForm.setPostCoeff10(Double.parseDouble(s[2]));
      pXForm.setPostCoeff11(Double.parseDouble(s[3]));
      pXForm.setPostCoeff20(Double.parseDouble(s[4]));
      pXForm.setPostCoeff21(Double.parseDouble(s[5]));
    }
    if ((hs = atts.get(ATTR_CHAOS)) != null) {
      String s[] = hs.split(" ");
      for (int i = 0; i < s.length; i++) {
        pXForm.getModifiedWeights()[i] = Double.parseDouble(s[i]);
      }
    }
    // variations
    {
      List<String> variationNameList = VariationFuncList.getNameList();
      Map<String, String> aliasMap = VariationFuncList.getAliasMap();

      for (XMLAttribute attr : atts.getAttributes()) {
        String rawName = attr.getName();
        String name = removeIndexFromAttr(rawName);
        String varName = name;
        boolean hasVariation = variationNameList.indexOf(varName) >= 0;
        if (!hasVariation) {
          String aliasName = aliasMap.get(name);
          if (aliasName != null) {
            varName = aliasName;
            hasVariation = variationNameList.indexOf(varName) >= 0;
          }
        }
        if (hasVariation) {
          VariationFunc varFunc = VariationFuncList.getVariationFuncInstance(varName);
          Variation variation = pXForm.addVariation(Double.parseDouble(atts.get(name)), varFunc);
          // params
          {
            String paramNames[] = variation.getFunc().getParameterNames();
            String paramAltNames[] = variation.getFunc().getParameterAlternativeNames();
            if (paramNames != null) {
              if (paramAltNames != null && paramAltNames.length != paramNames.length) {
                paramAltNames = null;
              }
              for (int i = 0; i < paramNames.length; i++) {
                String pName = paramNames[i];
                String pHs;
                if ((pHs = atts.get(rawName + "_" + pName)) != null) {
                  variation.getFunc().setParameter(pName, Double.parseDouble(pHs));
                }
                // altNames can only be come from flames which were not created by JWF, so no need
                // to handle index here
                else if (paramAltNames != null && ((pHs = atts.get(paramAltNames[i])) != null)) {
                  variation.getFunc().setParameter(pName, Double.parseDouble(pHs));
                }
              }
            }
          }
          // ressources
          {
            String ressNames[] = variation.getFunc().getRessourceNames();
            if (ressNames != null) {
              for (String pName : ressNames) {
                String pHs;
                if ((pHs = atts.get(name + "_" + pName)) != null) {
                  variation.getFunc().setRessource(pName, Tools.hexStringToByteArray(pHs));
                }
              }
            }
          }
          //
        }
      }
    }
  }
  private static Flame morphFlames_morph(
      Prefs pPrefs, Flame pFlame1, Flame pFlame2, int pFrame, int pFrames) {
    if (pFrame < 1 || pFrames < 2) return pFlame1;
    double fScl = (double) (pFrame - 1) / (pFrames - 1);
    if (fScl <= MathLib.EPSILON) {
      return pFlame1;
    } else if (fScl >= 1.0 - MathLib.EPSILON) {
      return pFlame2;
    }
    Flame res = pFlame1.makeCopy();
    res.getLayers().clear();
    int layerSize1 = pFlame1.getLayers().size();
    int layerSize2 = pFlame2.getLayers().size();
    int maxLayerSize = layerSize1 > layerSize2 ? layerSize1 : layerSize2;
    for (int lIdx = 0; lIdx < maxLayerSize; lIdx++) {
      Layer layer = new Layer();
      res.getLayers().add(layer);
      // Morph layers
      if (lIdx < layerSize1 && lIdx < layerSize2) {
        Layer layer1 = pFlame1.getLayers().get(lIdx);
        Layer layer2 = pFlame2.getLayers().get(lIdx);
        layer.assign(layer1);
        layer.getXForms().clear();
        layer.getFinalXForms().clear();
        layer.setWeight(morphValue(layer1.getWeight(), layer2.getWeight(), fScl));
        // morph XForms
        {
          int size1 = layer1.getXForms().size();
          int size2 = layer2.getXForms().size();
          int maxSize = size1 > size2 ? size1 : size2;
          for (int i = 0; i < maxSize; i++) {
            XForm xForm1 = i < size1 ? layer1.getXForms().get(i) : null;
            if (xForm1 == null) {
              xForm1 = new XForm();
              xForm1.addVariation(
                  0.0, VariationFuncList.getVariationFuncInstance("linear3D", true));
              xForm1.setWeight(0.0);
            }

            XForm xForm2 = i < size2 ? layer2.getXForms().get(i) : null;
            if (xForm2 == null) {
              xForm2 = new XForm();
              xForm2.addVariation(
                  0.0, VariationFuncList.getVariationFuncInstance("linear3D", true));
              xForm2.setWeight(0.0);
            }

            XForm morphedXForm = morphXForms(pPrefs, xForm1, xForm2, fScl, pFrame, pFrames);
            layer.getXForms().add(morphedXForm);
          }
        }
        // morph final XForms
        {
          int size1 = layer1.getFinalXForms().size();
          int size2 = layer2.getFinalXForms().size();
          int maxSize = size1 > size2 ? size1 : size2;
          for (int i = 0; i < maxSize; i++) {
            XForm xForm1 = i < size1 ? layer1.getFinalXForms().get(i) : null;
            if (xForm1 == null) {
              xForm1 = new XForm();
              xForm1.addVariation(
                  0.0, VariationFuncList.getVariationFuncInstance("linear3D", true));
              xForm1.setWeight(0.0);
            }

            XForm xForm2 = i < size2 ? layer2.getFinalXForms().get(i) : null;
            if (xForm2 == null) {
              xForm2 = new XForm();
              xForm2.addVariation(
                  0.0, VariationFuncList.getVariationFuncInstance("linear3D", true));
              xForm2.setWeight(0.0);
            }

            XForm morphedXForm = morphXForms(pPrefs, xForm1, xForm2, fScl, pFrame, pFrames);
            layer.getFinalXForms().add(morphedXForm);
          }
        }
        // morph colors
        RGBPalette palette1 = layer1.getPalette();
        RGBPalette palette2 = layer2.getPalette();
        for (int i = 0; i < RGBPalette.PALETTE_SIZE; i++) {
          RGBColor color1 = palette1.getColor(i);
          RGBColor color2 = palette2.getColor(i);
          int red = Tools.roundColor(color1.getRed() + (color2.getRed() - color1.getRed()) * fScl);
          int green =
              Tools.roundColor(color1.getGreen() + (color2.getGreen() - color1.getGreen()) * fScl);
          int blue =
              Tools.roundColor(color1.getBlue() + (color2.getBlue() - color1.getBlue()) * fScl);
          layer.getPalette().setColor(i, red, green, blue);
        }
      }
      // fade out layer1 to black
      else if (lIdx < layerSize1) {
        Layer layer1 = pFlame1.getLayers().get(lIdx);
        layer.assign(layer1);
        layer.setWeight(morphValue(layer1.getWeight(), 0.0, fScl));
      }
      // fade in layer2 from black
      else if (lIdx < layerSize2) {
        Layer layer2 = pFlame2.getLayers().get(lIdx);
        layer.assign(layer2);
        layer.setWeight(morphValue(0.0, layer2.getWeight(), fScl));
      }
    }
    // morph camera settings etc.
    morphFlameValues(pFlame1, pFlame2, fScl, res);
    return res;
  }
 private static void morphFlameValues(Flame pFlame1, Flame pFlame2, double fScl, Flame res) {
   res.setCamDOF(morphValue(pFlame1.getCamDOF(), pFlame2.getCamDOF(), fScl));
   res.setCamPerspective(
       morphValue(pFlame1.getCamPerspective(), pFlame2.getCamPerspective(), fScl));
   res.setCamPitch(morphValue(pFlame1.getCamPitch(), pFlame2.getCamPitch(), fScl));
   res.setCamYaw(morphValue(pFlame1.getCamYaw(), pFlame2.getCamYaw(), fScl));
   res.setCamRoll(morphValue(pFlame1.getCamRoll(), pFlame2.getCamRoll(), fScl));
   res.setFocusZ(morphValue(pFlame1.getFocusZ(), pFlame2.getFocusZ(), fScl));
   res.setCamZoom(morphValue(pFlame1.getCamZoom(), pFlame2.getCamZoom(), fScl));
   res.setBGColorRed(morphColorValue(pFlame1.getBGColorRed(), pFlame2.getBGColorRed(), fScl));
   res.setBGColorGreen(
       morphColorValue(pFlame1.getBGColorGreen(), pFlame2.getBGColorGreen(), fScl));
   res.setBGColorBlue(morphColorValue(pFlame1.getBGColorBlue(), pFlame2.getBGColorBlue(), fScl));
   res.setBrightness(morphValue(pFlame1.getBrightness(), pFlame2.getBrightness(), fScl));
   res.setCentreX(morphValue(pFlame1.getCentreX(), pFlame2.getCentreX(), fScl));
   res.setCentreY(morphValue(pFlame1.getCentreY(), pFlame2.getCentreY(), fScl));
   res.setContrast(morphValue(pFlame1.getContrast(), pFlame2.getContrast(), fScl));
   res.setGamma(morphValue(pFlame1.getGamma(), pFlame2.getGamma(), fScl));
   res.setGammaThreshold(
       morphValue(pFlame1.getGammaThreshold(), pFlame2.getGammaThreshold(), fScl));
   res.setPixelsPerUnit(morphValue(pFlame1.getPixelsPerUnit(), pFlame2.getPixelsPerUnit(), fScl));
   res.setWidth(morphValue(pFlame1.getWidth(), pFlame2.getWidth(), fScl));
   res.setHeight(morphValue(pFlame1.getHeight(), pFlame2.getHeight(), fScl));
   res.setPreserveZ(morphValue(pFlame1.isPreserveZ(), pFlame2.isPreserveZ(), fScl));
   res.setSpatialFilterRadius(
       morphValue(pFlame1.getSpatialFilterRadius(), pFlame2.getSpatialFilterRadius(), fScl));
   res.setVibrancy(morphValue(pFlame1.getVibrancy(), pFlame2.getVibrancy(), fScl));
   res.setWhiteLevel(morphValue(pFlame1.getWhiteLevel(), pFlame2.getWhiteLevel(), fScl));
 }
  @Override
  public Flame prepareFlame(RandomFlameGeneratorState pState) {
    Flame flame = new Flame();
    Layer layer = flame.getFirstLayer();
    flame.setCamRoll(0);
    flame.setCamPitch(90.0 - Math.random() * 180.0);
    flame.setCamYaw(30.0 - Math.random() * 60.0);
    flame.setCamPerspective(Math.random() * 0.2);
    flame.setWidth(601);
    flame.setHeight(338);
    flame.setPixelsPerUnit(92.48366013);
    flame.setCamZoom(0.3 + Math.random() * 0.5);

    randomizeSolidRenderingSettings(flame);

    layer.getFinalXForms().clear();
    layer.getXForms().clear();

    // create transform 1
    {
      XForm xForm = new XForm();
      layer.getXForms().add(xForm);
      xForm.setWeight(0.5);
      xForm.setColor(Math.random());
      xForm.setColorSymmetry(1.0 - 2 * Math.random());
      xForm.setMaterial(0);
      xForm.setMaterialSpeed(0);

      xForm.setCoeff00(1); // a
      xForm.setCoeff10(0); // b
      xForm.setCoeff20(0); // e
      xForm.setCoeff01(0); // c
      xForm.setCoeff11(1); // d
      xForm.setCoeff21(0); // f

      xForm.setPostCoeff00(1);
      xForm.setPostCoeff10(0);
      xForm.setPostCoeff01(0);
      xForm.setPostCoeff11(1);
      xForm.setPostCoeff20(0);
      xForm.setPostCoeff21(0);

      if (Math.random() > 0.125) {
        xForm.setDrawMode(DrawMode.HIDDEN);
      }

      // variation 1
      xForm.addVariation(0.2 + Math.random(), getRandom3DShape());
      // set default edit plane
      flame.setEditPlane(
          Math.random() > 0.666 ? EditPlane.XY : Math.random() < 0.5 ? EditPlane.YZ : EditPlane.ZX);
      XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, false);
      XFormTransformService.rotate(xForm, 360.0 * Math.random(), false);
      XFormTransformService.localTranslate(
          xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), false);

      if (Math.random() > 0.5) {
        XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, true);
        XFormTransformService.rotate(xForm, 360.0 * Math.random(), true);
        XFormTransformService.localTranslate(
            xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), true);
      }
    }

    // create transform 2
    {
      XForm xForm = new XForm();
      layer.getXForms().add(xForm);
      xForm.setWeight(0.5);
      xForm.setColor(0);
      xForm.setColorSymmetry(0);
      xForm.setMaterial(0);
      xForm.setMaterialSpeed(0);

      xForm.setXYCoeff00(0.54625622); // a
      xForm.setXYCoeff10(0.26758811); // b
      xForm.setXYCoeff20(0); // e
      xForm.setXYCoeff01(-0.26758811); // c
      xForm.setXYCoeff11(0.54625622); // d
      xForm.setXYCoeff21(0); // f

      xForm.setXYPostCoeff00(1);
      xForm.setXYPostCoeff10(0);
      xForm.setXYPostCoeff01(0);
      xForm.setXYPostCoeff11(1);
      xForm.setXYPostCoeff20(0);
      xForm.setXYPostCoeff21(0);

      xForm.setYZCoeff00(0.46864442);
      xForm.setYZCoeff10(-0.17017929);
      xForm.setYZCoeff20(1.21536218);
      xForm.setYZCoeff01(0.17017929);
      xForm.setYZCoeff11(0.46864442);
      xForm.setYZCoeff21(-0.02558657);

      xForm.setYZPostCoeff00(1);
      xForm.setYZPostCoeff10(0);
      xForm.setYZPostCoeff01(0);
      xForm.setYZPostCoeff11(1);
      xForm.setYZPostCoeff20(0);
      xForm.setYZPostCoeff21(0);

      xForm.setZXCoeff00(0.81078767);
      xForm.setZXCoeff10(0.12035676);
      xForm.setZXCoeff20(0.21748586);
      xForm.setZXCoeff01(-0.12035676);
      xForm.setZXCoeff11(0.81078767);
      xForm.setZXCoeff21(-0.05117314);

      xForm.setZXPostCoeff00(1);
      xForm.setZXPostCoeff10(0);
      xForm.setZXPostCoeff01(0);
      xForm.setZXPostCoeff11(1);
      xForm.setZXPostCoeff20(0);
      xForm.setZXPostCoeff21(0);

      // variation 1
      xForm.addVariation(1, VariationFuncList.getVariationFuncInstance("linear3D", true));
      // set default edit plane
      flame.setEditPlane(EditPlane.XY);
      XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, false);
      XFormTransformService.rotate(xForm, 360.0 * Math.random(), false);
      XFormTransformService.localTranslate(
          xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), false);
      if (Math.random() > 0.666) {
        XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, true);
        XFormTransformService.rotate(xForm, 360.0 * Math.random(), true);
        XFormTransformService.localTranslate(
            xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), true);
      }
    }
    // create transform 3
    if (Math.random() > 0.666) {
      XForm xForm = new XForm();
      layer.getXForms().add(xForm);
      xForm.setWeight(0.5);
      xForm.setColor(0);
      xForm.setColorSymmetry(0);
      xForm.setMaterial(0);
      xForm.setMaterialSpeed(0);

      xForm.setXYCoeff00(0.54625622); // a
      xForm.setXYCoeff10(0.26758811); // b
      xForm.setXYCoeff20(0); // e
      xForm.setXYCoeff01(-0.26758811); // c
      xForm.setXYCoeff11(0.54625622); // d
      xForm.setXYCoeff21(0); // f

      xForm.setXYPostCoeff00(1);
      xForm.setXYPostCoeff10(0);
      xForm.setXYPostCoeff01(0);
      xForm.setXYPostCoeff11(1);
      xForm.setXYPostCoeff20(0);
      xForm.setXYPostCoeff21(0);

      xForm.setYZCoeff00(0.46864442);
      xForm.setYZCoeff10(-0.17017929);
      xForm.setYZCoeff20(1.21536218);
      xForm.setYZCoeff01(0.17017929);
      xForm.setYZCoeff11(0.46864442);
      xForm.setYZCoeff21(-0.02558657);

      xForm.setYZPostCoeff00(1);
      xForm.setYZPostCoeff10(0);
      xForm.setYZPostCoeff01(0);
      xForm.setYZPostCoeff11(1);
      xForm.setYZPostCoeff20(0);
      xForm.setYZPostCoeff21(0);

      xForm.setZXCoeff00(0.59207155);
      xForm.setZXCoeff10(-0.56684538);
      xForm.setZXCoeff20(1.31770847);
      xForm.setZXCoeff01(0.56684538);
      xForm.setZXCoeff11(0.59207155);
      xForm.setZXCoeff21(-0.84435688);

      xForm.setZXPostCoeff00(1);
      xForm.setZXPostCoeff10(0);
      xForm.setZXPostCoeff01(0);
      xForm.setZXPostCoeff11(1);
      xForm.setZXPostCoeff20(0);
      xForm.setZXPostCoeff21(0);

      // variation 1
      xForm.addVariation(1, VariationFuncList.getVariationFuncInstance("linear3D", true));
      // set default edit plane
      flame.setEditPlane(EditPlane.XY);
      XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, false);
      XFormTransformService.rotate(xForm, 360.0 * Math.random(), false);
      XFormTransformService.localTranslate(
          xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), false);
      if (Math.random() > 0.5) {
        XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, true);
        XFormTransformService.rotate(xForm, 360.0 * Math.random(), true);
        XFormTransformService.localTranslate(
            xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), true);
      }
    }

    // create final transform 1
    if (Math.random() > 0.42) {
      XForm xForm = new XForm();
      layer.getFinalXForms().add(xForm);
      xForm.setWeight(0);
      xForm.setColor(0);
      xForm.setColorSymmetry(0);
      xForm.setMaterial(0);
      xForm.setMaterialSpeed(0);

      xForm.setCoeff00(1); // a
      xForm.setCoeff10(0); // b
      xForm.setCoeff20(0); // e
      xForm.setCoeff01(0); // c
      xForm.setCoeff11(1); // d
      xForm.setCoeff21(0); // f

      xForm.setPostCoeff00(1);
      xForm.setPostCoeff10(0);
      xForm.setPostCoeff01(0);
      xForm.setPostCoeff11(1);
      xForm.setPostCoeff20(0);
      xForm.setPostCoeff21(0);

      // variation 1
      xForm.addVariation(0.75 + Math.random() * 0.25, getRandomVariation());
      // variation 2
      if (Math.random() > 0.5) {
        xForm.addVariation(
            0.25 + Math.random() * 0.25,
            VariationFuncList.getVariationFuncInstance("linear3D", true));
      }
      // set default edit plane
      flame.setEditPlane(EditPlane.XY);
      if (Math.random() > 0.5) {
        XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, false);
        XFormTransformService.rotate(xForm, 360.0 * Math.random(), false);
        XFormTransformService.localTranslate(
            xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), false);
      }
      if (Math.random() > 0.5) {
        XFormTransformService.scale(xForm, 1.25 - Math.random() * 0.5, true, true, true);
        XFormTransformService.rotate(xForm, 360.0 * Math.random(), true);
        XFormTransformService.localTranslate(
            xForm, 1.0 - 2.0 * Math.random(), 1.0 - 2.0 * Math.random(), true);
      }
    }

    return flame;
  }