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 }