feat(renderer): add visible area handling to rendering components for improved clipping

This commit is contained in:
extio-de
2025-12-29 18:36:43 +01:00
parent 705c6a1f5a
commit ec815b9cd7
5 changed files with 135 additions and 12 deletions

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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);
}