Added another key to exit the GUI - 'q'
[kaka/cakelight.git] / src / kaka / cakelight / GuiTest.java
1 package kaka.cakelight;
2
3 import javafx.application.Application;
4 import javafx.scene.Scene;
5 import javafx.scene.canvas.Canvas;
6 import javafx.scene.canvas.GraphicsContext;
7 import javafx.scene.input.KeyCode;
8 import javafx.scene.layout.Pane;
9 import javafx.scene.paint.Color;
10 import javafx.scene.paint.Paint;
11 import javafx.stage.Stage;
12 import org.opencv.core.Core;
13 import org.opencv.core.Mat;
14
15 import static kaka.cakelight.Main.log;
16
17 public class GuiTest extends Application {
18     private static final int BLOCK = 45;
19     private static final int GUTTER = 3 * BLOCK;
20     private Canvas canvas;
21     private Configuration config;
22     private CakeLight cakelight;
23     private boolean paused;
24
25     public static void main(String[] args) {
26         System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
27         launch(args);
28     }
29
30     @Override
31     public void start(Stage stage) throws Exception {
32         config = Configuration.from("config.properties");
33         canvas = new Canvas(16 * BLOCK + 2 * GUTTER, 9 * BLOCK + 2 * GUTTER);
34
35         Pane root = new Pane();
36         root.getChildren().add(canvas);
37
38         Scene scene = new Scene(root);
39         scene.setOnKeyPressed(keyEvent -> {
40             if (keyEvent.getCode() == KeyCode.ESCAPE || keyEvent.getCode() == KeyCode.Q) {
41                 stage.close();
42                 cakelight.cleanup();
43             }
44             if (keyEvent.getCode() == KeyCode.SPACE) {
45                 paused = !paused;
46             }
47         });
48
49         stage.setTitle("Cakelight");
50         stage.setScene(scene);
51         stage.setOnCloseRequest(windowEvent -> cakelight.cleanup());
52         stage.show();
53
54         setupCakeLight();
55     }
56
57     private void setupCakeLight() {
58         log("Running with config:\n" + config);
59         cakelight = new CakeLight(config);
60         VideoMode mode = new VideoMode();
61         cakelight.setMode(mode);
62         cakelight.startLoop();
63         mode.onVideoFrame(frame -> drawFrame(canvas.getGraphicsContext2D(), frame));
64     }
65
66     private javafx.scene.paint.Color getLedColor(LedFrame frame, int led) {
67         kaka.cakelight.Color c = frame.getLedColor(led);
68         return javafx.scene.paint.Color.rgb(c.r(), c.g(), c.b());
69     }
70
71     private void drawFrame(GraphicsContext gc, Frame frame) {
72         if (paused) return;
73         System.out.println("Drawing a frame");
74         drawCols(gc, frame);
75         drawRows(gc, frame);
76 //        drawVideo(gc, frame);
77         drawBorderAndGrid(gc);
78     }
79
80     private void drawLEDs(GraphicsContext gc, LedFrame frame) {
81         int ledLength = GUTTER;
82         float colSize = 16f * BLOCK / config.leds.cols;
83         float rowSize = 9f * BLOCK / config.leds.rows;
84 //        DropShadow shadow = new DropShadow(BlurType.ONE_PASS_BOX, Color.RED, colSize * 2, colSize, 0, 0);
85         for (int x = 0; x < config.leds.cols; x++) {
86             gc.setFill(getLedColor(frame, x + config.leds.rows));
87             gc.fillRect(GUTTER + x * colSize, GUTTER - ledLength, colSize, ledLength);
88             gc.setFill(getLedColor(frame, config.leds.rows * 2 + config.leds.cols * 2 - 1 - x));
89             gc.fillRect(GUTTER + x * colSize, GUTTER + 9 * BLOCK, colSize, ledLength);
90         }
91         for (int y = 0; y < config.leds.rows; y++) {
92             gc.setFill(getLedColor(frame, config.leds.rows - 1 - y));
93             gc.fillRect(GUTTER - ledLength, GUTTER + y * rowSize, ledLength, rowSize);
94             gc.setFill(getLedColor(frame, y + config.leds.rows + config.leds.cols));
95             gc.fillRect(GUTTER + 16 * BLOCK, GUTTER + y * rowSize, ledLength, rowSize);
96         }
97     }
98
99     private void drawVideo(GraphicsContext gc, Frame frame) {
100         byte[] rgb = new byte[3];
101         Mat img = frame.getConvertedImage();
102         float colSize = 16 * BLOCK / (float)img.cols();
103         float rowSize = 9 * BLOCK / (float)img.rows();
104         for (int x = 0, cols = img.cols(); x < cols; x++) {
105             for (int y = 0, rows = img.rows(); y < rows; y++) {
106                 img.get(y, x, rgb);
107                 gc.setFill(Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff, 0.5));
108                 gc.fillRect(GUTTER + x * colSize, GUTTER + y * rowSize, colSize, rowSize);
109             }
110         }
111     }
112
113     private void drawCols(GraphicsContext gc, Frame frame) {
114         byte[] rgb = new byte[3];
115         for (int x = 0; x < config.leds.cols; x++) {
116             for (int y = 0; y < 9; y++) {
117                 frame.getColImage().get(y, x, rgb);
118                 drawColPixel(gc, x, y, rgb);
119             }
120         }
121     }
122
123     private void drawRows(GraphicsContext gc, Frame frame) {
124         byte[] rgb = new byte[3];
125         for (int y = 0; y < config.leds.rows; y++) {
126             for (int x = 0; x < 16; x++) {
127                 frame.getRowImage().get(y, x, rgb);
128                 drawRowPixel(gc, x, y, rgb);
129             }
130         }
131     }
132
133     private void drawColPixel(GraphicsContext gc, int x, int y, byte[] rgb) {
134         float ledSize = 16f * BLOCK / config.leds.cols;
135         gc.setFill(Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff, 0.5));
136         gc.fillRect(GUTTER + x * ledSize, GUTTER + y * BLOCK, ledSize, BLOCK);
137     }
138
139     private void drawRowPixel(GraphicsContext gc, int x, int y, byte[] rgb) {
140         float ledSize = 9f * BLOCK / config.leds.rows;
141         gc.setFill(Color.rgb(rgb[0] & 0xff, rgb[1] & 0xff, rgb[2] & 0xff, 0.5));
142         gc.fillRect(GUTTER + x * BLOCK, GUTTER + y * ledSize, BLOCK, ledSize);
143     }
144
145     private void drawBorderAndGrid(GraphicsContext gc) {
146         gc.setStroke(Color.BLACK);
147         gc.setLineWidth(BLOCK * 0.1);
148         gc.strokeRect(GUTTER, GUTTER, 16 * BLOCK, 9 * BLOCK);
149         gc.setLineWidth(1);
150         for (int x = 1; x < 16; x++) {
151             gc.strokeLine(GUTTER + x * BLOCK, GUTTER, GUTTER + x * BLOCK, GUTTER + 9 * BLOCK);
152         }
153         for (int y = 1; y < 9; y++) {
154             gc.strokeLine(GUTTER, GUTTER + y * BLOCK, GUTTER + 16 * BLOCK, GUTTER + y * BLOCK);
155         }
156     }
157
158     private void drawPixel(GraphicsContext gc, int x, int y, Paint paint) {
159         gc.setFill(paint);
160         gc.fillRect(GUTTER + x * BLOCK, GUTTER + y * BLOCK, BLOCK, BLOCK);
161     }
162 }