import vtk.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class SmoothRender extends JPanel {

  static {
    // Load VTK MarchingCubes library, rest is loaded by vtkPanel
    System.loadLibrary("vtkPatentedJava");
  }

  private final String PREFIX = "/data/";

  /**
   * Constructor.
   */
  public SmoothRender() {
    // Setup VTK rendering panel
    vtkPanel renWin = new vtkPanel();

    vtkRenderer ren = renWin.GetRenderer();

    // Create actors for each segmented region

    vtkActor skullActor = createActor(PREFIX + "brainweb1_skull_smooth.vtk", 127, 0.5, 500);
    skullActor.GetProperty().SetOpacity(0.25);
    skullActor.GetProperty().SetColor(1, 1, 1);
    skullActor.GetProperty().SetDiffuse(0.75);
    skullActor.GetProperty().SetSpecular(0.75);
    ren.AddActor(skullActor);

    vtkActor brainActor = createActor(PREFIX + "brainweb1_both_matters.vtk", 127, 0.5, 500);
    brainActor.GetProperty().SetColor(0.9961, 0.75, 0.1);
    brainActor.GetProperty().SetSpecular(1);
    ren.AddActor(brainActor);

    vtkActor rightEyeActor = createActor(PREFIX + "brainweb1_right_eye.vtk", 127, 0.5, 500);
    rightEyeActor.GetProperty().SetColor(1, 1, 1);
    rightEyeActor.GetProperty().SetDiffuse(0.95);
    rightEyeActor.GetProperty().SetSpecular(0.1);
    ren.AddActor(rightEyeActor);

    vtkActor rightRetinaActor = createActor(PREFIX + "brainweb1_right_eye_lens.vtk", 127, 0.10, 100);
    rightRetinaActor.GetProperty().SetColor(0.1, 0.1, 0.1);
    rightRetinaActor.GetProperty().SetSpecular(1);
    ren.AddActor(rightRetinaActor);

    vtkActor leftEyeActor = createActor(PREFIX + "brainweb1_left_eye_smooth.vtk", 127, 0.5, 500);
    leftEyeActor.GetProperty().SetColor(1, 1, 1);
    leftEyeActor.GetProperty().SetDiffuse(0.95);
    leftEyeActor.GetProperty().SetSpecular(0.1);
    ren.AddActor(leftEyeActor);

    vtkActor leftRetinaActor = createActor(PREFIX + "brainweb1_left_eye_lens.vtk", 127, 0.10, 100);
    leftRetinaActor.GetProperty().SetColor(0.1, 0.1, 0.1);
    leftRetinaActor.GetProperty().SetSpecular(1);
    leftRetinaActor.GetProperty().SetSpecularPower(1);
    ren.AddActor(leftRetinaActor);

    // Place renWin in the center of this panel
    setLayout(new BorderLayout());
    add(renWin, BorderLayout.CENTER);
  }

  /**
   * Load region data from a file and create its rendering pipeline.
   */
  private vtkActor createActor(String fileName,
                               int threshold,
                               double targetReduction,
                               int smoothingIterations) {
    vtkStructuredPointsReader reader = new vtkStructuredPointsReader();
    reader.SetFileName(fileName);
    reader.Update();

    vtkMarchingCubes surfaceExtractor = new vtkMarchingCubes();
    surfaceExtractor.SetInput(reader.GetOutput());
    surfaceExtractor.SetValue(0, threshold);
    surfaceExtractor.ComputeNormalsOn();


    vtkDecimatePro deci = new vtkDecimatePro();
    deci.SetInput(surfaceExtractor.GetOutput());
    deci.SetTargetReduction(targetReduction);
    deci.PreserveTopologyOn();

    vtkSmoothPolyDataFilter smoother = new vtkSmoothPolyDataFilter();
    smoother.SetInput(deci.GetOutput());
    smoother.SetNumberOfIterations(smoothingIterations);

    vtkPolyDataNormals normals = new vtkPolyDataNormals();
    normals.SetInput(smoother.GetOutput());
    normals.FlipNormalsOn();

    vtkPolyDataMapper mapper = new vtkPolyDataMapper();
    mapper.SetInput(normals.GetOutput());
    mapper.ScalarVisibilityOff();

    vtkActor actor = new vtkActor();
    actor.SetMapper(mapper);

    return actor;
  }

  /**
   * 
   */
  public static void main(String[] args) {
    SmoothRender panel = new SmoothRender();

    JFrame frame = new JFrame("SmoothRender");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    frame.getContentPane().add("Center", panel);
    frame.pack();
    frame.setVisible(true);
  }
}