Package org.jwildfire.create.tina.render

Source Code of org.jwildfire.create.tina.render.DefaultRenderIterationState

package org.jwildfire.create.tina.render;

import static org.jwildfire.base.mathlib.MathLib.EPSILON;
import static org.jwildfire.base.mathlib.MathLib.M_2PI;
import static org.jwildfire.base.mathlib.MathLib.M_PI;
import static org.jwildfire.base.mathlib.MathLib.cos;
import static org.jwildfire.base.mathlib.MathLib.exp;
import static org.jwildfire.base.mathlib.MathLib.fabs;
import static org.jwildfire.base.mathlib.MathLib.log;
import static org.jwildfire.base.mathlib.MathLib.sin;
import static org.jwildfire.base.mathlib.MathLib.sqrt;

import java.util.ArrayList;
import java.util.List;

import org.jwildfire.create.tina.base.Constants;
import org.jwildfire.create.tina.base.DrawMode;
import org.jwildfire.create.tina.base.Flame;
import org.jwildfire.create.tina.base.Layer;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.base.XYZPoint;
import org.jwildfire.create.tina.base.XYZProjectedPoint;
import org.jwildfire.create.tina.base.raster.AbstractRasterPoint;
import org.jwildfire.create.tina.palette.RGBPalette;
import org.jwildfire.create.tina.palette.RenderColor;
import org.jwildfire.create.tina.random.AbstractRandomGenerator;
import org.jwildfire.create.tina.variation.FlameTransformationContext;

public class DefaultRenderIterationState extends RenderIterationState {

  private static final long serialVersionUID = 2L;

  protected XYZPoint affineT;
  protected XYZPoint varT;
  protected XYZPoint p;
  protected XYZPoint q;
  protected XForm xf;
  protected final XYZProjectedPoint prj = new XYZProjectedPoint();
  protected PointProjector projector;

  public DefaultRenderIterationState(AbstractRenderThread pRenderThread, FlameRenderer pRenderer, RenderPacket pPacket, Layer pLayer, FlameTransformationContext pCtx, AbstractRandomGenerator pRandGen) {
    super(pRenderThread, pRenderer, pPacket, pLayer, pCtx, pRandGen);
    projector = new DefaultPointProjector();
    Flame flame = pPacket.getFlame();
    switch (flame.getPostSymmetryType()) {
      case POINT: {
        if (flame.getPostSymmetryOrder() > 1) {
          int order = flame.getPostSymmetryOrder() <= 64 ? flame.getPostSymmetryOrder() : 64;
          projector = new PointSymmetryProjector(projector, order, flame.getPostSymmetryCentreX(), flame.getPostSymmetryCentreY());
        }
        break;
      }
      case X_AXIS:
        projector = new XAxisSymmetryProjector(projector, flame.getPostSymmetryDistance(), flame.getPostSymmetryCentreX(), flame.getPostSymmetryCentreY(), flame.getPostSymmetryRotation());
        break;
      case Y_AXIS:
        projector = new YAxisSymmetryProjector(projector, flame.getPostSymmetryDistance(), flame.getPostSymmetryCentreX(), flame.getPostSymmetryCentreY(), flame.getPostSymmetryRotation());
        break;
    }
  }

  public void init() {
  }

  public void preFuseIter() {
    affineT = new XYZPoint(); // affine part of the transformation
    varT = new XYZPoint(); // complete transformation
    p = new XYZPoint();
    q = new XYZPoint();
    p.x = 2.0 * randGen.random() - 1.0;
    p.y = 2.0 * randGen.random() - 1.0;
    p.z = 0.0;
    p.color = randGen.random();
    p.modGamma = 0.0;
    p.modContrast = 0.0;
    p.modSaturation = 0.0;

    xf = layer.getXForms().get(0);
    transformPoint();
    for (int i = 0; i <= Constants.INITIAL_ITERATIONS; i++) {
      xf = xf.getNextAppliedXFormTable()[randGen.random(Constants.NEXT_APPLIED_XFORM_TABLE_SIZE)];
      if (xf == null) {
        xf = layer.getXForms().get(0);
        return;
      }
      transformPoint();
    }
  }

  public void validateState() {
    if (Double.isInfinite(p.x) || Double.isInfinite(p.y) || Double.isInfinite(p.z) || Double.isNaN(p.x) || Double.isNaN(p.y) || Double.isNaN(p.z) || xf == null) {
      preFuseIter();
    }
  }

