content: package edu.stanford.rsl.conrad.opencl.rendering;
  
  import java.awt.Dimension;
  import java.awt.GridLayout;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.nio.IntBuffer;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.Timer;
  import java.util.TimerTask;
  
  
  import javax.swing.JButton;
  import javax.swing.JLabel;
  import javax.swing.JPanel;
  import javax.swing.JSlider;
  import javax.swing.SwingUtilities;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.ChangeListener;
  
  import com.jogamp.opencl.CLImage3d;
  import com.jogamp.opencl.CLImageFormat;
  import com.jogamp.opencl.CLImageFormat.ChannelOrder;
  import com.jogamp.opencl.CLImageFormat.ChannelType;
  import com.jogamp.opencl.CLMemory.Mem;
  
  import edu.stanford.rsl.conrad.utils.ImageUtil;
  import ij.ImagePlus;
  import ij.process.ImageProcessor;
  
  public class OpenCLVolumeRenderer extends OpenCLTextureRendering {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 369749150640130620L;
  
  	private boolean multiFrameMode = false;
  	private ArrayList<CLImage3d<IntBuffer>> clImages;
  	private byte[][] volumes;
  	private int nFrames=1;
  	private int time = 0;
  
  	public OpenCLVolumeRenderer(byte[] volumeData, int sizeX, int sizeY,
  			int sizeZ, boolean stereoMode) {
  		super(volumeData, sizeX, sizeY, sizeZ, stereoMode);
  		/*transferFunc = new float[]
  				{ 
  				0.0f, 0.0f, 0.0f, 0.0f, 
  				1.0f, 1.0f, 1.0f, 1.0f, 
  				0.0f, 0.0f, 0.0f, 0.0f,
  				};
  */
  		volumes = new byte[1][volumeData.length];
  		volumes[0]=volumeData;
  		clImages = new ArrayList<CLImage3d<IntBuffer>>(1);
  		start();
  
  	}
  
  	private double [] minmax = null;
  
  	public OpenCLVolumeRenderer(ImagePlus image){
  		super (new byte[image.getWidth() * image.getHeight() * image.getStackSize() / image.getNFrames()], image.getWidth(), image.getHeight(), image.getStackSize() / image.getNFrames(), false);
  
  		transferFunc = new float[]
  				{ 
  				0.0f, 0.0f, 0.0f, 0.0f, 
  				1.0f, 1.0f, 1.0f, 1.0f, 
  				0.0f, 0.0f, 0.0f, 0.0f,
  				};
  		
  		minmax = ImageUtil.minAndMaxOfImageProcessor(image);
  		minmax[1] *= 1.05;
  		
  		if (image.getNFrames() == 1)
  			multiFrameMode = false;
  		else
  			multiFrameMode = true;
  
  
  		nFrames = image.getNFrames();
  		// Create the image array
  		clImages = new ArrayList<CLImage3d<IntBuffer>>(image.getNFrames());
  		// rewrite imagePlus container into nFrames single byte volumes
  		volumes = new byte [image.getNFrames()][volumeSize[2]*volumeSize[1]*volumeSize[0]];
  		for (int n = 0; n < image.getNFrames(); n++) {
  			for (int k = 0; k < volumeSize[2]; k++) {
  				ImageProcessor img = image.getStack().getProcessor((n*volumeSize[2])+k + 1);
  				for (int i = 0; i < image.getWidth(); i++){
  					for (int j = 0; j < image.getHeight(); j++){
  						setVoxel(volumes[n], i,j,k, img.getPixelValue(i, j));
  					}	
  				}
  			}
  		}
  		
  		initialized = false;
  		//System.out.println("init");
  		frame.setTitle("Volume: " + image.getTitle());	
  
  
  
  	}
  
  
  	public void setVoxel(byte [] h_volume, int i, int j, int k, double value){
  		h_volume[((((int)volumeSize[1] * k) + j) * (int)volumeSize[0]) + i] = (byte) (((value - minmax[0]) / (minmax[1] - minmax[0])) * 256);
  	}
  
  	/**
  	 * Entry point for this sample.
  	 * 
  	 * @param args not used
  	 */
  	public static void main(String args[])
  	{
  		startSample("Bucky.raw", 32, 32, 32, false);
  
  		// Other input files may be obtained from http://www.volvis.org
  		//startSample("mri_ventricles.raw", 256, 256, 124, false);
  		//startSample("backpack8.raw", 512, 512, 373, false);
  		//startSample("foot.raw", 256, 256, 256, false);
  	}
  
  	/**
  	 * Starts this sample with the data that is read from the file
  	 * with the given name. The data is assumed to have the 
  	 * specified dimensions.
  	 * 
  	 * @param fileName The name of the volume data file to load
  	 * @param sizeX The size of the data set in X direction
  	 * @param sizeY The size of the data set in Y direction
  	 * @param sizeZ The size of the data set in Z direction
  	 * @param stereoMode Whether stereo mode should be used
  	 */
  	private static void startSample(
  			String fileName, final int sizeX, final int sizeY, 
  			final int sizeZ, final boolean stereoMode)
  	{
  		// Try to read the specified file
  		byte data[] = null;
  		try
  		{
  			int size = sizeX * sizeY * sizeZ; 
  			FileInputStream fis = new FileInputStream(fileName);
  			data = new byte[size];
  			fis.read(data);
  			fis.close();
  		}
  		catch (IOException e)
  		{
  			System.err.println("Could not load input file");
  			e.printStackTrace();
  			return;
  		}
  
  		// Start the sample with the data that was read from the file
  		final byte volumeData[] = data;
  		SwingUtilities.invokeLater(new Runnable()
  		{
  			public void run()
  			{
  				new OpenCLVolumeRenderer(
  						volumeData, sizeX, sizeY, sizeZ, stereoMode);
  			}
  		});
  	}
  
  	/**
  	 * Stops the animator and calls System.exit() in a new Thread.
  	 * (System.exit() may not be called synchronously inside one 
  	 * of the JOGL callbacks)
  	 */
  	protected void runExit()
  	{
  		if (pbo != 0)
  		{
  			unload();
  			//gl.glDeleteBuffers(1, new int[]{ pbo }, 0);
  			pbo = 0;
  		}
  		new Thread(new Runnable()
  		{
  			public void run()
  			{
  				animatorL.stop();
  				if (animatorR != null)
  				{
  					animatorR.stop();
  				}
  
  				//System.exit(0);
  			}
  		}).start();
  	}
  
  	private Timer playTimer = null;
  	private long frameDuration = 37;
  
  	@Override
  	protected JPanel createControlPanel(){
  		JPanel controlPanel = super.createControlPanel();
  		if (multiFrameMode) {
  			JPanel panel = null;
  			JSlider slider = null;
  			// Time
  			panel = new JPanel(new GridLayout(1, 2));
  			panel.add(new JLabel("Time:"));
  			slider = new JSlider(0, nFrames-1, 0);
  			slider.addChangeListener(new ChangeListener()
  			{
  				public void stateChanged(ChangeEvent e)
  				{
  					JSlider source = (JSlider) e.getSource();
  					time = source.getValue();
  				}
  			});
  			slider.setPreferredSize(new Dimension(0, 0));
  			panel.add(slider);
  
  			controlPanel.add(panel);
  			JPanel buttons = new JPanel(new GridLayout(1,3));
  
  
  			JButton animateButton = new JButton("play");
  			animateButton.addActionListener(new ActionListener(){
  
  				public void actionPerformed(ActionEvent arg0) {
  					if (playTimer == null){
  						playTimer = new Timer();
  						playTimer.scheduleAtFixedRate(new TimerTask(){
  							@Override
  							public void run() {
  								time = (time +1) % nFrames;
  							}}, 0, frameDuration);
  					} else {
  						playTimer.cancel();
  						playTimer = null;
  					}
  
  				}
  			}
  					);
  			buttons.add(animateButton);
  			JButton button = new JButton("-");
  			button.addActionListener(new ActionListener(){
  				public void actionPerformed(ActionEvent arg0) {
  					frameDuration +=10;
  					if (frameDuration > 1000) frameDuration = 1000;
  					resetTimer();
  				}
  			}
  					);
  			buttons.add(button);
  			button = new JButton("+");
  			button.addActionListener(new ActionListener(){
  				public void actionPerformed(ActionEvent arg0) {
  					frameDuration -=10;
  					if (frameDuration < 10) frameDuration = 10;
  					resetTimer();
  				}
  			}
  					);
  			buttons.add(button);
  			controlPanel.add(buttons);
  		}
  		return controlPanel;
  	}
  
  	public void resetTimer(){
  		if (playTimer!=null){
  			playTimer.cancel();
  			playTimer = new Timer();
  			playTimer.scheduleAtFixedRate(new TimerTask(){
  				@Override
  				public void run() {
  					time = (time +1) % nFrames;
  				}}, 0, frameDuration);
  		}
  	}
  
  
  	@Override
  	protected void initVolumeBuffer(){
  
  		CLImageFormat format = new CLImageFormat(ChannelOrder.RGBA, ChannelType.UNORM_INT8);
  		for (int i = 0; i < nFrames; i++) {
  			hvolumeBuffer = glCtx.createIntBuffer(volumes[i].length, Mem.READ_ONLY);
  			for (int j = 0; j < h_volume.length; j++) {
  				hvolumeBuffer.getBuffer().put(j, (int)volumes[i][j]);
  			}
  			hvolumeBuffer.getBuffer().rewind();
  
  
  			clImages.add(glCtx.createImage3d(hvolumeBuffer.getBuffer(),
  					volumeSize[0], volumeSize[1], volumeSize[2],
  					format, Mem.READ_ONLY, Mem.ALLOCATE_BUFFER));
  			hvolumeBuffer.release();
  
  			try {
  				commandQueue.putWriteImage(clImages.get(i), true)
  				.finish();
  			} catch (Exception e) {
  				e.printStackTrace();
  				unload();
  			}
  		}
  		hvolumeBuffer = null;
  	}
  
  
  	@Override
  	protected void setKernelParameters(){
  		// Set up the execution parameters for the kernel:
  		// - One pointer for the output that is mapped to the PBO
  		// - Two ints for the width and height of the image to render
  		// - Four floats for the visualization parameters of the renderer
  		kernelFunction.rewind()
  		.putArg(d_output)
  		.putArg(width)
  		.putArg(height)
  		.putArg(density)
  		.putArg(brightness)
  		.putArg(transferOffset)
  		.putArg(transferScale)
  		.putArg(invViewMatrix)
  		.putArg(clImages.get(time))
  		.putArg(transferTex)
  		.rewind();
  	}
  	
  	
  	/**
  	 * release all CL related objects and free memory
  	 */
  	@Override
  	protected void unload(){
  		if (commandQueue != null)
  			commandQueue.release();
  		//release all buffers
  		if (clImages != null){
  			Iterator<CLImage3d<IntBuffer>> it = clImages.iterator();
  			while (it.hasNext()) {
  				it.next().release();
  			}
  		}
  		if (tex != null)
  			tex.release();
  		if (transferTex != null)
  			transferTex.release();
  		if (invViewMatrix != null)
  			invViewMatrix.release();
  		if (d_output != null)
  			d_output.release();
  		if (hvolumeBuffer != null)
  			hvolumeBuffer.release();
  		if (kernelFunction != null)
  			kernelFunction.release();
  		if (program != null)
  			program.release();
  		if (glCtx != null)
  			glCtx.release();
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Martin Berger
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  