Fix copyArea to work with zoom

This commit is contained in:
fourbites
2025-08-27 17:19:10 +02:00
parent 5bc8ff224c
commit 45afe38ccc
@@ -187,6 +187,7 @@ public class VirtualMediaPanel extends MediaPanel
{
// translate the screen rect into happy coordinates
rect.translate(_nx, _ny);
rect = _zoomManager.scaleOnCenter(rect);
_metamgr.getRegionManager().addDirtyRegion(rect);
}
@@ -220,7 +221,7 @@ public class VirtualMediaPanel extends MediaPanel
{
// Adjust for any scrolling we're currently doing.
super.addObscurerDirtyRegion(
new Rectangle(region.x - _dx, region.y - _dy, region.width, region.height));
new Rectangle(region.x - (int) _dx, region.y - (int) _dy, region.width, region.height));
}
/**
@@ -266,13 +267,13 @@ public class VirtualMediaPanel extends MediaPanel
// "), d=(" + dx + ", " + dy +
// "), width=" + width + ", height=" + height + "].");
_dx = dx;
_dy = dy;
_dx += dx * getZoomLevel();
_dy += dy * getZoomLevel();
// now go ahead and update our location so that changes in between here and the call
// to paint() for this tick don't booch everything
_vbounds.x += _dx;
_vbounds.y += _dy;
_vbounds.x += dx;
_vbounds.y += dy;
// these are used to prevent the vertical strip from
// overlapping the horizontal strip
@@ -287,7 +288,9 @@ public class VirtualMediaPanel extends MediaPanel
_metamgr.getRegionManager().invalidateRegion(_vbounds.x, _vbounds.y, width, -dy);
}
if (dx > 0) {
_metamgr.getRegionManager().invalidateRegion(_vbounds.x + width - dx, sy, dx, shei);
// zoom rounding errors make it so we need to account for potential off-by-one errors
int dx2 = dx + 1;
_metamgr.getRegionManager().invalidateRegion(_vbounds.x + width - dx2, sy, dx2, shei);
} else if (dx < 0) {
_metamgr.getRegionManager().invalidateRegion(_vbounds.x, sy, -dx, shei);
}
@@ -371,21 +374,12 @@ public class VirtualMediaPanel extends MediaPanel
@Override
protected void paint (Graphics2D gfx, Rectangle[] dirty)
{
// if we zoom too quickly, the zoomManager scale may not be in sync with the paint tick
// so we check based on the actual view bounds to be safe
double scale = getWidth() / (double) _vbounds.width;
if (scale != 1.0) {
// if our scale is not 1.0, we can't rely on copyArea(). it doesn't support non integer
// movements, so it will cause an unpleasant stutter as the rounding errors accumulate.
// TODO?: keep track of movement over multiple frames to cancel out the rounding errors.
dirty = new Rectangle[]{_vbounds};
// if we're scrolling, go ahead and do the business
} else if (_dx != 0 || _dy != 0) {
int dx = (int) Math.round(_dx);
int dy = (int) Math.round(_dy);
if (dx != 0 || dy != 0) {
int width = getWidth(), height = getHeight();
int cx = (_dx > 0) ? _dx : 0;
int cy = (_dy > 0) ? _dy : 0;
int cx = (dx > 0) ? dx : 0;
int cy = (dy > 0) ? dy : 0;
// set the clip to the bounds of the component (we can't assume the clip is anything
// sensible upon entry to paint() because the frame manager expects us to set our own
@@ -398,14 +392,14 @@ public class VirtualMediaPanel extends MediaPanel
if (RunAnywhere.isWindows()) {
gfx.translate(-_abounds.x, -_abounds.y);
gfx.copyArea(_abounds.x + cx, _abounds.y + cy,
width - Math.abs(_dx),
height - Math.abs(_dy), -_dx, -_dy);
width - Math.abs(dx),
height - Math.abs(dy), -dx, -dy);
gfx.translate(_abounds.x, _abounds.y);
} else if (RunAnywhere.isMacOS()) {
try {
gfx.copyArea(cx, cy,
width - Math.abs(_dx),
height - Math.abs(_dy), -_dx, -_dy);
width - Math.abs(dx),
height - Math.abs(dy), -dx, -dy);
} catch (Exception e) {
// HACK when it throws an exception trying to do the copy area, just repaint
// everything
@@ -413,12 +407,13 @@ public class VirtualMediaPanel extends MediaPanel
}
} else {
gfx.copyArea(cx, cy,
width - Math.abs(_dx),
height - Math.abs(_dy), -_dx, -_dy);
width - Math.abs(dx),
height - Math.abs(dy), -dx, -dy);
}
// and clear out our scroll deltas
_dx = 0; _dy = 0;
_dx -= dx;
_dy -= dy;
}
AffineTransform originalTransform = gfx.getTransform();
@@ -426,6 +421,10 @@ public class VirtualMediaPanel extends MediaPanel
int centerX = _vbounds.x + _vbounds.width / 2;
int centerY = _vbounds.y + _vbounds.height / 2;
// if we zoom too quickly, the zoomManager scale may not be in sync with the paint tick
// so we check based on the actual view bounds to be safe
double scale = getWidth() / (double) _vbounds.width;
// translate into happy space
gfx.translate(getWidth() / 2, getHeight() / 2);
gfx.scale(scale, scale);
@@ -499,8 +498,10 @@ public class VirtualMediaPanel extends MediaPanel
/** Our target offsets to be effected on the next tick. */
protected int _nx, _ny;
/** Our scroll offsets. */
protected int _dx, _dy;
/**
* Our scroll offsets in real pixels.
*/
protected double _dx, _dy;
/** Our tiling background image. */
protected Mirage _background;