  public void iterateNext() {
    int nextXForm = randGen.random(Constants.NEXT_APPLIED_XFORM_TABLE_SIZE);
    if (xf == null) {
      return;
    }
    xf = xf.getNextAppliedXFormTable()[nextXForm];
    if (xf == null) {
      return;
    }
    transformPoint();
    if (xf.getDrawMode() == DrawMode.HIDDEN)
      return;
    else if ((xf.getDrawMode() == DrawMode.OPAQUE) && (randGen.random() > xf.getOpacity()))
      return;
    List<XForm> finalXForms = layer.getFinalXForms();
    if (finalXForms.size() > 0) {
      applyFinalTransforms(finalXForms);
    }
    else {
      applyEmptyFinalTransform();
    }
    projector.projectPoint(q);
  }

  public void iterateNext(List<RenderSlice> pSlices, double pThicknessMod, int pTicknessSamples) {
    int nextXForm = randGen.random(Constants.NEXT_APPLIED_XFORM_TABLE_SIZE);
    xf = xf.getNextAppliedXFormTable()[nextXForm];
    if (xf == null) {
      return;
    }
    transformPoint();
    if (xf.getDrawMode() == DrawMode.HIDDEN)
      return;
    else if ((xf.getDrawMode() == DrawMode.OPAQUE) && (randGen.random() > xf.getOpacity()))
      return;
    List<XForm> finalXForms = layer.getFinalXForms();
    if (finalXForms.size() > 0) {
      applyFinalTransforms(finalXForms);
    }
    else {
      applyEmptyFinalTransform();
    }

    if (pThicknessMod > EPSILON && pTicknessSamples > 0) {
      XYZPoint w = new XYZPoint();
      w.assign(q);
      try {
        for (int i = 0; i < pTicknessSamples; i++) {
          addNoise(w, q, pThicknessMod);
          List<AbstractRasterPoint[][]> sliceRasters = collectSliceRasters(q, pSlices);
          for (AbstractRasterPoint[][] sliceRaster : sliceRasters) {
            raster = sliceRaster;
            projector.projectPoint(q);
          }
        }
      }
      finally {
        q.assign(w);
      }
    }
    else {
      if (setupSliceRaster(q, pSlices)) {
        projector.projectPoint(q);
      }
    }
  }

  private void addNoise(XYZPoint pSrc, XYZPoint pDst, double pRadius) {
    double angle = randGen.random() * 2 * M_PI;
    double sina = sin(angle);
    double cosa = cos(angle);
    angle = randGen.random() * M_PI;
    double sinb = sin(angle);
    double cosb = cos(angle);
    pDst.x = pSrc.x + pRadius * sinb * cosa;
    pDst.y = pSrc.y + pRadius * sinb * sina;
    pDst.z = pSrc.z + pRadius * cosb;
  }

  private boolean setupSliceRaster(XYZPoint pPoint, List<RenderSlice> pSlices) {
    int sliceIdx = getSliceIndex(pPoint, pSlices, 0);
    if (sliceIdx >= 0) {
      raster = pSlices.get(sliceIdx).getRaster();
      return true;
    }
    else {
      raster = null;
      return false;
    }
  }

  private List<AbstractRasterPoint[][]> collectSliceRasters(XYZPoint pPoint, List<RenderSlice> pSlices) {
    List<AbstractRasterPoint[][]> res = new ArrayList<AbstractRasterPoint[][]>();
    int sliceIdx = -1;
    while (true) {
      sliceIdx = getSliceIndex(pPoint, pSlices, sliceIdx + 1);
      if (sliceIdx >= 0) {
        res.add(pSlices.get(sliceIdx).getRaster());
      }
      else {
        break;
      }
    }
    return res;
  }

  private int getSliceIndex(XYZPoint pPoint, List<RenderSlice> pSlices, int pStartIndex) {
    double value = pPoint.z;
    for (int i = pStartIndex; i < pSlices.size(); i++) {
      RenderSlice slice = pSlices.get(i);
      if (value >= slice.getZmin() && value < slice.getZmax()) {
        return i;
      }
    }
    return -1;
  }

  protected void applyEmptyFinalTransform() {
    q.assign(p);
  }

  protected void applyFinalTransforms(List<XForm> finalXForms) {
    finalXForms.get(0).transformPoint(ctx, affineT, varT, p, q);
    for (int i = 1; i < finalXForms.size(); i++) {
      finalXForms.get(i).transformPoint(ctx, affineT, varT, q, q);
    }
  }

