Skip to content

Commit

Permalink
Moved some constants to ZoneRendererConstants
Browse files Browse the repository at this point in the history
Moved utility methods, fogExtents() and  zoneExtents(PlayerView view) to ExportDialog as it was the only place they were used.
Created ZoneCompositor which will take on the role of determining what to draw.
Added ZoneCompositor to ZR constructor
Changed get and restore antialiasing to RenderingHints
  • Loading branch information
bubblobill committed Nov 23, 2023
1 parent c709279 commit 4938b03
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@
import net.rptools.maptool.client.ui.zone.PlayerView;
import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer;
import net.rptools.maptool.language.I18N;
import net.rptools.maptool.model.Token;
import net.rptools.maptool.model.Zone;
import net.rptools.maptool.model.drawing.DrawablePaint;
import net.rptools.maptool.model.drawing.DrawableTexturePaint;
import net.rptools.maptool.model.drawing.*;
import net.rptools.maptool.model.player.Player;
import net.rptools.maptool.util.ImageManager;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -776,7 +776,7 @@ private PlayerView preScreenshot() throws Exception, OutOfMemoryError {
//
Player.Role viewRole = viewAsPlayer ? Player.Role.PLAYER : Player.Role.GM;
PlayerView view = renderer.getPlayerView(viewRole, false);
Rectangle extents = renderer.zoneExtents(view);
Rectangle extents = zoneExtents(view);
try {
// Clip to what the players know about (if applicable).
// This keeps the player from exporting the map to learn which
Expand Down Expand Up @@ -842,6 +842,125 @@ private PlayerView preScreenshot() throws Exception, OutOfMemoryError {
waitingForPostScreenshot = true;
return view;
}
public Rectangle fogExtents() {
return zone.getExposedArea().getBounds();
}
/**
* Get a bounding box, in Zone coordinates, of all the elements in the zone. This method was
* created by copying renderZone() and then replacing each bit of rendering with a routine to
* simply aggregate the extents of the object that would have been rendered.
*
* @param view the player view
* @return a new Rectangle with the bounding box of all the elements in the Zone
*/
public Rectangle zoneExtents(PlayerView view) {
// Can't initialize extents to any set x/y values, because
// we don't know if the actual map contains that x/y.
// So we need a flag to say extents is 'unset', and the best I
// could come up with is checking for 'null' on each loop iteration.
Rectangle extents = null;

// We don't iterate over the layers in the same order as rendering
// because its cleaner to group them by type and the order doesn't matter.

// First background image extents
// TODO: when the background image can be resized, fix this!
if (zone.getMapAssetId() != null) {
extents =
new Rectangle(
zone.getBoardX(),
zone.getBoardY(),
ImageManager.getImage(zone.getMapAssetId(), this).getWidth(),
ImageManager.getImage(zone.getMapAssetId(), this).getHeight());
}
// next, extents of drawing objects
List<DrawnElement> drawableList = zone.getAllDrawnElements();
for (DrawnElement element : drawableList) {
if (!view.isGMView() && !element.getDrawable().getLayer().isVisibleToPlayers()) {
continue;
}

Drawable drawable = element.getDrawable();
Rectangle drawnBounds = new Rectangle(drawable.getBounds());

// Handle pen size
// This slightly over-estimates the size of the pen, but we want to
// make sure to include the anti-aliased edges.
Pen pen = element.getPen();
int penSize = (int) Math.ceil((pen.getThickness() / 2) + 1);
drawnBounds.setBounds(
drawnBounds.x - penSize,
drawnBounds.y - penSize,
drawnBounds.width + (penSize * 2),
drawnBounds.height + (penSize * 2));

if (extents == null) {
extents = drawnBounds;
} else {
extents.add(drawnBounds);
}
}
// now, add the stamps/tokens
// tokens and stamps are the same thing, just treated differently

// Note: order doesn't matter, so don't need to go back-to-front.
for (Token element :
zone.getTokensForLayers(layer -> view.isGMView() || layer.isVisibleToPlayers())) {
Rectangle drawnBounds = element.getBounds(zone);
if (element.hasFacing()) {
// Get the facing and do a quick fix to make the math easier: -90 is 'unrotated' for some
// reason
int facing = element.getFacing() + 90;
if (facing > 180) {
facing -= 360;
}
// if 90 degrees, just swap w and h
// also swap them if rotated more than 90 (optimization for non-90deg rotations)
if (facing != 0 && facing != 180) {
if (Math.abs(facing) >= 90) {
drawnBounds.setSize(drawnBounds.height, drawnBounds.width); // swapping h and w
}
// if rotated to non-axis direction, assume the worst case 45 deg
// also assumes the rectangle rotates around its center
// This will usually make the bounds bigger than necessary, but its quick.
// Also, for quickness, we assume its a square token using the larger dimension
// At 45 deg, the bounds of the square will be sqrt(2) bigger, and the UL corner will
// shift by 1/2 of the length.
// The size increase is: (sqrt*(2) - 1) * size ~= 0.42 * size.
if (facing != 0 && facing != 180 && facing != 90 && facing != -90) {
int size = Math.max(drawnBounds.width, drawnBounds.height);
int x = drawnBounds.x - (int) (0.21 * size);
int y = drawnBounds.y - (int) (0.21 * size);
int w = drawnBounds.width + (int) (0.42 * size);
int h = drawnBounds.height + (int) (0.42 * size);
drawnBounds.setBounds(x, y, w, h);
}
}
}
// TODO: Handle auras here?
if (extents == null) {
extents = drawnBounds;
} else {
extents.add(drawnBounds);
}
}
if (zone.hasFog()) {
if (extents == null) {
extents = fogExtents();
} else {
extents.add(fogExtents());
}
}
// TODO: What are token templates?
// renderTokenTemplates(g2d, view);

// TODO: Do lights make the area of interest larger?
// see: renderLights(g2d, view);

// TODO: Do auras make the area of interest larger?
// see: renderAuras(g2d, view);
return extents;
}

private void postScreenshot() {
assert waitingForPostScreenshot : "postScrenshot called without preScreenshot";
Expand Down Expand Up @@ -909,4 +1028,4 @@ public void thumbnailProgress(ImageWriter source, float percentageDone) {}
public void thumbnailComplete(ImageWriter source) {}

public void writeAborted(ImageWriter source) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* This software Copyright by the RPTools.net development team, and
* licensed under the Affero GPL Version 3 or, at your option, any later
* version.
*
* MapTool Source Code is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public
* License * along with this source Code. If not, please visit
* <http://www.gnu.org/licenses/> and specifically the Affero license
* text at <http://www.gnu.org/licenses/agpl.html>.
*/
package net.rptools.maptool.client.ui.zone.renderer;

import java.awt.geom.Rectangle2D;
import java.util.*;
import net.rptools.maptool.model.Token;
import net.rptools.maptool.model.Zone;

/**
* The Zone Compositor is responsible for providing the Zone Renderer with what needs to be
* rendered. Within a given map region what objects exist that need to be drawn. Basically "What's
* on screen?"
*/
public class ZoneCompositor {
Zone zone;
ZoneRenderer renderer;
private Map<Token, Set<Token>> objectCache; // placeholder
private boolean initialised;

ZoneCompositor() {
initialised = false;
}

public boolean isInitialised() {
return initialised;
}

public void setRenderer(ZoneRenderer zoneRenderer) {
renderer = zoneRenderer;
zone = renderer.getZone();
initialised = true;
}

protected Map<Token, Set<Token>> drawWhat(Rectangle2D bounds) {
// Some logic goes here
return objectCache;
}


}
Loading

0 comments on commit 4938b03

Please sign in to comment.