1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package mandel;
 26 
 27 import hat.Accelerator;
 28 import hat.Accelerator.Compute;
 29 import hat.ComputeContext;
 30 import hat.NDRange;
 31 import hat.KernelContext;
 32 import hat.backend.Backend;
 33 import hat.buffer.S32Array;
 34 import hat.buffer.S32Array2D;
 35 
 36 import java.awt.Color;
 37 import java.lang.invoke.MethodHandles;
 38 
 39 import jdk.incubator.code.Reflect;
 40 import optkl.ifacemapper.MappableIface.RO;
 41 import optkl.ifacemapper.MappableIface.RW;
 42 import optkl.ifacemapper.MappableIface.RW;
 43 
 44 public class Main {
 45     @Reflect
 46     public static void mandel(KernelContext kc, S32Array2D s32Array2D, S32Array pallette, float offsetx, float offsety, float scale) {
 47         if (kc.gix < kc.gsx) {
 48             float width = s32Array2D.width();
 49             float height = s32Array2D.height();
 50             float x = ((kc.gix % s32Array2D.width()) * scale - (scale / 2f * width)) / width + offsetx;
 51             float y = ((kc.gix / s32Array2D.width()) * scale - (scale / 2f * height)) / height + offsety;
 52             float zx = x;
 53             float zy = y;
 54             float new_zx;
 55             int colorIdx = 0;
 56             while ((colorIdx < pallette.length()) && (((zx * zx) + (zy * zy)) < 4f)) {
 57                 new_zx = ((zx * zx) - (zy * zy)) + x;
 58                 zy = (2f * zx * zy) + y;
 59                 zx = new_zx;
 60                 colorIdx++;
 61             }
 62             int color = colorIdx < pallette.length() ? pallette.array(colorIdx) : 0;
 63             s32Array2D.array(kc.gix, color);
 64         }
 65     }
 66 
 67 
 68     @Reflect
 69     static public void compute(final ComputeContext computeContext, S32Array pallete, S32Array2D s32Array2D, float x, float y, float scale) {
 70         computeContext.dispatchKernel(
 71                 NDRange.of1D(s32Array2D.width()*s32Array2D.height()),               //0..S32Array2D.size()
 72                 kc -> Main.mandel(kc, s32Array2D, pallete, x, y, scale));
 73     }
 74 
 75     public static void main(String[] args) {
 76         final int width = 1024;
 77         final int height = 1024;
 78         final float defaultScale = 3f;
 79         final float originX = -1f;
 80         final float originY = 0;
 81         final int maxIterations = 64;
 82         final int zoomFrames = 200;
 83 
 84         Accelerator accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
 85         boolean headless = accelerator.config().headless(args.length>0?args[0]:null);
 86         S32Array2D s32Array2D = S32Array2D.create(accelerator, width, height);
 87 
 88         int[] palletteArray = new int[maxIterations];
 89 
 90         if (accelerator.config().headless(args.length>0?args[0]:null)){
 91             for (int i = 1; i < maxIterations; i++) {
 92                 palletteArray[i]=(i/8+1);// 0-7?
 93             }
 94             palletteArray[0]=0;
 95         }else {
 96             for (int i = 0; i < maxIterations; i++) {
 97                 final float h = i / (float) maxIterations;
 98                 final float b = 1.0f - (h * h);
 99                 palletteArray[i] = Color.HSBtoRGB(h, 1f, b);
100             }
101         }
102         S32Array pallette = S32Array.createFrom(accelerator, palletteArray);
103 
104         accelerator.compute((@Reflect Compute)
105                 cc -> Main.compute(cc, pallette, s32Array2D, originX, originY, defaultScale));
106 
107         if (headless){
108             // Well take 1 in 4 samples (so 1024 -> 128 grid) of the pallette.
109             int subsample = 16;
110             char[] charPallette9 = new char []{' ', '.', ',',':', '-', '+','*', '#', '@', '%'};
111             for (int y = 0; y<height/subsample; y++) {
112                 for (int x = 0; x<width/subsample; x++) {
113                      int palletteValue = s32Array2D.get(x*subsample,y*subsample); // so 0->8
114                      System.out.print(charPallette9[palletteValue]);
115                 }
116                 System.out.println();
117             }
118 
119         }else {
120             Viewer viewer = new Viewer("mandel", s32Array2D);
121             viewer.imageViewer.syncWithRGB(s32Array2D);
122 
123             while (viewer.imageViewer.getZoomPoint(defaultScale) instanceof Viewer.PointF32 zoomPoint) {
124                 float x = originX;
125                 float y = originY;
126                 float scale = defaultScale;
127                 final long startMillis = System.currentTimeMillis();
128 
129                 for (int sign : new int[]{-1, 1}) {
130                     for (int i = 0; i < zoomFrames; i++) {
131                         scale = scale + ((sign * defaultScale) / zoomFrames);
132                         final float fscale = scale;
133                         final float fx = x - sign * zoomPoint.x / zoomFrames;
134                         final float fy = y - sign * zoomPoint.y / zoomFrames;
135                         accelerator.compute((@Reflect Compute)
136                                 cc -> Main.compute(cc, pallette, s32Array2D, fx, fy, fscale));
137                         viewer.imageViewer.syncWithRGB(s32Array2D);
138 
139                     }
140                 }
141                 var fps =  ((zoomFrames * 2 * 1000) / (System.currentTimeMillis() - startMillis));
142                 viewer.framesSecondSevenSegment.set((int)fps);
143                // System.out.println("FPS = " +fps);
144             }
145         }
146     }
147 }