package mandelbrot;

import easyplot.color.Colorizer;
import easyplot.color.LinearGradientColorizer;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.nio.FloatBuffer;
import vecpy.VecPy;

public class Main {

   public static final int max = 100;
   public static final int w = 801;
   public static final int h = 601;
   public static final int N = w * h;
   public static final float w_m1 = w - 1, h_m1 = h - 1;
   public static float dx = 0f, dy = 0, sx = 4, sy = 3;
   private static double time;
   private static Colorizer color;

   public static void main(String[] args) throws Exception {
      Color[] colors = new Color[]{
         Color.black,
         new Color(128, 0, 255),
         Color.black,
         new Color(255, 128, 0),
         Color.black,
         new Color(0, 255, 128),
         Color.black,
         new Color(0, 128, 255),
         Color.black,
         new Color(128, 255, 0),
         Color.black,
         new Color(255, 0, 128),
         Color.black
      };
      color = new LinearGradientColorizer(LinearGradientColorizer.getUniformStops(colors.length), colors);
      System.load("/home/undefined/NetBeansProjects/VecPy_Mandelbrot/VecPy_mandelbrot.so");
      FloatBuffer row = VecPy.getFloatBuffer(N);
      FloatBuffer col = VecPy.getFloatBuffer(N);
      FloatBuffer count = VecPy.getFloatBuffer(N);
      for (int r = 0; r < h; r++) {
         for (int c = 0; c < w; c++) {
            row.put(r);
            col.put(c);
         }
      }
      GraphicsDevice screen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
      DisplayMode newDisplayMode = null;
      DisplayMode oldDisplayMode = screen.getDisplayMode();
      for (DisplayMode dm : screen.getDisplayModes()) {
         if (dm.getWidth() == w && dm.getHeight() == h && dm.getRefreshRate() == 60) {
            newDisplayMode = dm;
            break;
         }
      }
      Window window = new Window(newDisplayMode != null);
      window.setVisible(true);
      try {
         if (newDisplayMode != null) {
            screen.setFullScreenWindow(window);
            screen.setDisplayMode(newDisplayMode);
         }
         double fps = 0;
         long lastUpdate = System.currentTimeMillis() - 16;
         while (true) {
            row.rewind();
            col.rewind();
            count.rewind();
            float left = dx - sx / 2f;
            float right = left + sx;
            float bottom = dy - sy / 2f;
            float top = bottom + sy;
            long start = System.nanoTime();
            boolean result = VecPy.mandelbrot(row, col, count, max, w_m1, h_m1, left, right, top, bottom);
            long end = System.nanoTime();
            if (!result) {
               throw new Exception("kernel failed");
            }
            for (int r = 0; r < h; r++) {
               for (int c = 0; c < w; c++) {
                  window.display.buffer.setRGB(c, r, getRGB(count.get() / (double) max));
               }
            }
            long thisUpdate = System.currentTimeMillis();
            fps = fps * 0.9 + (1000.0 / (thisUpdate - lastUpdate)) * 0.1;
            double delta = (thisUpdate - lastUpdate) / 1000.0;
            time += delta;
            cr += Math.sin(time * 3) * .0003;
            ci += Math.cos(time * 1) * .0001;
            lastUpdate = thisUpdate;
            Graphics g = window.display.buffer.getGraphics();
            g.setColor(Color.green);
            String timer = String.format("%.1fms", (end - start) / 1e6d);
            g.drawString(timer, 5, 15);
            window.display.repaint();
//          Thread.sleep(10);
         }
      } finally {
         if (newDisplayMode != null) {
            screen.setDisplayMode(oldDisplayMode);
            screen.setFullScreenWindow(null);
         }
      }
   }

   private static final double LOG2 = Math.log(2);

   private static boolean mandelbrot(FloatBuffer row_, FloatBuffer col_, FloatBuffer count_, float max, float w_m1, float h_m1, float left, float right, float top, float bottom) {
      for (int index = 0; index < N; index++) {
         float row = row_.get();
         float col = col_.get();
         float x0 = left + col * (right - left) / w_m1;
         float y0 = bottom + (h_m1 - row) * (top - bottom) / h_m1;
         float x = 0, y = 0;
         float count = 0;
         float xx = x * x;
         float yy = y * y;
         //Standard escape time
         while (count < max && xx + yy < 16) {
            float temp = xx - yy + x0;
            y = 2 * x * y + y0;
            x = temp;
            xx = x * x;
            yy = y * y;
            ++count;
         }
         //Smooth shading
         if (count < max) {
            count += 1 - Math.log(Math.log(xx + yy) / LOG2 / 2.0) / LOG2;
         }
         count_.put(count);
      }
      count_.rewind();
      return true;
   }

   private static int getRGB(double d) {
      Color c = color.getColor((time * .02 + d) % 1);
      return c.getRGB();
   }
}

Main.java

package mandelbrot;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Window extends JFrame {

   public Display display;

   public Window(boolean fullscreen) throws HeadlessException {
      super("VecPy Demo");
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      setUndecorated(fullscreen);
      setResizable(false);
      display = new Display();
      add(display);
      pack();
      setLocationRelativeTo(null);
   }

   public class Display extends JPanel implements MouseMotionListener, MouseWheelListener {

      public BufferedImage buffer;
      public int x, y;

      public Display() {
         buffer = new BufferedImage(Main.w, Main.h, BufferedImage.TYPE_INT_RGB);
         setPreferredSize(new Dimension(Main.w, Main.h));
         addMouseMotionListener(this);
         addMouseWheelListener(this);
      }

      @Override
      public void paint(Graphics g) {
         g.drawImage(buffer, 0, 0, null);
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         Main.dx += -(e.getX() - x) / (float) Main.w * Main.sx;
         Main.dy += (e.getY() - y) / (float) Main.h * Main.sy;
         x = e.getX();
         y = e.getY();
      }

      @Override
      public void mouseMoved(MouseEvent e) {
         x = e.getX();
         y = e.getY();
      }

      @Override
      public void mouseWheelMoved(MouseWheelEvent e) {
         int i = e.getWheelRotation();
         float ratio = 1.2f;
         if (i < 0) {
            ratio = 1 / ratio;
            i *= -1;
         }
         while (i-- > 0) {
            Main.sx *= ratio;
            Main.sy *= ratio;
         }
      }

   }

}

Window.java