  protected void transformPoint() {
    xf.transformPoint(ctx, affineT, varT, p, p);
  }

  protected double plotRed, plotGreen, plotBlue, plotContribution;

  protected void plotPoint(int xIdx, int yIdx, double intensity) {
    AbstractRasterPoint rp = raster[yIdx][xIdx];
    if (p.rgbColor) {
      plotRed = p.redColor;
      plotGreen = p.greenColor;
      plotBlue = p.blueColor;
    }
    else if (q.rgbColor) {
      plotRed = q.redColor;
      plotGreen = q.greenColor;
      plotBlue = q.blueColor;
    }
    else {
      int colorIdx = (int) (p.color * paletteIdxScl + 0.5);
      if (colorIdx < 0)
        colorIdx = 0;
      else if (colorIdx > RGBPalette.PALETTE_SIZE)
        colorIdx = RGBPalette.PALETTE_SIZE;
      RenderColor color = colorMap[colorIdx];
      plotRed = color.red;
      plotGreen = color.green;
      plotBlue = color.blue;
    }
    transformPlotColor(p);
    rp.setRed(rp.getRed() + plotRed * intensity);
    rp.setGreen(rp.getGreen() + plotGreen * intensity);
    rp.setBlue(rp.getBlue() + plotBlue * intensity);

    rp.incCount();
    if (observers != null && observers.size() > 0) {
      for (IterationObserver observer : observers) {
        observer.notifyIterationFinished(renderThread, xIdx, yIdx);
      }
    }
  }

  protected void transformPlotColor(XYZPoint p) {
    if (fabs(p.modGamma) > EPSILON) {
      double gamma = 4.2 / (4.2 - p.modGamma);
      double alpha = plotRed * 0.299 + plotGreen * 0.588 + plotBlue * 0.113;
      if (alpha > EPSILON) {
        double modAlpha = Math.pow(alpha, gamma);
        plotRed *= modAlpha / alpha;
        plotGreen *= modAlpha / alpha;
        plotBlue *= modAlpha / alpha;
      }
    }
    if (fabs(p.modContrast) > EPSILON) {
      double gamma = 1.2 / (1.2 - p.modContrast * 0.5);
      plotRed = (plotRed - 127.5) * gamma + 127.5;
      plotGreen = (plotGreen - 127.5) * gamma + 127.5;
      plotBlue = (plotBlue - 127.5) * gamma + 127.5;
    }
    if (fabs(p.modSaturation) > EPSILON) {
      double avg = plotRed * 0.299 + plotGreen * 0.588 + plotBlue * 0.113;
      plotRed += (plotRed - avg) * p.modSaturation;
      plotGreen += (plotGreen - avg) * p.modSaturation;
      plotBlue += (plotBlue - avg) * p.modSaturation;
    }
    if (p.withAlpha) {
      plotRed *= p.alpha;
      plotGreen *= p.alpha;
      plotBlue *= p.alpha;
    }
  }

  public interface PointProjector {
    void projectPoint(XYZPoint q);
  }

  public abstract class AxisSymmetryProjector implements PointProjector {
    protected final PointProjector parent;
    protected final double distance;
    protected final double centreX;
    protected final double centreY;
    protected final double rotation;
    protected final XYZPoint a;
    protected final XYZPoint b;
    protected final double sina, cosa;
    protected final double halve_dist;
    protected final boolean doRotate;

    public AxisSymmetryProjector(PointProjector pParent, double pDistance, double pCentreX, double pCentreY, double pRotation) {
      parent = pParent;
      distance = pDistance;
      centreX = pCentreX;
      centreY = pCentreY;
      rotation = pRotation;
      a = new XYZPoint();
      b = new XYZPoint();

      double a = rotation * M_2PI / 180.0 / 2.0;
      doRotate = fabs(a) > EPSILON;

      sina = sin(a);
      cosa = cos(a);
      halve_dist = distance / 2.0;
    }
  }

  public class XAxisSymmetryProjector extends AxisSymmetryProjector implements PointProjector {

    public XAxisSymmetryProjector(PointProjector pParent, double pDistance, double pCentreX, double pCentreY, double pRotation) {
      super(pParent, pDistance, pCentreX, pCentreY, pRotation);
    }

