package kaka.cakelight;
-import static kaka.cakelight.Main.timeIt;
-
public class CakeLight {
private Configuration config;
private Mode mode;
+ private LedController ledController;
- public CakeLight(Configuration config) {
+ public CakeLight(Configuration config, LedController ledController) {
this.config = config;
+ this.ledController = ledController;
}
public void setMode(Mode mode) {
cleanup();
this.mode = mode;
+ mode.setFrameListener(ledController);
mode.enter(config);
}
public Mat getConvertedImage() {
return converted;
}
+
+ /**
+ * Creates a LED frame going clockwise from the bottom-left corner, sans the corners.
+ */
+ public LedFrame getLedFrame() {
+ LedFrame frame = LedFrame.from(config);
+ int led = 0;
+ for (int i = config.leds.rows - 1; i >= 0; i--) frame.setLedColor(led++, getLedColor(ListPosition.LEFT, i));
+ for (int i = 0; i < config.leds.cols; i++) frame.setLedColor(led++, getLedColor(ListPosition.TOP, i));
+ for (int i = 0; i < config.leds.rows; i++) frame.setLedColor(led++, getLedColor(ListPosition.RIGHT, i));
+ for (int i = config.leds.cols - 1; i >= 0; i--) frame.setLedColor(led++, getLedColor(ListPosition.BOTTOM, i));
+ return frame;
+ }
}
private void setupCakeLight() {
log("Running with config:\n" + config);
- cakelight = new CakeLight(config);
+ cakelight = new CakeLight(config, new LedController() {
+ @Override
+ public void accept(LedFrame ledFrame) {
+ if (!paused) drawLEDs(canvas.getGraphicsContext2D(), ledFrame);
+ }
+ });
VideoMode mode = new VideoMode();
cakelight.setMode(mode);
cakelight.startLoop();
- mode.onFrame(frame -> drawFrame(canvas.getGraphicsContext2D(), frame));
+ mode.onVideoFrame(frame -> drawFrame(canvas.getGraphicsContext2D(), frame));
}
private void drawFrame(GraphicsContext gc, Frame frame) {
drawRows(gc, frame);
// drawVideo(gc, frame);
drawBorderAndGrid(gc);
- drawLEDs(gc, frame);
}
- private void drawLEDs(GraphicsContext gc, Frame frame) {
+ private void drawLEDs(GraphicsContext gc, LedFrame frame) {
int ledLength = GUTTER;
float colSize = 16f * BLOCK / config.leds.cols;
float rowSize = 9f * BLOCK / config.leds.rows;
// DropShadow shadow = new DropShadow(BlurType.ONE_PASS_BOX, Color.RED, colSize * 2, colSize, 0, 0);
for (int x = 0; x < config.leds.cols; x++) {
- gc.setFill(frame.getLedColor(ListPosition.TOP, x));
+ gc.setFill(frame.getLedColor(x + config.leds.rows));
gc.fillRect(GUTTER + x * colSize, GUTTER - ledLength, colSize, ledLength);
- gc.setFill(frame.getLedColor(ListPosition.BOTTOM, x));
+ gc.setFill(frame.getLedColor(config.leds.rows * 2 + config.leds.cols * 2 - 1 - x));
gc.fillRect(GUTTER + x * colSize, GUTTER + 9 * BLOCK, colSize, ledLength);
}
for (int y = 0; y < config.leds.rows; y++) {
- gc.setFill(frame.getLedColor(ListPosition.LEFT, y));
+ gc.setFill(frame.getLedColor(config.leds.rows - 1 - y));
gc.fillRect(GUTTER - ledLength, GUTTER + y * rowSize, ledLength, rowSize);
- gc.setFill(frame.getLedColor(ListPosition.RIGHT, y));
+ gc.setFill(frame.getLedColor(y + config.leds.rows + config.leds.cols));
gc.fillRect(GUTTER + 16 * BLOCK, GUTTER + y * rowSize, ledLength, rowSize);
}
}
--- /dev/null
+package kaka.cakelight;
+
+import java.util.function.Consumer;
+
+public class LedController implements Consumer<LedFrame> {
+ @Override
+ public void accept(LedFrame ledFrame) {
+ // TODO
+ }
+}
--- /dev/null
+package kaka.cakelight;
+
+import javafx.scene.paint.Color;
+
+public class LedFrame {
+ private Color[] leds;
+
+ public static LedFrame from(Configuration config) {
+ LedFrame frame = new LedFrame();
+ frame.leds = new Color[config.leds.cols * 2 + config.leds.rows * 2];
+ return frame;
+ }
+
+ public void setLedColor(int led, Color color) {
+ leds[led] = color;
+ }
+
+ public Color getLedColor(int led) {
+ return leds[led];
+ }
+}
Configuration config = Configuration.from("config.properties");
log("Running with config:\n" + config);
- CakeLight cakelight = new CakeLight(config);
+ CakeLight cakelight = new CakeLight(config, new LedController());
cakelight.setMode(new VideoMode());
cakelight.startLoop();
// try {
package kaka.cakelight;
-public interface Mode {
- void enter(Configuration config);
- void exit();
+import java.util.function.Consumer;
+
+public abstract class Mode {
+ protected Consumer<LedFrame> frameListener;
+
+ public abstract void enter(Configuration config);
+ public abstract void exit();
+
+ public void setFrameListener(Consumer<LedFrame> listener) {
+ frameListener = listener;
+ }
}
import java.util.Optional;
import java.util.function.Consumer;
-public class VideoMode implements Mode, Consumer<Optional<File>> {
+public class VideoMode extends Mode implements Consumer<Optional<File>> {
private Configuration config;
private Thread thread;
private Consumer<Frame> frameConsumer;
public void run() {
try (FrameGrabber grabber = FrameGrabber.from(videoDevice, config)) {
while (!isInterrupted()) {
-// Optional<Frame> frame = grabber.grabFrame();
- grabber.grabFrame().ifPresent(frameConsumer);
+ Optional<Frame> frame = grabber.grabFrame();
+ if (frameConsumer != null) frame.ifPresent(frameConsumer);
+ frame.ifPresent(VideoMode.this::onFrame);
// timeIt("frame", grabber::grabFrame);
// TODO: process frame
// TODO: save where the LedController can access it
thread.start();
}
- public void onFrame(Consumer<Frame> consumer) {
+ public void onVideoFrame(Consumer<Frame> consumer) {
frameConsumer = consumer;
}
+ private void onFrame(Frame frame) {
+ assert frameListener != null;
+ frameListener.accept(frame.getLedFrame());
+ }
+
@Override
public void accept(Optional<File> videoDevice) {
// Should only happen when this mode is active!