content: package edu.stanford.rsl.conrad.opencl.shapes;
  
  import java.nio.FloatBuffer;
  import java.util.ArrayList;
  
  import com.jogamp.opencl.CLBuffer;
  import com.jogamp.opencl.CLCommandQueue;
  import com.jogamp.opencl.CLDevice;
  import com.jogamp.opencl.CLImage2d;
  import com.jogamp.opencl.CLImageFormat;
  import com.jogamp.opencl.CLKernel;
  import com.jogamp.opencl.CLMemory;
  import com.jogamp.opencl.CLMemory.Mem;
  
  
  
  import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND;
  import edu.stanford.rsl.conrad.opencl.OpenCLUtil;
  
  public class OpenCLUniformTextureBSpline extends OpenCLUniformBSpline {
  
  	CLImage2d<FloatBuffer> texture;
  	
  	public OpenCLUniformTextureBSpline(ArrayList<PointND> controlPoints,
  			double[] uVector, CLDevice device) {
  		super(controlPoints, uVector, device);
  	}
  
  	protected void handleControlPoints(ArrayList<PointND> controlPoints){
  		this.controlPoints = context.createFloatBuffer(controlPoints.size()*4, Mem.READ_ONLY);
  		FloatBuffer buffer= this.controlPoints.getBuffer();
  		for(int i=0;i<controlPoints.size();i++) {
  			buffer.put((float)controlPoints.get(i).get(0));
  			buffer.put((float)controlPoints.get(i).get(1));
  			buffer.put((float)controlPoints.get(i).get(2));
  			buffer.put(0f);
  		}
  		buffer.rewind();
  		texture = context.createImage2d(buffer, controlPoints.size(), 1, new CLImageFormat(CLImageFormat.ChannelOrder.RGBA, CLImageFormat.ChannelType.FLOAT), CLMemory.Mem.READ_ONLY);
  		device.createCommandQueue().putWriteImage(texture, true);
  	}
  	
  	/**
  	 * Example how to read a texture at float coordinates. Note that the pixel center is at (x.5, y.5) to get the exact value.
  	 * @param outputBuffer
  	 */
  	public void readControlPointsFromTextureInterpolate(CLBuffer<FloatBuffer> outputBuffer){
  		int elementCount = getControlPoints().size(); 
  		int localWorkSize = Math.min(device.getMaxWorkGroupSize(), 256);  // Local work size dimensions
  		int globalWorkSize = OpenCLUtil.roundUp(localWorkSize, elementCount);   // rounded up to the nearest multiple of the localWorkSize
  		
  		CLKernel kernel = OpenCLUtil.getProgramInstance().createCLKernel("readTextureInterp");
  		kernel.putArg(texture)
  		.putArg(outputBuffer)
  		.putArg(elementCount);
  
  		CLCommandQueue clc = device.createCommandQueue();
  		clc.put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize).finish();
  		kernel.release();
  		clc.release();
  	}
  	
  	/**
  	 * Example how to read a texture at integer coordinates. Note that the pixel center is at (x.0, y.0) to get the exact value.
  	 * @param outputBuffer
  	 */
  	public void readControlPointsFromTexture(CLBuffer<FloatBuffer> outputBuffer){
  		int elementCount = getControlPoints().size(); 
  		int localWorkSize = Math.min(device.getMaxWorkGroupSize(), 256);  // Local work size dimensions
  		int globalWorkSize = OpenCLUtil.roundUp(localWorkSize, elementCount);   // rounded up to the nearest multiple of the localWorkSize
  		
  		CLKernel kernel = OpenCLUtil.getProgramInstance().createCLKernel("readTexture");
  		kernel.putArg(texture)
  		.putArg(outputBuffer)
  		.putArg(elementCount);
  
  		CLCommandQueue clc = device.createCommandQueue();
  		clc.put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize).finish();
  		kernel.release();
  		clc.release();
  	}
  	
  	
  	public void evaluate(CLBuffer<FloatBuffer> samplingPoints, CLBuffer<FloatBuffer> outputBuffer){
  		int elementCount = samplingPoints.getBuffer().capacity();               // Length of arrays to process
  		int localWorkSize = Math.min(device.getMaxWorkGroupSize(), 256);  		// Local work size dimensions
  		int globalWorkSize = OpenCLUtil.roundUp(localWorkSize, elementCount);   // rounded up to the nearest multiple of the localWorkSize
  		
  		CLKernel kernel = OpenCLUtil.getProgramInstance().createCLKernel("evalTextureInterp");
  		kernel.putArgs(texture, samplingPoints, outputBuffer)
  		.putArg(getKnots().length)
  		.putArg(getControlPoints().size())
  		.putArg(elementCount);
  
  		CLCommandQueue clc = device.createCommandQueue();
  		clc.put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize).finish();
  		kernel.release();
  		clc.release();
  	}
  	
  	public void evaluateNoInterp(CLBuffer<FloatBuffer> samplingPoints, CLBuffer<FloatBuffer> outputBuffer){
  		int elementCount = samplingPoints.getBuffer().capacity();                                  // Length of arrays to process
  		int localWorkSize = Math.min(device.getMaxWorkGroupSize(), 256);  // Local work size dimensions
  		int globalWorkSize = OpenCLUtil.roundUp(localWorkSize, elementCount);   // rounded up to the nearest multiple of the localWorkSize
  		
  		CLKernel kernel = OpenCLUtil.getProgramInstance().createCLKernel("evalTexture");
  		kernel.putArg(texture)
  		.putArgs(samplingPoints, outputBuffer)
  		.putArg(getKnots().length)
  		.putArg(getControlPoints().size())
  		.putArg(elementCount);
  		
  
  		CLCommandQueue clc = device.createCommandQueue();
  		clc.put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize).finish();
  		kernel.release();
  		clc.release();
  	}
  	
  	
  	private static final long serialVersionUID = -3769875288043610795L;
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */