From edf8a1b3c474143d2856e477cec005d3a51aa4bc Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 20:07:30 +0300 Subject: [PATCH 01/11] fix(BufferedImageRaster): fix strange frame rendering bug --- .../lab5/graphics/BufferedImageRaster.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/labs/introtoprogramming/lab5/graphics/BufferedImageRaster.java b/src/main/java/labs/introtoprogramming/lab5/graphics/BufferedImageRaster.java index 874b74e..b7eaecf 100644 --- a/src/main/java/labs/introtoprogramming/lab5/graphics/BufferedImageRaster.java +++ b/src/main/java/labs/introtoprogramming/lab5/graphics/BufferedImageRaster.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.awt.GraphicsEnvironment; import java.awt.Image; +import java.awt.Transparency; import java.awt.image.BufferedImage; public class BufferedImageRaster implements Raster { @@ -14,9 +15,9 @@ public BufferedImageRaster(int width, int height) { if (!GraphicsEnvironment.isHeadless()) { image = GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice() - .getDefaultConfiguration().createCompatibleImage(width, height); + .getDefaultConfiguration().createCompatibleImage(width, height, Transparency.BITMASK); } else { - image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); } } From dc0e1b232ddff4d1a47de8c197660a78c1bc0de5 Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 20:15:52 +0300 Subject: [PATCH 02/11] feat(ControllableCamera): camera controllable by keyboard and mouse --- .../introtoprogramming/lab5/gui/Input.java | 92 +++++++++++++++++++ .../lab5/gui/InputKeyListener.java | 49 ++++++++++ .../lab5/gui/MouseController.java | 57 ++++++++++++ .../lab5/gui/SceneRendererWindow.java | 72 +++++++++++++++ .../introtoprogramming/lab5/gui/Window.java | 3 +- .../lab5/scene/BasicScene.java | 17 +++- .../introtoprogramming/lab5/scene/Camera.java | 4 + .../lab5/scene/ControllableCamera.java | 25 +++++ .../introtoprogramming/lab5/scene/Scene.java | 18 +++- .../lab5/scene/SceneObject.java | 12 +++ 10 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 src/main/java/labs/introtoprogramming/lab5/gui/Input.java create mode 100644 src/main/java/labs/introtoprogramming/lab5/gui/InputKeyListener.java create mode 100644 src/main/java/labs/introtoprogramming/lab5/gui/MouseController.java create mode 100644 src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java create mode 100644 src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/Input.java b/src/main/java/labs/introtoprogramming/lab5/gui/Input.java new file mode 100644 index 0000000..617b633 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/gui/Input.java @@ -0,0 +1,92 @@ +package labs.introtoprogramming.lab5.gui; + +import labs.introtoprogramming.lab5.geometry.Vector3; + +public class Input { + + private boolean forwardKeyDown = false; + private boolean backwardKeyDown = false; + private boolean leftKeyDown = false; + private boolean rightKeyDown = false; + private boolean upKeyDown = false; + private boolean downKeyDown = false; + + private double mouseDeltaX = 0; + private double mouseDeltaY = 0; + + public Vector3 movementVector() { + return new Vector3((leftKeyDown ? -1 : 0) + (rightKeyDown ? 1 : 0), + (upKeyDown ? 1 : 0) + (downKeyDown ? -1 : 0), + (forwardKeyDown ? -1 : 0) + (backwardKeyDown ? 1 : 0)); + } + + public Vector3 mouseMovement() { + //noinspection SuspiciousNameCombination + return new Vector3(mouseDeltaY, mouseDeltaX, 0); + } + + public double getMouseDeltaX() { + return mouseDeltaX; + } + + public void setMouseDeltaX(double mouseDeltaX) { + this.mouseDeltaX = mouseDeltaX; + } + + public double getMouseDeltaY() { + return mouseDeltaY; + } + + public void setMouseDeltaY(double mouseDeltaY) { + this.mouseDeltaY = mouseDeltaY; + } + + public boolean isForwardKeyDown() { + return forwardKeyDown; + } + + public void setForwardKeyDown(boolean forwardKeyDown) { + this.forwardKeyDown = forwardKeyDown; + } + + public boolean isBackwardKeyDown() { + return backwardKeyDown; + } + + public void setBackwardKeyDown(boolean backwardKeyDown) { + this.backwardKeyDown = backwardKeyDown; + } + + public boolean isLeftKeyDown() { + return leftKeyDown; + } + + public void setLeftKeyDown(boolean leftKeyDown) { + this.leftKeyDown = leftKeyDown; + } + + public boolean isRightKeyDown() { + return rightKeyDown; + } + + public void setRightKeyDown(boolean rightKeyDown) { + this.rightKeyDown = rightKeyDown; + } + + public boolean isUpKeyDown() { + return upKeyDown; + } + + public void setUpKeyDown(boolean upKeyDown) { + this.upKeyDown = upKeyDown; + } + + public boolean isDownKeyDown() { + return downKeyDown; + } + + public void setDownKeyDown(boolean downKeyDown) { + this.downKeyDown = downKeyDown; + } + +} diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/InputKeyListener.java b/src/main/java/labs/introtoprogramming/lab5/gui/InputKeyListener.java new file mode 100644 index 0000000..4e37221 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/gui/InputKeyListener.java @@ -0,0 +1,49 @@ +package labs.introtoprogramming.lab5.gui; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +class InputKeyListener implements KeyListener { + + private Input input; + + InputKeyListener(Input input) { + this.input = input; + } + + @Override + public void keyTyped(KeyEvent e) { + // ignore + } + + @Override + public void keyPressed(KeyEvent e) { + keyCodeUpdate(e.getKeyCode(), true); + } + + @Override + public void keyReleased(KeyEvent e) { + keyCodeUpdate(e.getKeyCode(), false); + } + + private void keyCodeUpdate(int keyCode, boolean isDown) { + if (keyCode == KeyEvent.VK_W || keyCode == KeyEvent.VK_UP) { + input.setForwardKeyDown(isDown); + } + if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_DOWN) { + input.setBackwardKeyDown(isDown); + } + if (keyCode == KeyEvent.VK_A || keyCode == KeyEvent.VK_LEFT) { + input.setLeftKeyDown(isDown); + } + if (keyCode == KeyEvent.VK_D || keyCode == KeyEvent.VK_RIGHT) { + input.setRightKeyDown(isDown); + } + if (keyCode == KeyEvent.VK_Q) { + input.setUpKeyDown(isDown); + } + if (keyCode == KeyEvent.VK_Z) { + input.setDownKeyDown(isDown); + } + } +} diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/MouseController.java b/src/main/java/labs/introtoprogramming/lab5/gui/MouseController.java new file mode 100644 index 0000000..5909296 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/gui/MouseController.java @@ -0,0 +1,57 @@ +package labs.introtoprogramming.lab5.gui; + +import java.awt.AWTException; +import java.awt.Cursor; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import javax.swing.JFrame; + +class MouseController { + + private static final String BLANK_CURSOR_NAME = "blank cursor"; + + private Input input; + private JFrame frame; + + private Robot robot; + private Point prevLocation; + + MouseController(Input input, JFrame frame) { + this.input = input; + this.frame = frame; + try { + this.robot = new Robot(); + } catch(AWTException e) { + throw new AssertionError(e); + } + } + + void hideCursor() { + BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor( + cursorImg, new Point(0, 0), BLANK_CURSOR_NAME); + frame.setCursor(blankCursor); + } + + void update() { + if (!frame.isFocused()) { + return; + } + + int centerX = frame.getX() + frame.getWidth() / 2; + int centerY = frame.getY() + frame.getHeight() / 2; + Point mouseLocation = MouseInfo.getPointerInfo().getLocation(); + + if (prevLocation != null) { + input.setMouseDeltaX(mouseLocation.getX() - centerX); + input.setMouseDeltaY(mouseLocation.getY() - centerY); + } + + prevLocation = mouseLocation; + robot.mouseMove(centerX, centerY); + } + +} diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java new file mode 100644 index 0000000..efd4d63 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java @@ -0,0 +1,72 @@ +package labs.introtoprogramming.lab5.gui; + +import java.util.Timer; +import java.util.TimerTask; +import labs.introtoprogramming.lab5.exception.NoCameraException; +import labs.introtoprogramming.lab5.scene.BasicRaytracingRender; +import labs.introtoprogramming.lab5.scene.Scene; +import labs.introtoprogramming.lab5.scene.SceneRender; + +public class SceneRendererWindow extends Window { + + private static final String UPDATE_LOOP_TIMER_NAME = "UpdateLoop"; + private static final int UPDATE_LOOP_DELAY = 100; // ms + private static final int TARGET_FPS = 60; + private static final int UPDATE_RATE = 1000/TARGET_FPS; + private static final boolean DEFAULT_CAMERA_CONTROLLABLE = false; + + private SceneRender render; + private Scene scene; + private MouseController mouseController; + private Input input; + + public SceneRendererWindow(Scene scene) { + this(new BasicRaytracingRender(scene.getCamera().orElseThrow(NoCameraException::new).raster()), scene); + setRaster(scene.getCamera().orElseThrow(NoCameraException::new).raster()); + } + + public SceneRendererWindow(SceneRender render, Scene scene) { + this.render = render; + this.scene = scene; + input = new Input(); + scene.getCamera().ifPresent(camera -> setRaster(camera.raster())); + scene.getSceneObjects().forEach(obj -> obj.setInput(input)); + mouseController = new MouseController(input, frame); + } + + public void show() { + super.show(); + startUpdateLoop(); + setupKeyboardListener(); + mouseController.hideCursor(); + } + + private void setupKeyboardListener() { + frame.addKeyListener(new InputKeyListener(input)); + } + + private void startUpdateLoop() { + new Timer(UPDATE_LOOP_TIMER_NAME, true).scheduleAtFixedRate(new TimerTask() { + long previousTime = System.currentTimeMillis(); + + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + updateIteration((int) (currentTime - previousTime)); + previousTime = currentTime; + } + }, UPDATE_LOOP_DELAY, UPDATE_RATE); + } + + private void updateIteration(int delta) { + this.mouseController.update(); + scene.update(delta); + render.render(scene); + this.update(); + } + + private void setScene(Scene scene) { + this.scene = scene; + } + +} diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/Window.java b/src/main/java/labs/introtoprogramming/lab5/gui/Window.java index 2759e57..25a6cc4 100644 --- a/src/main/java/labs/introtoprogramming/lab5/gui/Window.java +++ b/src/main/java/labs/introtoprogramming/lab5/gui/Window.java @@ -8,7 +8,7 @@ public class Window { private static final int FPS_UPDATE_RATE = 100; - private JFrame frame; + protected JFrame frame; private RasterRendererComponent renderer; private Toolkit toolkit; private String title; @@ -74,6 +74,7 @@ public void setTitle(String text) { } public void setRaster(Raster raster) { + setDimensions(raster.getWidth(), raster.getHeight()); this.renderer.setRaster(raster); } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java b/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java index ab695bc..ecf6cc1 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java @@ -1,11 +1,12 @@ package labs.introtoprogramming.lab5.scene; import java.awt.Color; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -public class BasicScene implements Scene { +public class BasicScene extends Scene { private List entities; private Color background; @@ -18,6 +19,15 @@ public BasicScene(List entities) { this(entities, new Color(0, 0, 0)); } + public BasicScene() { + this(new ArrayList<>()); + } + + @Override + public void update(int delta) { + entities.forEach(obj -> obj.update(delta)); + } + @Override public List getSceneObjects() { return entities; @@ -43,4 +53,9 @@ public Optional getCamera() { public Color getBackgroundColor() { return background; } + + @Override + public void addSceneObject(SceneObject obj) { + entities.add(obj); + } } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/Camera.java b/src/main/java/labs/introtoprogramming/lab5/scene/Camera.java index 80ac2ba..2571c2e 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/Camera.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/Camera.java @@ -57,4 +57,8 @@ public void lookAt(Vector3 from, Vector3 to) { Vector3 up = forward.crossProduct(right); transform.setMatrix(right, up, forward, from); } + + public Raster raster() { + return raster; + } } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java b/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java new file mode 100644 index 0000000..73cd247 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java @@ -0,0 +1,25 @@ +package labs.introtoprogramming.lab5.scene; + +import labs.introtoprogramming.lab5.graphics.Raster; + +public class ControllableCamera extends Camera { + + private static double DEFAULT_MOVEMENT_SPEED = 0.0015; + private static double DEFAULT_MOUSE_SENSITIVITY = 0.006; + private double movementSpeed = DEFAULT_MOVEMENT_SPEED; + private double mouseSensitivity = DEFAULT_MOUSE_SENSITIVITY; + + public ControllableCamera(Raster raster, Transform transform) { + super(raster, transform); + } + + @Override + protected void update(int delta) { + getTransform().setPosition( + getTransform().position().add(getInput().movementVector().multiply(movementSpeed * delta)) + ); + getTransform().setRotation(getTransform().rotation().add( + getInput().mouseMovement().multiply(mouseSensitivity * delta) + )); + } +} diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java b/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java index dad60a4..e39508d 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java @@ -1,17 +1,25 @@ package labs.introtoprogramming.lab5.scene; import java.awt.Color; +import java.util.Arrays; import java.util.List; import java.util.Optional; -public interface Scene { +public abstract class Scene { - List getSceneObjects(); + public abstract void update(int delta); - List getLights(); + public abstract List getSceneObjects(); - Optional getCamera(); + public abstract List getLights(); - Color getBackgroundColor(); + public abstract Optional getCamera(); + abstract Color getBackgroundColor(); + + public abstract void addSceneObject(SceneObject obj); + + public void addSceneObjects(SceneObject... obj) { + Arrays.stream(obj).forEach(this::addSceneObject); + } } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java b/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java index 1af25e1..e9e8333 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java @@ -1,11 +1,13 @@ package labs.introtoprogramming.lab5.scene; import labs.introtoprogramming.lab5.geometry.Ray; +import labs.introtoprogramming.lab5.gui.Input; public class SceneObject { protected Transform transform; protected Mesh mesh; + protected Input input; /** * Base class of scene objects. @@ -26,6 +28,8 @@ public SceneObject() { this(new Transform(), new Mesh()); } + protected void update(int delta) {} + public Transform getTransform() { return transform; } @@ -37,4 +41,12 @@ public Mesh getMesh() { public boolean intersect(Ray ray) { return false; } + + public void setInput(Input input) { + this.input = input; + } + + protected Input getInput() { + return input; + } } From 23cfe7b7bb0255f74dd0f246a99bb95518d8b010 Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 20:44:29 +0300 Subject: [PATCH 03/11] feat(scenes): add DemoScene --- .../labs/introtoprogramming/lab5/Main.java | 30 +++++++++++++++++-- .../lab5/scenes/DemoScene.java | 18 +++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/main/java/labs/introtoprogramming/lab5/scenes/DemoScene.java diff --git a/src/main/java/labs/introtoprogramming/lab5/Main.java b/src/main/java/labs/introtoprogramming/lab5/Main.java index e0c95fb..15c5b25 100644 --- a/src/main/java/labs/introtoprogramming/lab5/Main.java +++ b/src/main/java/labs/introtoprogramming/lab5/Main.java @@ -1,11 +1,37 @@ package labs.introtoprogramming.lab5; -import labs.introtoprogramming.lab5.exception.NotImplementedException; +import labs.introtoprogramming.lab5.geometry.Vector3; +import labs.introtoprogramming.lab5.graphics.BufferedImageRaster; +import labs.introtoprogramming.lab5.graphics.Raster; +import labs.introtoprogramming.lab5.gui.SceneRendererWindow; +import labs.introtoprogramming.lab5.scene.Scene; +import labs.introtoprogramming.lab5.scene.Camera; +import labs.introtoprogramming.lab5.scene.ControllableCamera; +import labs.introtoprogramming.lab5.scene.Transform; +import labs.introtoprogramming.lab5.scenes.DemoScene; public class Main { + private static final String APP_TILE = "ray tracing demo"; + private static final int SCREEN_WIDTH = 640; + private static final int SCREEN_HEIGHT = 640; + public static void main(String[] args) { - throw new NotImplementedException(); + new Main().run(); } + private void run() { + Scene demoScene = new DemoScene(); + demoScene.addSceneObject(createCamera()); + + SceneRendererWindow window = new SceneRendererWindow(demoScene); + window.setTitle(APP_TILE); + window.setDisplayFPS(true); + window.show(); + } + + private Camera createCamera() { + Raster raster = new BufferedImageRaster(SCREEN_WIDTH, SCREEN_HEIGHT); + return new ControllableCamera(raster, new Transform(Vector3.ZERO)); + } } diff --git a/src/main/java/labs/introtoprogramming/lab5/scenes/DemoScene.java b/src/main/java/labs/introtoprogramming/lab5/scenes/DemoScene.java new file mode 100644 index 0000000..6b65c44 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/scenes/DemoScene.java @@ -0,0 +1,18 @@ +package labs.introtoprogramming.lab5.scenes; + +import labs.introtoprogramming.lab5.geometry.Vector3; +import labs.introtoprogramming.lab5.object.Box; +import labs.introtoprogramming.lab5.object.Sphere; +import labs.introtoprogramming.lab5.scene.BasicScene; +import labs.introtoprogramming.lab5.scene.Transform; + +public class DemoScene extends BasicScene { + + public DemoScene() { + addSceneObjects( + new Sphere(new Transform(Vector3.FORWARD.multiply(-3)), 1), + new Box(new Transform(Vector3.FORWARD.multiply(-10)), 1), + new Box(new Transform(Vector3.RIGHT.multiply(5)), 1) + ); + } +} From ad7ed847c8d9eba012bd2dd6ba63a992f81a29bb Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:05:33 +0300 Subject: [PATCH 04/11] feat(troubleshooting): add troubleshooting notes --- troubleshooting.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 troubleshooting.md diff --git a/troubleshooting.md b/troubleshooting.md new file mode 100644 index 0000000..f82f1f4 --- /dev/null +++ b/troubleshooting.md @@ -0,0 +1,4 @@ +# Camera movements are limited +If camera rotations are limited, then most probably `Robot` fails to center the cursor. +That's because `moveMouse` does not work on Wayland. The only solution is to switch to +Xorg. \ No newline at end of file From c69d67921bf937c733c0a6df21fbe5431457fc3e Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:06:55 +0300 Subject: [PATCH 05/11] refactor(tests): remove MainTests --- src/test/java/com/labs/introtoprogramming/lab5/MainTests.java | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/test/java/com/labs/introtoprogramming/lab5/MainTests.java diff --git a/src/test/java/com/labs/introtoprogramming/lab5/MainTests.java b/src/test/java/com/labs/introtoprogramming/lab5/MainTests.java deleted file mode 100644 index 9e76a9e..0000000 --- a/src/test/java/com/labs/introtoprogramming/lab5/MainTests.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.labs.introtoprogramming.lab5; - -public class MainTests { -} From 34c96ffe2e1574e3135cded7b9b1878014c966da Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:18:25 +0300 Subject: [PATCH 06/11] feat(Input): add tests --- .../introtoprogramming/lab5/gui/Input.java | 33 ---------- .../lab5/gui/InputTests.java | 60 +++++++++++++++++++ 2 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 src/test/java/labs/introtoprogramming/lab5/gui/InputTests.java diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/Input.java b/src/main/java/labs/introtoprogramming/lab5/gui/Input.java index 617b633..2f131a7 100644 --- a/src/main/java/labs/introtoprogramming/lab5/gui/Input.java +++ b/src/main/java/labs/introtoprogramming/lab5/gui/Input.java @@ -25,68 +25,35 @@ public Vector3 mouseMovement() { return new Vector3(mouseDeltaY, mouseDeltaX, 0); } - public double getMouseDeltaX() { - return mouseDeltaX; - } - public void setMouseDeltaX(double mouseDeltaX) { this.mouseDeltaX = mouseDeltaX; } - public double getMouseDeltaY() { - return mouseDeltaY; - } - public void setMouseDeltaY(double mouseDeltaY) { this.mouseDeltaY = mouseDeltaY; } - public boolean isForwardKeyDown() { - return forwardKeyDown; - } - public void setForwardKeyDown(boolean forwardKeyDown) { this.forwardKeyDown = forwardKeyDown; } - public boolean isBackwardKeyDown() { - return backwardKeyDown; - } - public void setBackwardKeyDown(boolean backwardKeyDown) { this.backwardKeyDown = backwardKeyDown; } - public boolean isLeftKeyDown() { - return leftKeyDown; - } - public void setLeftKeyDown(boolean leftKeyDown) { this.leftKeyDown = leftKeyDown; } - public boolean isRightKeyDown() { - return rightKeyDown; - } - public void setRightKeyDown(boolean rightKeyDown) { this.rightKeyDown = rightKeyDown; } - public boolean isUpKeyDown() { - return upKeyDown; - } - public void setUpKeyDown(boolean upKeyDown) { this.upKeyDown = upKeyDown; } - public boolean isDownKeyDown() { - return downKeyDown; - } - public void setDownKeyDown(boolean downKeyDown) { this.downKeyDown = downKeyDown; } - } diff --git a/src/test/java/labs/introtoprogramming/lab5/gui/InputTests.java b/src/test/java/labs/introtoprogramming/lab5/gui/InputTests.java new file mode 100644 index 0000000..e104931 --- /dev/null +++ b/src/test/java/labs/introtoprogramming/lab5/gui/InputTests.java @@ -0,0 +1,60 @@ +package labs.introtoprogramming.lab5.gui; + +import static org.junit.Assert.assertEquals; + +import java.awt.event.KeyEvent; +import labs.introtoprogramming.lab5.geometry.Vector3; +import org.junit.Test; + +public class InputTests { + + @Test + public void testKeyForward() { + Input input = new Input(); + input.setForwardKeyDown(true); + assertEquals(new Vector3(0, 0, -1), input.movementVector()); + } + + @Test + public void testKeyBackward() { + Input input = new Input(); + input.setBackwardKeyDown(true); + assertEquals(new Vector3(0, 0, 1), input.movementVector()); + } + + @Test + public void testKeyLeft() { + Input input = new Input(); + input.setLeftKeyDown(true); + assertEquals(new Vector3(-1, 0, 0), input.movementVector()); + } + + @Test + public void testKeyRight() { + Input input = new Input(); + input.setRightKeyDown(true); + assertEquals(new Vector3(1, 0, 0), input.movementVector()); + } + + @Test + public void testKeyUp() { + Input input = new Input(); + input.setUpKeyDown(true); + assertEquals(new Vector3(0, 1, 0), input.movementVector()); + } + + @Test + public void testKeyDown() { + Input input = new Input(); + input.setDownKeyDown(true); + assertEquals(new Vector3(0, -1, 0), input.movementVector()); + } + + @Test + public void testMouseDelta() { + Input input = new Input(); + input.setMouseDeltaX(2); + input.setMouseDeltaY(3); + assertEquals(new Vector3(3, 2, 0), input.mouseMovement()); + } +} From e76590c1ede62c8a460b686eb4c1bca122214116 Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:26:32 +0300 Subject: [PATCH 07/11] feat(ControllableCamera): add tests --- .../lab5/scene/ControllableCameraTests.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java diff --git a/src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java b/src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java new file mode 100644 index 0000000..9a2aa92 --- /dev/null +++ b/src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java @@ -0,0 +1,27 @@ +package labs.introtoprogramming.lab5.scene; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertTrue; + +import labs.introtoprogramming.lab5.geometry.Vector3; +import labs.introtoprogramming.lab5.graphics.BufferedImageRaster; +import labs.introtoprogramming.lab5.graphics.Raster; +import labs.introtoprogramming.lab5.gui.Input; +import org.junit.Test; + +public class ControllableCameraTests { + + @Test + public void testUpdate() { + Raster raster = new BufferedImageRaster(100, 100); + SceneObject camera = new ControllableCamera(raster, new Transform(Vector3.ZERO)); + Input input = new Input(); + input.setForwardKeyDown(true); + input.setRightKeyDown(true); + camera.setInput(input); + camera.update(10); + assertTrue(camera.getTransform().position().x > 0); + assertTrue(camera.getTransform().position().z < 0); + } + +} From 21caa877d4be5d4567a4c2b08a318ec13b0b2648 Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:33:31 +0300 Subject: [PATCH 08/11] feat(scene): add scene tests --- .../lab5/scene/SceneTests.java | 32 +++++++++++++++++++ .../lab5/scenes/DemoSceneTests.java | 14 ++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java create mode 100644 src/test/java/labs/introtoprogramming/lab5/scenes/DemoSceneTests.java diff --git a/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java b/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java new file mode 100644 index 0000000..14b863c --- /dev/null +++ b/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java @@ -0,0 +1,32 @@ +package labs.introtoprogramming.lab5.scene; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import labs.introtoprogramming.lab5.geometry.Vector3; +import labs.introtoprogramming.lab5.object.Box; +import org.junit.Test; + +public class SceneTests { + + @Test + public void testSceneUpdateUpdatesObjects() { + Scene scene = new BasicScene(); + MockSceneObject obj = new MockSceneObject(); + scene.addSceneObjects(new Box(new Transform(Vector3.ZERO), 1), obj); + scene.update(10); + assertTrue(obj.updated); + assertEquals(10, obj.updatedWithDelta); + } + + private class MockSceneObject extends SceneObject { + boolean updated = false; + int updatedWithDelta = 0; + + @Override + public void update(int delta) { + this.updated = true; + this.updatedWithDelta = delta; + } + } +} diff --git a/src/test/java/labs/introtoprogramming/lab5/scenes/DemoSceneTests.java b/src/test/java/labs/introtoprogramming/lab5/scenes/DemoSceneTests.java new file mode 100644 index 0000000..baed622 --- /dev/null +++ b/src/test/java/labs/introtoprogramming/lab5/scenes/DemoSceneTests.java @@ -0,0 +1,14 @@ +package labs.introtoprogramming.lab5.scenes; + +import static junit.framework.TestCase.assertTrue; + +import org.junit.Test; + +public class DemoSceneTests { + + @Test + public void testInstantiation() { + DemoScene scene = new DemoScene(); + assertTrue(scene.getSceneObjects().size() > 0); + } +} From 1cfe8462f941bcfc70012817879c64def0a5b4cd Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Sun, 9 Jun 2019 21:41:19 +0300 Subject: [PATCH 09/11] feat(CameraTests): update with raster check --- .../java/labs/introtoprogramming/lab5/scene/CameraTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/labs/introtoprogramming/lab5/scene/CameraTests.java b/src/test/java/labs/introtoprogramming/lab5/scene/CameraTests.java index d9793a8..884470b 100644 --- a/src/test/java/labs/introtoprogramming/lab5/scene/CameraTests.java +++ b/src/test/java/labs/introtoprogramming/lab5/scene/CameraTests.java @@ -17,6 +17,7 @@ public void testInstantiation() { assertEquals(cam.size(), 1, DELTA); assertEquals(cam.fieldOfView(), 2 * Math.atan(1), DELTA); assertEquals(cam.aspectRatio(), 600.0 / 400.0, DELTA); + assertEquals(DUMMY_RASTER, cam.raster()); } @Test From bf9c2d3f847459641463c0e8baac497d715b808a Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Tue, 11 Jun 2019 19:35:38 +0300 Subject: [PATCH 10/11] refactor(ControllableCamera): add KeyAndMouseMovementController for moving and rotating objects --- .../labs/introtoprogramming/lab5/Main.java | 8 ++++-- .../lab5/controllers/Controller.java | 9 ++++++ .../KeyAndMouseMovementController.java | 28 +++++++++++++++++++ .../lab5/gui/SceneRendererWindow.java | 5 +--- .../lab5/scene/BasicScene.java | 17 +++++++++-- .../lab5/scene/ControllableCamera.java | 25 ----------------- .../introtoprogramming/lab5/scene/Scene.java | 8 +++++- .../lab5/scene/SceneObject.java | 12 -------- .../KeyAndMouseControllerTests.java} | 14 ++++++---- .../lab5/scene/SceneTests.java | 19 +++++++------ 10 files changed, 84 insertions(+), 61 deletions(-) create mode 100644 src/main/java/labs/introtoprogramming/lab5/controllers/Controller.java create mode 100644 src/main/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseMovementController.java delete mode 100644 src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java rename src/test/java/labs/introtoprogramming/lab5/{scene/ControllableCameraTests.java => controllers/KeyAndMouseControllerTests.java} (57%) diff --git a/src/main/java/labs/introtoprogramming/lab5/Main.java b/src/main/java/labs/introtoprogramming/lab5/Main.java index 15c5b25..1616f55 100644 --- a/src/main/java/labs/introtoprogramming/lab5/Main.java +++ b/src/main/java/labs/introtoprogramming/lab5/Main.java @@ -1,12 +1,12 @@ package labs.introtoprogramming.lab5; +import labs.introtoprogramming.lab5.controllers.KeyAndMouseMovementController; import labs.introtoprogramming.lab5.geometry.Vector3; import labs.introtoprogramming.lab5.graphics.BufferedImageRaster; import labs.introtoprogramming.lab5.graphics.Raster; import labs.introtoprogramming.lab5.gui.SceneRendererWindow; import labs.introtoprogramming.lab5.scene.Scene; import labs.introtoprogramming.lab5.scene.Camera; -import labs.introtoprogramming.lab5.scene.ControllableCamera; import labs.introtoprogramming.lab5.scene.Transform; import labs.introtoprogramming.lab5.scenes.DemoScene; @@ -22,7 +22,9 @@ public static void main(String[] args) { private void run() { Scene demoScene = new DemoScene(); - demoScene.addSceneObject(createCamera()); + Camera camera = createCamera(); + demoScene.addSceneObjects(camera); + demoScene.addController(new KeyAndMouseMovementController(camera)); SceneRendererWindow window = new SceneRendererWindow(demoScene); window.setTitle(APP_TILE); @@ -32,6 +34,6 @@ private void run() { private Camera createCamera() { Raster raster = new BufferedImageRaster(SCREEN_WIDTH, SCREEN_HEIGHT); - return new ControllableCamera(raster, new Transform(Vector3.ZERO)); + return new Camera(raster, new Transform(Vector3.ZERO)); } } diff --git a/src/main/java/labs/introtoprogramming/lab5/controllers/Controller.java b/src/main/java/labs/introtoprogramming/lab5/controllers/Controller.java new file mode 100644 index 0000000..72a8e46 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/controllers/Controller.java @@ -0,0 +1,9 @@ +package labs.introtoprogramming.lab5.controllers; + +import labs.introtoprogramming.lab5.gui.Input; + +public abstract class Controller { + + public abstract void update(int delta, Input input); + +} diff --git a/src/main/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseMovementController.java b/src/main/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseMovementController.java new file mode 100644 index 0000000..4818230 --- /dev/null +++ b/src/main/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseMovementController.java @@ -0,0 +1,28 @@ +package labs.introtoprogramming.lab5.controllers; + +import labs.introtoprogramming.lab5.gui.Input; +import labs.introtoprogramming.lab5.scene.SceneObject; + +public class KeyAndMouseMovementController extends Controller { + + private static double DEFAULT_MOVEMENT_SPEED = 0.0015; + private static double DEFAULT_MOUSE_SENSITIVITY = 0.006; + private double movementSpeed = DEFAULT_MOVEMENT_SPEED; + private double mouseSensitivity = DEFAULT_MOUSE_SENSITIVITY; + + private SceneObject controllableObject; + + public KeyAndMouseMovementController(SceneObject controllableObject) { + this.controllableObject = controllableObject; + } + + @Override + public void update(int delta, Input input) { + controllableObject.getTransform().setPosition(controllableObject.getTransform().position().add( + input.movementVector().multiply(movementSpeed * delta) + )); + controllableObject.getTransform().setRotation(controllableObject.getTransform().rotation().add( + input.mouseMovement().multiply(mouseSensitivity * delta) + )); + } +} diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java index efd4d63..c400875 100644 --- a/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java +++ b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java @@ -13,7 +13,6 @@ public class SceneRendererWindow extends Window { private static final int UPDATE_LOOP_DELAY = 100; // ms private static final int TARGET_FPS = 60; private static final int UPDATE_RATE = 1000/TARGET_FPS; - private static final boolean DEFAULT_CAMERA_CONTROLLABLE = false; private SceneRender render; private Scene scene; @@ -30,7 +29,6 @@ public SceneRendererWindow(SceneRender render, Scene scene) { this.scene = scene; input = new Input(); scene.getCamera().ifPresent(camera -> setRaster(camera.raster())); - scene.getSceneObjects().forEach(obj -> obj.setInput(input)); mouseController = new MouseController(input, frame); } @@ -60,7 +58,7 @@ public void run() { private void updateIteration(int delta) { this.mouseController.update(); - scene.update(delta); + scene.update(delta, input); render.render(scene); this.update(); } @@ -68,5 +66,4 @@ private void updateIteration(int delta) { private void setScene(Scene scene) { this.scene = scene; } - } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java b/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java index ecf6cc1..8554b07 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/BasicScene.java @@ -5,9 +5,12 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import labs.introtoprogramming.lab5.controllers.Controller; +import labs.introtoprogramming.lab5.gui.Input; public class BasicScene extends Scene { private List entities; + private List controllers = new ArrayList<>(); private Color background; public BasicScene(List entities, Color background) { @@ -24,8 +27,8 @@ public BasicScene() { } @Override - public void update(int delta) { - entities.forEach(obj -> obj.update(delta)); + public void update(int delta, Input input) { + controllers.forEach(controller -> controller.update(delta, input)); } @Override @@ -41,6 +44,11 @@ public List getLights() { .collect(Collectors.toList()); } + @Override + public List getControllers() { + return controllers; + } + @Override public Optional getCamera() { return entities.stream() @@ -58,4 +66,9 @@ public Color getBackgroundColor() { public void addSceneObject(SceneObject obj) { entities.add(obj); } + + @Override + public void addController(Controller controller) { + this.controllers.add(controller); + } } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java b/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java deleted file mode 100644 index 73cd247..0000000 --- a/src/main/java/labs/introtoprogramming/lab5/scene/ControllableCamera.java +++ /dev/null @@ -1,25 +0,0 @@ -package labs.introtoprogramming.lab5.scene; - -import labs.introtoprogramming.lab5.graphics.Raster; - -public class ControllableCamera extends Camera { - - private static double DEFAULT_MOVEMENT_SPEED = 0.0015; - private static double DEFAULT_MOUSE_SENSITIVITY = 0.006; - private double movementSpeed = DEFAULT_MOVEMENT_SPEED; - private double mouseSensitivity = DEFAULT_MOUSE_SENSITIVITY; - - public ControllableCamera(Raster raster, Transform transform) { - super(raster, transform); - } - - @Override - protected void update(int delta) { - getTransform().setPosition( - getTransform().position().add(getInput().movementVector().multiply(movementSpeed * delta)) - ); - getTransform().setRotation(getTransform().rotation().add( - getInput().mouseMovement().multiply(mouseSensitivity * delta) - )); - } -} diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java b/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java index e39508d..dfc6ea2 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/Scene.java @@ -4,15 +4,19 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import labs.introtoprogramming.lab5.controllers.Controller; +import labs.introtoprogramming.lab5.gui.Input; public abstract class Scene { - public abstract void update(int delta); + public abstract void update(int delta, Input input); public abstract List getSceneObjects(); public abstract List getLights(); + public abstract List getControllers(); + public abstract Optional getCamera(); abstract Color getBackgroundColor(); @@ -22,4 +26,6 @@ public abstract class Scene { public void addSceneObjects(SceneObject... obj) { Arrays.stream(obj).forEach(this::addSceneObject); } + + public abstract void addController(Controller controller); } diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java b/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java index e9e8333..1af25e1 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/SceneObject.java @@ -1,13 +1,11 @@ package labs.introtoprogramming.lab5.scene; import labs.introtoprogramming.lab5.geometry.Ray; -import labs.introtoprogramming.lab5.gui.Input; public class SceneObject { protected Transform transform; protected Mesh mesh; - protected Input input; /** * Base class of scene objects. @@ -28,8 +26,6 @@ public SceneObject() { this(new Transform(), new Mesh()); } - protected void update(int delta) {} - public Transform getTransform() { return transform; } @@ -41,12 +37,4 @@ public Mesh getMesh() { public boolean intersect(Ray ray) { return false; } - - public void setInput(Input input) { - this.input = input; - } - - protected Input getInput() { - return input; - } } diff --git a/src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java b/src/test/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseControllerTests.java similarity index 57% rename from src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java rename to src/test/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseControllerTests.java index 9a2aa92..9a5b4e8 100644 --- a/src/test/java/labs/introtoprogramming/lab5/scene/ControllableCameraTests.java +++ b/src/test/java/labs/introtoprogramming/lab5/controllers/KeyAndMouseControllerTests.java @@ -1,25 +1,27 @@ -package labs.introtoprogramming.lab5.scene; +package labs.introtoprogramming.lab5.controllers; -import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; import labs.introtoprogramming.lab5.geometry.Vector3; import labs.introtoprogramming.lab5.graphics.BufferedImageRaster; import labs.introtoprogramming.lab5.graphics.Raster; import labs.introtoprogramming.lab5.gui.Input; +import labs.introtoprogramming.lab5.scene.Camera; +import labs.introtoprogramming.lab5.scene.SceneObject; +import labs.introtoprogramming.lab5.scene.Transform; import org.junit.Test; -public class ControllableCameraTests { +public class KeyAndMouseControllerTests { @Test public void testUpdate() { Raster raster = new BufferedImageRaster(100, 100); - SceneObject camera = new ControllableCamera(raster, new Transform(Vector3.ZERO)); + SceneObject camera = new Camera(raster, new Transform(Vector3.ZERO)); + KeyAndMouseMovementController controller = new KeyAndMouseMovementController(camera); Input input = new Input(); input.setForwardKeyDown(true); input.setRightKeyDown(true); - camera.setInput(input); - camera.update(10); + controller.update(10, input); assertTrue(camera.getTransform().position().x > 0); assertTrue(camera.getTransform().position().z < 0); } diff --git a/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java b/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java index 14b863c..fefda33 100644 --- a/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java +++ b/src/test/java/labs/introtoprogramming/lab5/scene/SceneTests.java @@ -3,28 +3,31 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import labs.introtoprogramming.lab5.controllers.Controller; import labs.introtoprogramming.lab5.geometry.Vector3; +import labs.introtoprogramming.lab5.gui.Input; import labs.introtoprogramming.lab5.object.Box; import org.junit.Test; public class SceneTests { @Test - public void testSceneUpdateUpdatesObjects() { + public void testSceneUpdateUpdatesControllers() { Scene scene = new BasicScene(); - MockSceneObject obj = new MockSceneObject(); - scene.addSceneObjects(new Box(new Transform(Vector3.ZERO), 1), obj); - scene.update(10); - assertTrue(obj.updated); - assertEquals(10, obj.updatedWithDelta); + MockSceneController controller = new MockSceneController(); + scene.addSceneObjects(new Box(new Transform(Vector3.ZERO), 1)); + scene.addController(controller); + scene.update(10, new Input()); + assertTrue(controller.updated); + assertEquals(10, controller.updatedWithDelta); } - private class MockSceneObject extends SceneObject { + private class MockSceneController extends Controller { boolean updated = false; int updatedWithDelta = 0; @Override - public void update(int delta) { + public void update(int delta, Input input) { this.updated = true; this.updatedWithDelta = delta; } From 321c84d7ad18f63a6e48858cd7890e06143e1bd4 Mon Sep 17 00:00:00 2001 From: Nikita Volobuev Date: Tue, 11 Jun 2019 19:42:21 +0300 Subject: [PATCH 11/11] feat(BasicRatraycingRender): add constructors taking scene or camera --- .../introtoprogramming/lab5/gui/SceneRendererWindow.java | 3 +-- .../lab5/scene/BasicRaytracingRender.java | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java index c400875..8388086 100644 --- a/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java +++ b/src/main/java/labs/introtoprogramming/lab5/gui/SceneRendererWindow.java @@ -20,8 +20,7 @@ public class SceneRendererWindow extends Window { private Input input; public SceneRendererWindow(Scene scene) { - this(new BasicRaytracingRender(scene.getCamera().orElseThrow(NoCameraException::new).raster()), scene); - setRaster(scene.getCamera().orElseThrow(NoCameraException::new).raster()); + this(new BasicRaytracingRender(scene), scene); } public SceneRendererWindow(SceneRender render, Scene scene) { diff --git a/src/main/java/labs/introtoprogramming/lab5/scene/BasicRaytracingRender.java b/src/main/java/labs/introtoprogramming/lab5/scene/BasicRaytracingRender.java index 9ae2c15..339bece 100644 --- a/src/main/java/labs/introtoprogramming/lab5/scene/BasicRaytracingRender.java +++ b/src/main/java/labs/introtoprogramming/lab5/scene/BasicRaytracingRender.java @@ -10,6 +10,14 @@ public class BasicRaytracingRender implements SceneRender { private Raster raster; + public BasicRaytracingRender(Scene scene) { + this(scene.getCamera().orElseThrow(NoCameraException::new)); + } + + public BasicRaytracingRender(Camera camera) { + this(camera.raster()); + } + public BasicRaytracingRender(Raster raster) { this.raster = raster; }