/*
- * Sixth 3D engine. Copyright ©2012-2018, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 3 of the GNU Lesser General Public License
- * or later as published by the Free Software Foundation.
- *
+ * Sixth 3D engine. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
*/
-
package eu.svjatoslav.sixth.e3d.gui;
-import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseClick;
+import eu.svjatoslav.sixth.e3d.geometry.Point2D;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseEvent;
import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
import java.awt.*;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
+/**
+ * Rendering context that contains all the information that is needed to render the scene.
+ */
+
public class RenderingContext {
public static final int bufferedImageType = BufferedImage.TYPE_4BYTE_ABGR;
- public final BufferedImage bufferedImage;
-
public final Graphics2D graphics;
- public final byte[] bytes;
+ /**
+ * Pixels of the rendering area.
+ * Each pixel is represented by 4 bytes: alpha, blue, green, red.
+ */
+ public final byte[] pixels;
+ /**
+ * Width of the rendering area in pixels.
+ */
public final int width;
+
+ /**
+ * Height of the rendering area in pixels.
+ */
public final int height;
- public final int xCenter;
- public final int yCenter;
+ /**
+ * Center of the screen in screen space (pixels).
+ * This is the point where (0,0) coordinate of the world space is rendered.
+ */
+ 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;
/**
- * Used to signal that actual rendering should be performed. It is useful to
- * skip rendering when we only want to detect mouse clicks intersections
- * without actually updating rendered frame.
+ * UI component that mouse is currently hovering over.
*/
- public boolean doRender = true; // TODO: make use of the variable
-
- public MouseClick mouseClick;
-
- public MouseInteractionController clickedItem;
-
- public RenderingContext(final int width, final int height,
- final RenderingContext oldContext) {
+ private MouseInteractionController objectPreviouslyUnderMouseCursor;
+ /**
+ * 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;
+ /**
+ * UI component that mouse is currently hovering over.
+ */
+ private MouseInteractionController currentObjectUnderMouseCursor;
+ public RenderingContext(final int width, final int height) {
this.width = width;
this.height = height;
-
- this.xCenter = width / 2;
- this.yCenter = height / 2;
-
+ this.centerCoordinate = new Point2D(width / 2d, height / 2d);
this.zoom = width / 3d;
bufferedImage = new BufferedImage(width, height, bufferedImageType);
final WritableRaster raster = bufferedImage.getRaster();
final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
- bytes = dbi.getData();
+ pixels = dbi.getData();
graphics = (Graphics2D) bufferedImage.getGraphics();
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
- graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
+ public void prepareForNewFrameRendering() {
+ mouseEvent = null;
+ currentObjectUnderMouseCursor = null;
+ }
- graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ public MouseEvent getMouseEvent() {
+ return mouseEvent;
+ }
- if (oldContext != null) {
- mouseClick = oldContext.mouseClick;
- clickedItem = oldContext.clickedItem;
+ public void setMouseEvent(MouseEvent mouseEvent) {
+ this.mouseEvent = mouseEvent;
+ }
+
+ /**
+ * Called when given object was detected under mouse cursor, while processing {@link #mouseEvent}.
+ * Because objects are rendered back to front. The last method caller will set the top-most object, if
+ * there are multiple objects under mouse cursor.
+ */
+ public void setCurrentObjectUnderMouseCursor(MouseInteractionController currentObjectUnderMouseCursor) {
+ this.currentObjectUnderMouseCursor = currentObjectUnderMouseCursor;
+ }
+
+ /**
+ * @return <code>true</code> if view update is needed as a consequence of this mouse event.
+ */
+ public boolean handlePossibleComponentMouseEvent() {
+ if (mouseEvent == null) return false;
+
+ boolean viewRepaintNeeded = false;
+
+ if (objectPreviouslyUnderMouseCursor != currentObjectUnderMouseCursor) {
+ // Mouse cursor has just entered or left component.
+ viewRepaintNeeded = objectPreviouslyUnderMouseCursor != null && objectPreviouslyUnderMouseCursor.mouseExited();
+ viewRepaintNeeded |= currentObjectUnderMouseCursor != null && currentObjectUnderMouseCursor.mouseEntered();
+ objectPreviouslyUnderMouseCursor = currentObjectUnderMouseCursor;
}
+
+ if (mouseEvent.button != 0 && currentObjectUnderMouseCursor != null) {
+ // Mouse button was clicked on some component.
+ viewRepaintNeeded |= currentObjectUnderMouseCursor.mouseClicked(mouseEvent.button);
+ }
+
+ return viewRepaintNeeded;
}
}