    @Override
    public void projectPoint(XYZPoint q) {
      if (q.doHide)
        return;
      a.assign(q);
      b.assign(q);
      double dx, dy;
      dx = q.x - centreX;
      a.x = centreX + dx + halve_dist;
      b.x = centreX - dx - halve_dist;
      if (doRotate) {
        dx = a.x - centreX;
        dy = a.y - centreY;
        a.x = centreX + dx * cosa + dy * sina;
        a.y = centreY + dy * cosa - dx * sina;

        dx = b.x - centreX;
        dy = b.y - centreY;
        b.x = centreX + dx * cosa - dy * sina;
        b.y = centreY + dy * cosa + dx * sina;
      }

      parent.projectPoint(a);
      parent.projectPoint(b);
    }

  }

  public class YAxisSymmetryProjector extends AxisSymmetryProjector implements PointProjector {

    public YAxisSymmetryProjector(PointProjector pParent, double pDistance, double pCentreX, double pCentreY, double pRotation) {
      super(pParent, pDistance, pCentreX, pCentreY, pRotation);
    }

    @Override
    public void projectPoint(XYZPoint q) {
      if (q.doHide)
        return;
      a.assign(q);
      b.assign(q);
      double dx, dy;
      dy = q.y - centreY;
      a.y = centreY + dy + halve_dist;
      b.y = centreY - dy - halve_dist;
      if (doRotate) {
        dx = a.x - centreX;
        dy = a.y - centreY;
        a.x = centreX + dx * cosa + dy * sina;
        a.y = centreY + dy * cosa - dx * sina;

        dx = b.x - centreX;
        dy = b.y - centreY;
        b.x = centreX + dx * cosa - dy * sina;
        b.y = centreY + dy * cosa + dx * sina;
      }

      parent.projectPoint(a);
      parent.projectPoint(b);
    }

  }

  public class PointSymmetryProjector implements PointProjector {
    private final PointProjector parent;
    private final double centreX, centreY;
    private final int order;
    private final double sina[], cosa[];
    private final XYZPoint ps;

    public PointSymmetryProjector(PointProjector pParent, int pOrder, double pCentreX, double pCentreY) {
      parent = pParent;
      order = pOrder >= 1 ? pOrder : 1;
      centreX = pCentreX;
      centreY = pCentreY;
      ps = new XYZPoint();
      sina = new double[order];
      cosa = new double[order];
      double da = M_2PI / (double) order;
      double angle = 0.0;
      for (int i = 0; i < order; i++) {
        sina[i] = sin(angle);
        cosa[i] = cos(angle);
        angle += da;
      }
    }

    @Override
    public void projectPoint(XYZPoint q) {
      if (q.doHide)
        return;
      double dx = q.x - centreX;
      double dy = q.y - centreY;
      parent.projectPoint(q);
      for (int i = 0; i < order; i++) {
        ps.assign(q);
        ps.x = centreX + dx * cosa[i] + dy * sina[i];
        ps.y = centreY + dy * cosa[i] - dx * sina[i];
        parent.projectPoint(ps);
      }
    }
  }

  public class DefaultPointProjector implements PointProjector {

    @Override
    public void projectPoint(XYZPoint q) {
      if (q.doHide || !view.project(q, prj))
        return;
      int xIdx, yIdx;
      if ((flame.getAntialiasAmount() > EPSILON) && (flame.getAntialiasRadius() > EPSILON) && (randGen.random() > 1.0 - flame.getAntialiasAmount())) {
        double dr = exp(flame.getAntialiasRadius() * sqrt(-log(randGen.random()))) - 1.0;
        double da = randGen.random() * 2.0 * M_PI;
        xIdx = (int) (view.bws * prj.x + dr * cos(da) + 0.5);
        if (xIdx < 0 || xIdx >= renderer.rasterWidth)
          return;
        yIdx = (int) (view.bhs * prj.y + dr * sin(da) + 0.5);
        if (yIdx < 0 || yIdx >= renderer.rasterHeight)
          return;
      }
      else {
        xIdx = (int) (view.bws * prj.x + 0.5);
        if (xIdx < 0 || xIdx >= renderer.rasterWidth)
          return;
        yIdx = (int) (view.bhs * prj.y + 0.5);
        if (yIdx < 0 || yIdx >= renderer.rasterHeight)
          return;
      }
      double intensity = prj.intensity * layer.getWeight();
      plotPoint(xIdx, yIdx, intensity);
    }

  }
}
TOP

Related Classes of org.jwildfire.create.tina.render.DefaultRenderIterationState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.