diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawImage.java b/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawImage.java index 7c52c0f..4e66c44 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawImage.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/bo/rendering/G2DDrawImage.java @@ -20,6 +20,9 @@ import de.extio.game_engine.renderer.model.RenderingBo; import de.extio.game_engine.renderer.model.RenderingBoLayer; import de.extio.game_engine.renderer.model.bo.DrawImageRenderingBo; import de.extio.game_engine.resource.StaticResource; +import de.extio.game_engine.spatial2.SpatialUtils2; +import de.extio.game_engine.spatial2.model.Area2; +import de.extio.game_engine.spatial2.model.ImmutableCoordI2; @Conditional(G2DRendererCondition.class) @Component @@ -172,7 +175,8 @@ public class G2DDrawImage extends G2DAbstractRenderingBo implements DrawImageRen } private void doDraw(final Graphics2D graphics, final CachedImage cachedImage, final double scaleFactor) { - int x, y; + int x, y, w, h; + final int visX, visY, visW, visH; if (this.scaledX != 0 || this.scaledY != 0) { x = this.scaledX; y = this.scaledY; @@ -181,12 +185,48 @@ public class G2DDrawImage extends G2DAbstractRenderingBo implements DrawImageRen x = (int) (this.x * scaleFactor); y = (int) (this.y * scaleFactor); } - - if (this.width == 0 && this.height == 0) { + w = (int) ((this.width > 0 ? this.width : cachedImage.getImage().getWidth()) * scaleFactor); + h = (int) ((this.height > 0 ? this.height : cachedImage.getImage().getHeight()) * scaleFactor); + visX = (int) (this.visibleAreaX * scaleFactor); + visY = (int) (this.visibleAreaY * scaleFactor); + visW = (int) (this.visibleAreaWidth * scaleFactor); + visH = (int) (this.visibleAreaHeight * scaleFactor); + + Area2 intersection = null; + if (visX != 0 || visY != 0 || visW != 0 || visH != 0) { + final var controlArea = new Area2(ImmutableCoordI2.create(x, y), ImmutableCoordI2.create(w, h)); + final var visibleArea = new Area2(ImmutableCoordI2.create(visX, visY), ImmutableCoordI2.create(visW, visH)); + intersection = SpatialUtils2.intersectAreas(controlArea, visibleArea); + if (intersection == null) { + return; + } + } + + if (intersection != null) { + try { + final double dstPerSrcX = (double) w / (double) cachedImage.getImage().getWidth(); + final double dstPerSrcY = (double) h / (double) cachedImage.getImage().getHeight(); + graphics.drawImage( + cachedImage.getImage(), + intersection.getPosition().getX(), + intersection.getPosition().getY(), + intersection.getPosition().getX() + intersection.getDimension().getX(), + intersection.getPosition().getY() + intersection.getDimension().getY(), + Math.max(0, Math.min(cachedImage.getImage().getWidth(), (int) Math.round((intersection.getPosition().getX() - x) / dstPerSrcX))), + Math.max(0, Math.min(cachedImage.getImage().getHeight(), (int) Math.round((intersection.getPosition().getY() - y) / dstPerSrcY))), + Math.max(0, Math.min(cachedImage.getImage().getWidth(), (int) Math.round((intersection.getPosition().getX() - x + intersection.getDimension().getX()) / dstPerSrcX))), + Math.max(0, Math.min(cachedImage.getImage().getHeight(), (int) Math.round((intersection.getPosition().getY() - y + intersection.getDimension().getY()) / dstPerSrcY))), + null); + } + catch (final Exception e) { + LOGGER.error("Error drawing image '" + cachedImage.getName() + "': " + e.getMessage(), e); + } + } + else if (this.width == 0 && this.height == 0) { graphics.drawImage(cachedImage.getImage(), x, y, null); } else { - graphics.drawImage(cachedImage.getImage(), x, y, (int) (this.width * scaleFactor), (int) (this.height * scaleFactor), null); + graphics.drawImage(cachedImage.getImage(), x, y, w, h, null); } } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java index 721308f..da05b5b 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java @@ -30,6 +30,9 @@ import de.extio.game_engine.renderer.model.RenderingBoLayer; import de.extio.game_engine.renderer.model.bo.ControlRenderingBo; import de.extio.game_engine.renderer.model.bo.HorizontalAlignment; import de.extio.game_engine.resource.StaticResource; +import de.extio.game_engine.spatial2.SpatialUtils2; +import de.extio.game_engine.spatial2.model.Area2; +import de.extio.game_engine.spatial2.model.ImmutableCoordI2; import de.extio.game_engine.renderer.model.color.RgbaColor; @Conditional(G2DRendererCondition.class) @@ -136,6 +139,15 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen @Override public void render(final Graphics2D graphics, final double scaleFactor, final boolean force) { + if (visibleAreaX != 0 || visibleAreaY != 0 || visibleAreaWidth != 0 || visibleAreaHeight != 0) { + final var controlArea = new Area2(ImmutableCoordI2.create(this.x, this.y), ImmutableCoordI2.create(this.width, this.height)); + final var visibleArea = new Area2(ImmutableCoordI2.create(this.visibleAreaX, this.visibleAreaY), ImmutableCoordI2.create(this.visibleAreaWidth, this.visibleAreaHeight)); + final var intersection = SpatialUtils2.intersectAreas(controlArea, visibleArea); + if (intersection == null) { + return; + } + } + var control = (G2DBaseControlImpl) CACHED_CONTROLS.get(this.id); if (control == null) { if (this.clazz == ButtonControl.class) { @@ -173,7 +185,8 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen control = new G2DTooltipControl(); } else if (this.clazz == null) { - throw new IllegalArgumentException("G2DDrawControl: control type not specified"); + LOGGER.warn("G2DDrawControl: control type not specified for control id {}", this.id); + return; } else { throw new UnsupportedOperationException("Not implemented " + this.clazz.getName()); @@ -203,7 +216,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen LOGGER.debug("Added control " + control.toString()); } - + this.setControlProps(control, scaleFactor); control.setMainFrameGraphics(graphics); control.setInUse(true); @@ -224,6 +237,11 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen control.setTooltip(this.tooltip); control.setZIndex(this.zIndex); control.setLayer(this.layer); + control.setVisibleArea( + (int) (this.visibleAreaX * scaleFactor), + (int) (this.visibleAreaY * scaleFactor), + (int) (this.visibleAreaWidth * scaleFactor), + (int) (this.visibleAreaHeight * scaleFactor)); if (this.clazz == LabelControl.class) { ((LabelControl) control).setForegroundColor(this.color); @@ -311,11 +329,11 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen } } } - + @Override public void apply(final RenderingBo other) { super.apply(other); - + if (other instanceof final G2DDrawControl o) { this.id = o.id; this.clazz = o.clazz; diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DBaseControlImpl.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DBaseControlImpl.java index 4d58761..519e440 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DBaseControlImpl.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DBaseControlImpl.java @@ -17,6 +17,7 @@ import de.extio.game_engine.renderer.g2d.control.G2DDrawControlTooltip.TooltipRe import de.extio.game_engine.renderer.model.RenderingBoLayer; import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.BaseControl; import de.extio.game_engine.spatial2.SpatialUtils2; +import de.extio.game_engine.spatial2.model.Area2; import de.extio.game_engine.spatial2.model.CoordI2; import de.extio.game_engine.spatial2.model.ImmutableCoordI2; @@ -36,6 +37,14 @@ public abstract class G2DBaseControlImpl implements BaseControl { protected int fontSize; + protected int visibleAreaX; + + protected int visibleAreaY; + + protected int visibleAreaWidth; + + protected int visibleAreaHeight; + protected Graphics2D mainFrameGraphics; protected RendererData rendererData; @@ -67,7 +76,7 @@ public abstract class G2DBaseControlImpl implements BaseControl { protected short layer; protected boolean modified; - + protected boolean positionModified; @Override @@ -192,11 +201,41 @@ public abstract class G2DBaseControlImpl implements BaseControl { return this; } + public G2DBaseControlImpl setVisibleArea(final int x, final int y, final int width, final int height) { + this.modified |= this.visibleAreaX != x || this.visibleAreaY != y || this.visibleAreaWidth != width || this.visibleAreaHeight != height; + this.visibleAreaX = x; + this.visibleAreaY = y; + this.visibleAreaWidth = width; + this.visibleAreaHeight = height; + return this; + } + @Override public void render() { if (this.visible && this.bufferedImage != null) { - this.mainFrameGraphics.drawImage(this.bufferedImage, this.x, this.y, null); - this.drawToolTip(); + if (this.visibleAreaX == 0 && this.visibleAreaY == 0 && this.visibleAreaWidth == 0 && this.visibleAreaHeight == 0) { + this.mainFrameGraphics.drawImage(this.bufferedImage, this.x, this.y, null); + this.drawToolTip(); + } + else { + final var controlArea = new Area2(ImmutableCoordI2.create(this.x, this.y), ImmutableCoordI2.create(this.width, this.height)); + final var visibleArea = new Area2(ImmutableCoordI2.create(this.visibleAreaX, this.visibleAreaY), ImmutableCoordI2.create(this.visibleAreaWidth, this.visibleAreaHeight)); + final var intersection = SpatialUtils2.intersectAreas(controlArea, visibleArea); + if (intersection != null) { + this.mainFrameGraphics.drawImage( + this.bufferedImage, + intersection.getPosition().getX(), + intersection.getPosition().getY(), + intersection.getPosition().getX() + intersection.getDimension().getX(), + intersection.getPosition().getY() + intersection.getDimension().getY(), + intersection.getPosition().getX() - this.x, + intersection.getPosition().getY() - this.y, + intersection.getPosition().getX() - this.x + intersection.getDimension().getX(), + intersection.getPosition().getY() - this.y + intersection.getDimension().getY(), + null); + this.drawToolTip(); + } + } } if (this.modified) { diff --git a/src/main/java/de/extio/game_engine/renderer/model/AbstractRenderingBo.java b/src/main/java/de/extio/game_engine/renderer/model/AbstractRenderingBo.java index b319c8d..7b86a5e 100644 --- a/src/main/java/de/extio/game_engine/renderer/model/AbstractRenderingBo.java +++ b/src/main/java/de/extio/game_engine/renderer/model/AbstractRenderingBo.java @@ -28,6 +28,14 @@ public abstract class AbstractRenderingBo implements RenderingBo { protected int width; protected int height; + + protected int visibleAreaX; + + protected int visibleAreaY; + + protected int visibleAreaWidth; + + protected int visibleAreaHeight; protected short layer; @@ -214,6 +222,14 @@ public abstract class AbstractRenderingBo implements RenderingBo { return (RenderingBoHasDimension) this; } + + public RenderingBoHasDimension withVisibleArea(final int x, final int y, final int width, final int height) { + this.visibleAreaX = x; + this.visibleAreaY = y; + this.visibleAreaWidth = width; + this.visibleAreaHeight = height; + return (RenderingBoHasDimension) this; + } @Override public void close() throws Exception { @@ -227,6 +243,10 @@ public abstract class AbstractRenderingBo implements RenderingBo { this.height = 0; this.layer = this.defaultLayer; this.zIndex = 0; + this.visibleAreaX = 0; + this.visibleAreaY = 0; + this.visibleAreaWidth = 0; + this.visibleAreaHeight = 0; } @Override @@ -242,6 +262,10 @@ public abstract class AbstractRenderingBo implements RenderingBo { this.height = abstractRenderingBo.height; this.layer = abstractRenderingBo.layer; this.zIndex = abstractRenderingBo.zIndex; + this.visibleAreaX = abstractRenderingBo.visibleAreaX; + this.visibleAreaY = abstractRenderingBo.visibleAreaY; + this.visibleAreaWidth = abstractRenderingBo.visibleAreaWidth; + this.visibleAreaHeight = abstractRenderingBo.visibleAreaHeight; } } diff --git a/src/main/java/de/extio/game_engine/renderer/model/RenderingBoHasDimension.java b/src/main/java/de/extio/game_engine/renderer/model/RenderingBoHasDimension.java index 2bf5ae6..73921ca 100644 --- a/src/main/java/de/extio/game_engine/renderer/model/RenderingBoHasDimension.java +++ b/src/main/java/de/extio/game_engine/renderer/model/RenderingBoHasDimension.java @@ -14,7 +14,7 @@ public interface RenderingBoHasDimension extends RenderingBo { RenderingBoHasDimension withDimensionAbsolute(HasPosition2 dim); RenderingBoHasDimension withDimensionAbsolute(int width, int height); - + /** * @param width Range 0.0 (No width) to 1.0 (Viewport width) * @param height Range 0.0 (No height) to 1.0 (Viewport height) @@ -26,4 +26,6 @@ public interface RenderingBoHasDimension extends RenderingBo { RenderingBoHasDimension withDimensionIncrementalAbsolute(int width, int height); RenderingBoHasDimension withDimensionIncrementalPercentual(double width, double height); + + RenderingBoHasDimension withVisibleArea(int x, int y, int width, int height); }