package main;
import static org.jocl.CL.CL_MEM_READ_WRITE;
import static org.jocl.CL.CL_MEM_WRITE_ONLY;
import static org.jocl.CL.CL_TRUE;
import static org.jocl.CL.clCreateBuffer;
import static org.jocl.CL.clCreateCommandQueue;
import static org.jocl.CL.clCreateKernel;
import static org.jocl.CL.clEnqueueNDRangeKernel;
import static org.jocl.CL.clEnqueueReadBuffer;
import static org.jocl.CL.clEnqueueWriteBuffer;
import static org.jocl.CL.clSetKernelArg;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jocl.Pointer;
import org.jocl.Sizeof;
import org.jocl.cl_command_queue;
import org.jocl.cl_context;
import org.jocl.cl_device_id;
import org.jocl.cl_kernel;
import org.jocl.cl_mem;
import org.jocl.cl_program;
public class FractalCL {
private cl_context context;
private cl_program program;
private cl_command_queue commandQueue;
private cl_kernel kernel;
private cl_mem pixelMem;
private cl_mem colorMapMem;
private BufferedImage image;
private JComponent imageComponent;
private int colorMap[];
private String name;
private int width = 0;
private int height = 0;
private float x0 = -2f;
private float y0 = -2.0f;
private float x1 = 2.0f;
private float y1 = 2.0f;
private float cr = 0.0f; // real component of C (this is a parameter of every Julia set function)
private float ci = 0.0f; // imaginary component of C
public FractalCL(cl_context context, cl_program program,
cl_device_id device, String kernelName, String fractalName,
int[] colorMap, int width, int height, float cr, float ci,
JFrame frame) {
this.context = context;
this.program = program;
this.colorMap = colorMap;
this.width = width;
this.height = height;
this.name = fractalName;
this.cr = cr;
this.ci = ci;
// Create the image and the component that will paint the image
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
imageComponent = new JPanel() {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
};
if (fractalName.equals("Julia Set")) {
String message = fractalName + ": C = " + this.cr;
if (this.ci > 0.0f) {
message += " + ";
}
message += this.ci + "i";
imageComponent.setToolTipText(message);
} else {
imageComponent.setToolTipText(fractalName);
}
initInteraction();
// Create a command-queue for the selected device
commandQueue = clCreateCommandQueue(context, device, 0, null);
kernel = clCreateKernel(this.program, kernelName, null);
pixelMem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, width * height
* Sizeof.cl_uint, null, null);
colorMapMem = clCreateBuffer(context, CL_MEM_READ_WRITE,
colorMap.length * Sizeof.cl_uint, null, null);
clEnqueueWriteBuffer(commandQueue, colorMapMem, true, 0,
colorMap.length * Sizeof.cl_uint, Pointer.to(colorMap), 0,
null, null);
imageComponent.setPreferredSize(new Dimension(width, height));
updateImage();
frame.add(imageComponent);
}
public void setC(float cr, float ci) {
this.cr = cr;
this.ci = ci;
x0 = -2.0f;
x1 = 2.0f;
y0 = -2.0f;
y1 = 2.0f;
if (this.name.equals("Julia Set"))
{
String message = this.name + ": C = " + this.cr;
if (this.ci > 0.0f)
{
message += " + ";
}
message += this.ci + "i";
imageComponent.setToolTipText(message);
}
updateImage();
}
private void initInteraction() {
final Point previousPoint = new Point();
imageComponent.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
int dx = previousPoint.x - e.getX();
int dy = previousPoint.y - e.getY();
float wdx = x1 - x0;
float wdy = y1 - y0;
x0 += (dx / 150.0f) * wdx;
x1 += (dx / 150.0f) * wdx;
y0 += (dy / 150.0f) * wdy;
y1 += (dy / 150.0f) * wdy;
previousPoint.setLocation(e.getX(), e.getY());
updateImage();
}
@Override
public void mouseMoved(MouseEvent e) {
previousPoint.setLocation(e.getX(), e.getY());
}
});
imageComponent.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
}
});
imageComponent.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
float dx = x1 - x0;
float dy = y1 - y0;
float delta = -1.0f * e.getWheelRotation() / 20.0f;
x0 += delta * dx;
x1 -= delta * dx;
y0 += delta * dy;
y1 -= delta * dy;
updateImage();
}
});
}
/**
* Execute the kernel function and read the resulting pixel data into the
* BufferedImage
*/
private void updateImage() {
// Set work size and execute the kernel
long globalWorkSize[] = new long[2];
globalWorkSize[0] = width;
globalWorkSize[1] = height;
int maxIterations = 125;
clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(pixelMem));
clSetKernelArg(kernel, 1, Sizeof.cl_uint, Pointer.to(new int[] { width }));
clSetKernelArg(kernel, 2, Sizeof.cl_uint, Pointer.to(new int[] { height }));
clSetKernelArg(kernel, 3, Sizeof.cl_float, Pointer.to(new float[] { x0 }));
clSetKernelArg(kernel, 4, Sizeof.cl_float, Pointer.to(new float[] { y0 }));
clSetKernelArg(kernel, 5, Sizeof.cl_float, Pointer.to(new float[] { x1 }));
clSetKernelArg(kernel, 6, Sizeof.cl_float, Pointer.to(new float[] { y1 }));
clSetKernelArg(kernel, 7, Sizeof.cl_int, Pointer.to(new int[] { maxIterations }));
clSetKernelArg(kernel, 8, Sizeof.cl_mem, Pointer.to(colorMapMem));
clSetKernelArg(kernel, 9, Sizeof.cl_int, Pointer.to(new int[] { colorMap.length }));
clSetKernelArg(kernel, 10, Sizeof.cl_float, Pointer.to(new float[] { cr }));
clSetKernelArg(kernel, 11, Sizeof.cl_float, Pointer.to(new float[] { ci }));
clEnqueueNDRangeKernel(commandQueue, kernel, 2, null, globalWorkSize,
null, 0, null, null);
// Read the pixel data into the BufferedImage
DataBufferInt dataBuffer = (DataBufferInt) image.getRaster()
.getDataBuffer();
int data[] = dataBuffer.getData();
clEnqueueReadBuffer(commandQueue, pixelMem, CL_TRUE, 0, Sizeof.cl_int * height * width, Pointer.to(data), 0, null, null);
imageComponent.repaint();
}
}