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.buffer.Buffer;
 28 import hat.buffer.S32Array2D;
 29 import hat.util.ui.SevenSegmentDisplay;
 30 
 31 import javax.swing.Box;
 32 import javax.swing.BoxLayout;
 33 import javax.swing.JButton;
 34 import javax.swing.JComponent;
 35 import javax.swing.JFrame;
 36 import javax.swing.JLabel;
 37 import javax.swing.JMenuBar;
 38 import javax.swing.JPanel;
 39 import javax.swing.WindowConstants;
 40 import java.awt.Dimension;
 41 import java.awt.Graphics;
 42 import java.awt.Graphics2D;
 43 import java.awt.Point;
 44 import java.awt.event.MouseAdapter;
 45 import java.awt.event.MouseEvent;
 46 import java.awt.image.BufferedImage;
 47 import java.awt.image.DataBufferInt;
 48 import java.lang.foreign.MemoryLayout;
 49 import java.lang.foreign.MemorySegment;
 50 
 51 import static java.lang.foreign.ValueLayout.JAVA_INT;
 52 
 53 public class Viewer extends JFrame {
 54 
 55     public final SevenSegmentDisplay framesSecondSevenSegment;
 56 
 57     public static class PointF32 {
 58         public final float x;
 59         public final float y;
 60 
 61         public PointF32(float x, float y) {
 62             this.x = x;
 63             this.y = y;
 64         }
 65     }
 66 
 67     public final ImageViewer imageViewer;
 68 
 69 
 70     public static class ImageViewer extends JComponent {
 71 
 72         public PointF32 getZoomPoint(float scale) {
 73             waitForDoorbell();
 74             return new PointF32(
 75                     ((float) (to.x - (image.getWidth() / 2)) / image.getWidth()) * scale,
 76                     ((float) (to.y - (image.getHeight() / 2)) / image.getHeight()) * scale);
 77         }
 78 
 79         final BufferedImage image;
 80         private final Object doorBell = new Object();
 81         public Point to = null;
 82 
 83         ImageViewer(BufferedImage image) {
 84             super();
 85             this.image = image;
 86             addMouseListener(new MouseAdapter() {
 87                 @Override
 88                 public void mouseClicked(MouseEvent e) {
 89                     to = e.getPoint();
 90                     synchronized (doorBell) {
 91                         doorBell.notify();
 92                     }
 93                 }
 94             });
 95             to = new Point(image.getWidth() / 2, image.getHeight() / 2);
 96         }
 97 
 98         @Override
 99         public Dimension getPreferredSize() {
100             return new Dimension(image.getWidth(), image.getHeight());
101         }
102 
103         @Override
104         public void paintComponent(Graphics g1d) {
105             super.paintComponent(g1d);
106             Graphics2D g = (Graphics2D) g1d;
107             g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), this);
108         }
109 
110         public void waitForDoorbell() {
111             to = null;
112             while (to == null) {
113                 synchronized (doorBell) {
114                     try {
115                         doorBell.wait();
116                     } catch (final InterruptedException ie) {
117                         ie.getStackTrace();
118                     }
119                 }
120             }
121         }
122 
123         public void syncWithRGB(S32Array2D s32Array2D) {
124             long offset = Buffer.getLayout(s32Array2D).byteOffset(MemoryLayout.PathElement.groupElement("array"));
125             MemorySegment.copy(Buffer.getMemorySegment(s32Array2D), JAVA_INT, offset, ((DataBufferInt) image.getRaster().getDataBuffer()).getData(), 0, s32Array2D.width()*s32Array2D.height());
126             this.repaint();
127         }
128 
129 
130     }
131 
132     public Viewer(String title, S32Array2D s32Array2D) {
133         super(title);
134 
135         this.imageViewer = new ImageViewer(new BufferedImage(s32Array2D.width(), s32Array2D.height(), BufferedImage.TYPE_INT_RGB));
136         var menuBar = new JMenuBar();
137         JPanel panel = new JPanel();
138         panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
139         ((JButton) panel.add(new JButton("Exit"))).addActionListener(_ -> System.exit(0));
140         panel.add(new JLabel("FPS"));
141         this.framesSecondSevenSegment = (SevenSegmentDisplay)
142                 panel.add(new SevenSegmentDisplay(4,30,panel.getForeground(),panel.getBackground()));
143         panel.add(Box.createHorizontalStrut(400));
144         menuBar.add(panel);
145         this.setJMenuBar(menuBar);
146         this.getContentPane().add(this.imageViewer);
147         this.pack();
148         this.setLocationRelativeTo(null);
149         this.setVisible(true);
150         this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
151     }
152 }