*/
public final Point2D centerCoordinate;
+ /**
+ * Zoom factor. The bigger the value, the more zoomed in the view is.
+ */
public final double zoom;
final BufferedImage bufferedImage;
+ /**
+ * Number of frame that is currently being rendered.
+ * Every frame has its own number.
+ */
public int frameNumber = 0;
/**
/**
* Mouse click event that needs to be processed.
+ * This event is processed only once per frame.
+ * If there are multiple objects under mouse cursor, the top-most object will receive the event.
+ * If there are no objects under mouse cursor, the event will be ignored.
+ * If there is no event, this field will be null.
+ * This field is set to null after the event is processed.
*/
- private MouseEvent mouseEvent;
+ private MouseEvent mouseEvent;
public void setMouseEvent(MouseEvent mouseEvent) {
this.mouseEvent = mouseEvent;
}
/**
- * Item that user clicked on.
+ * UI component that mouse is currently hovering over.
*/
private MouseInteractionController currentObjectUnderMouseCursor;
}
/**
- * @return <code>true</code> if view repaint is needed.
+ * @return <code>true</code> if view update is needed as a consequence of this mouse event.
*/
public boolean handlePossibleComponentMouseEvent() {
if (mouseEvent == null) return false;
package eu.svjatoslav.sixth.e3d.gui;
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.math.Vertex;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
public class UserRelativityTracker {
}
- public void analyze(final TransformsPipeline transformPipe,
+ public void analyze(final TransformsStack transformPipe,
final RenderingContext renderingContext) {
- center.transform(transformPipe, renderingContext);
+ center.calculateLocationRelativeToViewer(transformPipe, renderingContext);
if (right != null) {
- right.transform(transformPipe, renderingContext);
- down.transform(transformPipe, renderingContext);
+ right.calculateLocationRelativeToViewer(transformPipe, renderingContext);
+ down.calculateLocationRelativeToViewer(transformPipe, renderingContext);
}
}
+++ /dev/null
-/*
- * Sixth 3D engine. Author: Svjatoslav Agejenko.
- * This project is released under Creative Commons Zero (CC0) license.
- */
-package eu.svjatoslav.sixth.e3d.math;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-
-public class TransformsPipeline {
-
-
- private Transform[] transforms = new Transform[100];
-
- /**
- * The number of transforms in the pipeline.
- */
- private int transformsCount = 0;
-
- /**
- * Adds a transform to the pipeline.
- *
- * @param transform
- * The transform to add.
- */
- public void addTransform(final Transform transform) {
- transforms[transformsCount] = transform;
- transformsCount++;
- }
-
- /**
- * Clears the pipeline.
- */
- public void clear() {
- transformsCount = 0;
- }
-
- /**
- * Drops the last transform from the pipeline.
- */
- public void dropTransform() {
- transformsCount--;
- }
-
- /**
- * Transforms a point.
- *
- * @param orinigalPoint
- * Original point to transform. Original point is not modified.
- * @param transformedPoint
- * Transformed point.
- */
- public void transform(final Point3D orinigalPoint, final Point3D transformedPoint) {
-
- transformedPoint.clone(orinigalPoint);
-
- // apply transforms in reverse order
- for (int i = transformsCount - 1; i >= 0; i--)
- transforms[i].transform(transformedPoint);
- }
-}
--- /dev/null
+/*
+ * Sixth 3D engine. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+package eu.svjatoslav.sixth.e3d.math;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+
+/**
+ * <pre>
+ * It is used to store and apply transforms to points.
+ * Transforms are applied in the reverse order they were added to the pipeline.
+ *
+ * Transforms are stacked and then every point is affected by every transform in this stack.
+ * This is needed to support feature where objects in the world are attached to and are relative to each other.
+ *
+ * <b>Example:</b>
+ * There is a ship it the sea. Ship moves along the sea and every object on the ship moves with it.
+ * Inside the ship there is a car. Car moves along the ship and every object on the car moves with it.
+ *
+ * So to calculate an absolute location in the world of particular object within a car,
+ * we must take into account object location relative to the car,
+ * car location relative to the ship,
+ * and ship location relative to the world.
+ * </pre>
+ */
+public class TransformsStack {
+
+
+ /**
+ * Transforms that are currently in the pipeline.
+ * Array is used for efficiency to avoid memory allocation during the rendering
+ * because depth of the pipeline needs to change very often.
+ */
+ private final Transform[] transforms = new Transform[100];
+
+ /**
+ * The number of transforms in the pipeline.
+ */
+ private int transformsCount = 0;
+
+ /**
+ * Adds a transform to the pipeline.
+ *
+ * @param transform The transform to add.
+ */
+ public void addTransform(final Transform transform) {
+ transforms[transformsCount] = transform;
+ transformsCount++;
+ }
+
+ /**
+ * Clears the pipeline.
+ */
+ public void clear() {
+ transformsCount = 0;
+ }
+
+ /**
+ * Drops the last transform from the pipeline.
+ */
+ public void dropTransform() {
+ transformsCount--;
+ }
+
+ /**
+ * Transforms a point.
+ *
+ * @param coordinate Coordinate to be transformed into result. Original input coordinate is not modified.
+ * @param result Resulting transformed point. For efficiency reasons, result is stored into preexisting object
+ * that is passed here as an argument to avoid memory allocation.
+ */
+ public void transform(final Point3D coordinate, final Point3D result) {
+
+ result.clone(coordinate);
+
+ // Apply transforms in reverse order.
+ for (int i = transformsCount - 1; i >= 0; i--)
+ transforms[i].transform(result);
+ }
+}
/**
* Vertex coordinate relative to the viewer after transformation.
+ * Visible vertices have positive z coordinate.
+ * Viewer is located at (0, 0, 0).
*/
public Point3D transformedCoordinate;
/**
- * Vertex coordinate on screen after transformation.
+ * Vertex coordinate in pixels relative to the top left corner of the screen after transformation.
*/
public Point2D onScreenCoordinate;
+ /**
+ * The frame number when this vertex was last transformed.
+ */
private int lastTransformedFrame;
public Vertex() {
onScreenCoordinate = new Point2D();
}
+
/**
- * Transforms the coordinate.
+ * Transforms vertex coordinate to calculate its location relative to the viewer.
+ * It also calculates its location on the screen.
*
- * @param transforms The transforms pipeline.
- * @param renderContext The rendering context.
+ * @param transforms Transforms pipeline.
+ * @param renderContext Rendering context.
*/
- public void transform(final TransformsPipeline transforms,
- final RenderingContext renderContext) {
+ public void calculateLocationRelativeToViewer(final TransformsStack transforms,
+ final RenderingContext renderContext) {
if (lastTransformedFrame == renderContext.frameNumber)
return;
import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractShape;
import java.util.ArrayList;
public class ShapeCollection {
private final RenderAggregator aggregator = new RenderAggregator();
- private final TransformsPipeline transformPipe = new TransformsPipeline();
+ private final TransformsStack transformPipe = new TransformsStack();
private final List<AbstractShape> shapes = new ArrayList<>();
public synchronized void addShape(final AbstractShape shape) {
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.math.Vertex;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
import eu.svjatoslav.sixth.e3d.renderer.raster.RenderAggregator;
import java.util.concurrent.atomic.AtomicInteger;
public abstract void paint(RenderingContext renderBuffer);
@Override
- public void transform(final TransformsPipeline transforms,
+ public void transform(final TransformsStack transforms,
final RenderAggregator aggregator,
final RenderingContext renderingContext) {
boolean paint = true;
for (final Vertex geometryPoint : coordinates) {
- geometryPoint.transform(transforms, renderingContext);
+ geometryPoint.calculateLocationRelativeToViewer(transforms, renderingContext);
accumulatedZ += geometryPoint.transformedCoordinate.z;
import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.renderer.raster.RenderAggregator;
public abstract class AbstractShape {
this.mouseInteractionController = mouseInteractionController;
}
- public abstract void transform(final TransformsPipeline transforms,
+ public abstract void transform(final TransformsStack transforms,
final RenderAggregator aggregator,
final RenderingContext renderingContext);
import eu.svjatoslav.sixth.e3d.gui.UserRelativityTracker;
import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.RenderAggregator;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractShape;
* This method should be overridden by anyone wanting to customize shape
* before it is rendered.
*/
- public void beforeTransformHook(final TransformsPipeline transformPipe,
+ public void beforeTransformHook(final TransformsStack transformPipe,
final RenderingContext context) {
}
final List<AbstractShape> result = new ArrayList<>();
final Slicer slicer = new Slicer(currentSliceFactor);
- originalSubShapes.stream().filter(subShape -> subShape.isVisible()).forEach(subShape -> {
+ originalSubShapes.stream().filter(SubShape::isVisible).forEach(subShape -> {
if (subShape.getShape() instanceof TexturedPolygon)
slicer.slice((TexturedPolygon) subShape.getShape());
else
}
@Override
- public void transform(final TransformsPipeline transformPipe,
+ public void transform(final TransformsStack transformPipe,
final RenderAggregator aggregator, final RenderingContext context) {
// add current composite shape transform to the end of the transform
import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
import eu.svjatoslav.sixth.e3d.gui.TextPointer;
import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.math.TransformsPipeline;
+import eu.svjatoslav.sixth.e3d.math.TransformsStack;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.TexturedRectangle;
public class TextCanvas extends TexturedRectangle {
- // character size in world coordiates
+ // character size in world coordinates
public static final int FONT_CHAR_WIDTH = 8;
public static final int FONT_CHAR_HEIGHT = 16;
private static final String GROUP_CHARACTERS = "characters";
private final TextPointer size;
private final TextPointer cursorLocation = new TextPointer();
- CanvasCharacter lines[][];
+ CanvasCharacter[][] lines;
private RenderMode renderMode = null;
private Color backgroundColor = BLACK;
private Color foregroundColor = WHITE;
}
@Override
- public void beforeTransformHook(final TransformsPipeline transformPipe,
+ public void beforeTransformHook(final TransformsStack transformPipe,
final RenderingContext context) {
final double textRelativeSize = context.width
setRenderMode(RenderMode.CHARACTERS);
}
- public void cls() {
+ public void clear() {
for (final CanvasCharacter[] line : lines)
for (final CanvasCharacter character : line) {
character.setValue(' ');
character.setForegroundColor(color);
}
- // @Override
- // public void transform(final TransformPipe transformPipe,
- // final RenderAggregator aggregator, final RenderingContext buffer) {
- //
- // super.transform(transformPipe, aggregator, buffer);
- //
- // }
}