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 experiments;
 26 
 27 import hat.Accelerator;
 28 import hat.ComputeContext;
 29 import hat.buffer.S32Array2D;
 30 import hat.buffer.S32RGBAImage;
 31 import jdk.incubator.code.Reflect;
 32 import optkl.ifacemapper.MappableIface;
 33 
 34 import javax.swing.Box;
 35 import javax.swing.JFrame;
 36 import javax.swing.JPanel;
 37 import java.awt.Dimension;
 38 import java.awt.Graphics;
 39 import java.awt.Graphics2D;
 40 import java.awt.Point;
 41 import java.awt.RenderingHints;
 42 import java.awt.image.BufferedImage;
 43 import java.awt.image.DataBufferInt;
 44 import java.awt.image.WritableRaster;
 45 import java.lang.invoke.MethodHandles;
 46 import java.util.Arrays;
 47 
 48 public class DirectRasterFrame extends JPanel implements Runnable {
 49     private final int WIDTH = 1024, HEIGHT = 1024;
 50     private BufferedImage canvas;
 51     private WritableRaster raster;
 52     private DataBufferInt dataBuffer;
 53     private int[] pixels;
 54     private Accelerator acc;
 55    // private F32x3Array2D arr;
 56     private boolean usePixels;
 57     private S32RGBAImage image;
 58     private float[] starX, starY, starZ;
 59     private final int NUM_STARS = 500000;
 60     static int FAR = 700;
 61     static int MID = 300;
 62     static int NEAR = 100;
 63 
 64     public DirectRasterFrame(Accelerator acc, boolean usePixels) {
 65         this.acc = acc;
 66         this.usePixels = usePixels;
 67         setPreferredSize(new Dimension(WIDTH, HEIGHT));
 68         this.image = S32RGBAImage.create(acc,WIDTH,HEIGHT);
 69        // this.arr = F32x3Array2D.create(acc, WIDTH,HEIGHT);
 70        // this.arr.clear();
 71         // Initialize the direct-access buffer
 72         this.canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
 73         this.raster = canvas.getRaster();
 74         this.dataBuffer = ((DataBufferInt) raster.getDataBuffer());
 75         this.pixels = dataBuffer.getData();
 76 
 77         // Initialize stars with random positions
 78         this.starX = new float[NUM_STARS];
 79         this.starY = new float[NUM_STARS];
 80         this.starZ = new float[NUM_STARS];
 81         for (int i = 0; i < NUM_STARS; i++) {
 82             this.starX[i] = (float) (Math.random() * 2 - 1) * WIDTH;
 83             this.starY[i] = (float) (Math.random() * 2 - 1) * HEIGHT;
 84             this.starZ[i] = (float) (Math.random() * WIDTH);
 85         }
 86     }
 87 
 88     public void run() {
 89         while (true) {
 90             long startNs = System.nanoTime();
 91             if (usePixels) {
 92                 Arrays.fill(pixels, 0);
 93 
 94                 for (int i = 0; i < NUM_STARS; i++) {
 95                     starZ[i] -= 4.0f; // Move star closer to camera
 96                     if (starZ[i] <= 0) starZ[i] = WIDTH; // Reset star depth
 97 
 98                     // Perspective projection: Divide by Z
 99                     int px = (int) (starX[i] / (starZ[i] / WIDTH)) + WIDTH / 2;
100                     int py = (int) (starY[i] / (starZ[i] / WIDTH)) + HEIGHT / 2;
101 
102                     // 3. Bounds check and direct write
103                     if (px > 1 && px < WIDTH - 2 && py > 1 && py < HEIGHT - 2) {
104                         // Calculate brightness based on depth (Z)
105                         int brightness = (int) (255 - (starZ[i] / WIDTH * 255));
106                         int color = (brightness << 16) | (brightness << 8) | brightness;
107                         pixels[py * WIDTH + px] = color;
108                         if (starZ[i] < FAR) {
109                             //System.out.println(starZ[i]);
110                             pixels[py * WIDTH + px + 1] = color;
111                             pixels[py * WIDTH + px - 1] = color;
112                             pixels[(py + 1) * WIDTH + px] = color;
113                             pixels[(py - 1) * WIDTH + px] = color;
114                             if (starZ[i] < MID) {
115                                 pixels[(py - 1) * WIDTH + px + 1] = color;
116                                 pixels[(py - 1) * WIDTH + px - 1] = color;
117                                 pixels[(py + 1) * WIDTH + px + 1] = color;
118                                 pixels[(py + 1) * WIDTH + px - 1] = color;
119                                 if (starZ[i] < NEAR) {
120                                     pixels[(py - 2) * WIDTH + px + 2] = color;
121                                     pixels[(py - 2) * WIDTH + px - 2] = color;
122                                     pixels[(py + 2) * WIDTH + px + 2] = color;
123                                     pixels[(py + 2) * WIDTH + px - 2] = color;
124                                 }
125                             }
126                         }
127                     }
128                 }
129             } else{
130                 MappableIface.getMemorySegment(image).fill((byte)0x10);
131 
132                 for (int i = 0; i < NUM_STARS; i++) {
133                     starZ[i] -= 4.0f; // Move star closer to camera
134                     if (starZ[i] <= 0) starZ[i] = WIDTH; // Reset star depth
135                     // Perspective projection: Divide by Z
136                     int px = (int) (starX[i] / (starZ[i] / WIDTH)) + WIDTH / 2;
137                     int py = (int) (starY[i] / (starZ[i] / WIDTH)) + HEIGHT / 2;
138 
139                     // 3. Bounds check and direct write
140                     if (px > 1 && px < WIDTH - 2 && py > 1 && py < HEIGHT - 2) {
141                         // Calculate brightness based on depth (Z)
142                         int brightness = (int) (255 - (starZ[i] / WIDTH * 255));
143                         int color = (brightness << 16) | (brightness << 8) | brightness;
144                         int pos = ((py * WIDTH) + px);
145                         image.data(pos,color);
146                         if (starZ[i] < FAR) {
147                             image.data(pos+1,color);
148                             image.data(pos-1,color);
149                             image.data(pos+WIDTH,color);
150                             image.data(pos-WIDTH,color);
151                             if (starZ[i] < MID) {
152                                 image.data(pos+WIDTH+1,color);
153                                 image.data(pos+WIDTH-1,color);
154                                 image.data(pos-WIDTH+1,color);
155                                 image.data(pos-WIDTH-1,color);
156                                 if (starZ[i] < NEAR) {
157                                     image.data(pos+WIDTH*2+2,color);
158                                     image.data(pos+WIDTH*2-2,color);
159                                     image.data(pos-WIDTH*2+2,color);
160                                     image.data(pos-WIDTH*2-2,color);
161                                 }
162                             }
163                         }
164                     }
165                 }
166                     image.syncToRasterDataBuffer(dataBuffer);
167 
168             }
169 
170             long endNs = System.nanoTime();
171             System.out.println((endNs-startNs)/1000000+"ms");
172 
173             // 4. Request UI to draw the modified image
174             repaint();
175 
176             try { Thread.sleep(8); } catch (Exception e) {}
177         }
178     }
179 
180     @Override
181     protected void paintComponent(Graphics g) {
182         Graphics2D g2d = (Graphics2D) g;
183         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
184         g2d.drawImage(canvas, 0, 0, null);
185     }
186 
187     public static void main(String[] args) {
188         JFrame f = new JFrame("Direct Pixel Starfield");
189         DirectRasterFrame fs = new DirectRasterFrame(new Accelerator(MethodHandles.lookup()), true);
190         f.add(fs);
191         f.pack();
192         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
193         f.setVisible(true);
194         new Thread(fs).start();
195     }
196 }