Everything that intersects the influential area will be
* resolved on the expectation that it could be scrolled into view at
* any time. The influential bounds should be large enough that the
* time between a block becoming influential and the time at which it
* is resolved is longer than the expected time by which it will be
* scrolled into view, otherwise the users will see the man behind the
* curtain.
*/
protected void computeInfluentialBounds ()
{
int infborx = 3*_vbounds.width/4;
int infbory = _vbounds.height/2;
_ibounds.setBounds(_vbounds.x-infborx, _vbounds.y-infbory,
_vbounds.width+2*infborx,
// we go extra on the height because objects
// below can influence fairly high up
_vbounds.height+3*infbory);
_vibounds.setBounds(_vbounds.x-_vbounds.width/4, _vbounds.y,
_vbounds.width+_vbounds.width/2,
_vbounds.height+infbory);
}
/**
* Returns the bounds for which all intersecting scene blocks are kept
* resolved. Do not modify the rectangle returned by this method.
*/
protected Rectangle getInfluentialBounds ()
{
return _ibounds;
}
/**
* Called by the scene block when it has started its resolution.
*/
protected void blockResolving (SceneBlock block)
{
if (_dpanel != null) {
_dpanel.resolvingBlock(block);
}
}
/**
* Called by the scene block if it has come up for resolution but is
* no longer influential.
*/
protected void blockAbandoned (SceneBlock block)
{
if (_dpanel != null) {
_dpanel.blockCleared(block);
}
}
/**
* Called by a scene block when it has completed its resolution
* process.
*/
protected void blockResolved (SceneBlock block)
{
if (_dpanel != null) {
_dpanel.resolvedBlock(block);
}
Rectangle sbounds = block.getScreenBounds();
if (!_delayRepaint && sbounds != null && sbounds.intersects(_vbounds)) {
// warnVisible(block, sbounds);
// if we have yet further blocks to resolve, queue up a
// repaint now so that we get this data onscreen as quickly as
// possible
if (_pendingBlocks > 1) {
recomputeVisible();
_remgr.invalidateRegion(sbounds);
}
}
--_pendingBlocks;
// if (_pendingBlocks == 0) {
// Log.info("Finished resolving pending blocks " +
// "[view=" + StringUtil.toString(_vbounds) + "].");
// reportMemoryUsage();
// }
// once all the visible pending blocks have completed their
// resolution, recompute our visible object set and show ourselves
if (_visiBlocks.remove(block) && _visiBlocks.size() == 0) {
recomputeVisible();
Log.info("Restoring repaint... [left=" + _pendingBlocks +
", view=" + StringUtil.toString(_vbounds) + "].");
_delayRepaint = false;
_remgr.invalidateRegion(_vbounds);
}
}
/**
* Issues a warning to the error log that the specified block became
* visible prior to being resolved. Derived classes may wish to
* augment or inhibit this warning.
*/
protected void warnVisible (SceneBlock block, Rectangle sbounds)
{
Log.warning("Block visible during resolution " + block +
" sbounds:" + StringUtil.toString(sbounds) +
" vbounds:" + StringUtil.toString(_vbounds) + ".");
}
/**
* Recomputes our set of visible objects and their tips.
*/
protected void recomputeVisible ()
{
// flush our visible object set which we'll recreate later
_vizobjs.clear();
Rectangle vbounds = new Rectangle(
_vbounds.x-_metrics.tilewid, _vbounds.y-_metrics.tilehei,
_vbounds.width+2*_metrics.tilewid,
_vbounds.height+2*_metrics.tilehei);
for (Iterator iter = _blocks.values().iterator(); iter.hasNext(); ) {
SceneBlock block = (SceneBlock)iter.next();
if (!block.isResolved()) {
continue;
}
// links this block to its neighbors; computes coverage
block.update(_blocks);
// see which of this block's objects are visible
SceneObject[] objs = block.getObjects();
for (int ii = 0; ii < objs.length; ii++) {
if (objs[ii].bounds != null &&
vbounds.intersects(objs[ii].bounds)) {
_vizobjs.add(objs[ii]);
}
}
}
// recompute our object tips
computeTips();
// Log.info("Computed " + _vizobjs.size() + " visible objects from " +
// _blocks.size() + " blocks.");
// Log.info(StringUtil.listToString(_vizobjs, new StringUtil.Formatter() {
// public String toString (Object object) {
// SceneObject scobj = (SceneObject)object;
// return (TileUtil.getTileSetId(scobj.info.tileId) + ":" +
// TileUtil.getTileIndex(scobj.info.tileId));
// }
// }));
}
/**
* Masks off the lower 16 bits of the supplied integers and composes
* them into a single int.
*/
protected static int compose (int x, int y)
{
return (x << 16) | (y & 0xFFFF);
}
/**
* Compute the tips for any objects in the scene.
*/
public void computeTips ()
{
// clear any old tips
_tips.clear();
for (int ii = 0, nn = _vizobjs.size(); ii < nn; ii++) {
SceneObject scobj = (SceneObject)_vizobjs.get(ii);
String action = scobj.info.action;
// if the object has no action, skip it
if (StringUtil.isBlank(action)) {
continue;
}
// if we have an object action handler, possibly let them veto
// the display of this tooltip and action
ObjectActionHandler oah = ObjectActionHandler.lookup(action);
if (oah != null && !oah.isVisible(action)) {
continue;
}
String tiptext = getTipText(scobj, action);
if (tiptext != null) {
Icon icon = getTipIcon(scobj, action);
SceneObjectTip tip = new SceneObjectTip(tiptext, icon);
_tips.put(scobj, tip);
}
}
_tipsLaidOut = false;
}
/**
* Derived classes can provide human readable object tips via this
* method.
*/
protected String getTipText (SceneObject scobj, String action)
{
ObjectActionHandler oah = ObjectActionHandler.lookup(action);
return (oah == null) ? action : oah.getTipText(action);
}
/**
* Provides an icon for this tooltip, the default looks up an object
* action handler for the action and requests the icon from it.
*/
protected Icon getTipIcon (SceneObject scobj, String action)
{
ObjectActionHandler oah = ObjectActionHandler.lookup(action);
return (oah == null) ? null : oah.getTipIcon(action);
}
/**
* Dirties the specified tip.
*/
protected void dirtyTip (SceneObjectTip tip)
{
if (tip != null) {
Rectangle r = tip.bounds;
if (r != null) {
_remgr.invalidateRegion(r);
}
}
}
/**
* Change the hover object to the new object.
*/
protected void changeHoverObject (Object newHover)
{
if (newHover == _hobject) {
return;
}
Object oldHover = _hobject;
_hobject = newHover;
hoverObjectChanged(oldHover, newHover);
}
/**
* A place for subclasses to react to the hover object changing.
* One of the supplied arguments may be null.
*/
protected void hoverObjectChanged (Object oldHover, Object newHover)
{
// deal with objects that care about being hovered over
if (oldHover instanceof SceneObject) {
SceneObject oldhov = (SceneObject)oldHover;
if (oldhov.setHovered(false)) {
_remgr.invalidateRegion(oldhov.bounds);
}
}
if (newHover instanceof SceneObject) {
SceneObject newhov = (SceneObject)newHover;
if (newhov.setHovered(true)) {
_remgr.invalidateRegion(newhov.bounds);
}
}
// dirty the tips associated with the hover objects
dirtyTip((SceneObjectTip)_tips.get(oldHover));
dirtyTip((SceneObjectTip)_tips.get(newHover));
}
/**
* Adds to the supplied dirty item list, all of the object tiles that
* are hit by the specified point (meaning the point is contained
* within their bounds and intersects a non-transparent pixel in the
* actual object image.
*/
protected void getHitObjects (DirtyItemList list, int x, int y)
{
for (int ii = 0, ll = _vizobjs.size(); ii < ll; ii++) {
SceneObject scobj = (SceneObject)_vizobjs.get(ii);
Rectangle pbounds = scobj.bounds;
if (!pbounds.contains(x, y)) {
continue;
}
// see if we should skip it
if (skipHitObject(scobj)) {
continue;
}
// now check that the pixel in the tile image is
// non-transparent at that point
if (!scobj.tile.hitTest(x - pbounds.x, y - pbounds.y)) {
continue;
}
// we've passed the test, add the object to the list
list.appendDirtyObject(scobj);
}
}
/**
* Determines whether we should skip the specified object when compiling
* the list of objects under a specified point using
* {@link #getHitObjects}. The default implementation returns
* true iff the object has no action.
*/
protected boolean skipHitObject (SceneObject scobj)
{
return StringUtil.isBlank(scobj.info.action);
}
/**
* Converts the supplied screen coordinates into tile coordinates,
* writing the values into the supplied {@link Point} instance and
* returning true if the screen coordinates translated into a
* different set of tile coordinates than were already contained in
* the point (so that the caller can know to update a highlight, for
* example).
*
* @return true if the tile coordinates have changed.
*/
protected boolean updateTileCoords (int sx, int sy, Point tpos)
{
Point npos = MisoUtil.screenToTile(_metrics, sx, sy, new Point());
if (!tpos.equals(npos)) {
tpos.setLocation(npos.x, npos.y);
return true;
} else {
return false;
}
}
// documentation inherited
public void paint (Graphics g)
{
if (_delayRepaint) {
return;
}
super.paint(g);
}
// documentation inherited
protected void paintInFront (Graphics2D gfx, Rectangle dirty)
{
super.paintInFront(gfx, dirty);
// paint any active menu (this should in theory check to see if
// the active menu intersects one or more of the dirty rects)
if (_activeMenu != null) {
_activeMenu.render(gfx);
}
}
// documentation inherited
protected void paintBetween (Graphics2D gfx, Rectangle dirty)
{
// render any intersecting tiles
paintTiles(gfx, dirty);
// render anything that goes on top of the tiles
paintBaseDecorations(gfx, dirty);
// render our dirty sprites and objects
paintDirtyItems(gfx, dirty);
// draw sprite paths
if (_pathsDebug.getValue()) {
_spritemgr.renderSpritePaths(gfx);
}
// paint any extra goodies
paintExtras(gfx, dirty);
}
/**
* We don't want sprites rendered using the standard mechanism because
* we intersperse them with objects in our scene and need to manage
* their z-order.
*/
protected void paintBits (Graphics2D gfx, int layer, Rectangle dirty)
{
_animmgr.paint(gfx, layer, dirty);
}
/**
* A function where derived classes can paint things after the base
* tiles have been rendered but before anything else has been rendered
* (so that whatever is painted appears to be on the ground).
*/
protected void paintBaseDecorations (Graphics2D gfx, Rectangle clip)
{
// nothing for now
}
/**
* Renders the dirty sprites and objects in the scene to the given
* graphics context.
*/
protected void paintDirtyItems (Graphics2D gfx, Rectangle clip)
{
// add any sprites impacted by the dirty rectangle
_dirtySprites.clear();
_spritemgr.getIntersectingSprites(_dirtySprites, clip);
int size = _dirtySprites.size();
for (int ii = 0; ii < size; ii++) {
Sprite sprite = (Sprite)_dirtySprites.get(ii);
Rectangle bounds = sprite.getBounds();
if (!bounds.intersects(clip)) {
continue;
}
appendDirtySprite(_dirtyItems, sprite);
// Log.info("Dirtied item: " + sprite);
}
// add any objects impacted by the dirty rectangle
for (int ii = 0, ll = _vizobjs.size(); ii < ll; ii++) {
SceneObject scobj = (SceneObject)_vizobjs.get(ii);
if (!scobj.bounds.intersects(clip)) {
continue;
}
_dirtyItems.appendDirtyObject(scobj);
// Log.info("Dirtied item: " + scobj);
}
// Log.info("paintDirtyItems [items=" + _dirtyItems.size() + "].");
// sort the dirty items so that we can paint them back-to-front
_dirtyItems.sort();
_dirtyItems.paintAndClear(gfx);
}
/**
* A function where derived classes can paint extra stuff while we've
* got the clipping region set up.
*/
protected void paintExtras (Graphics2D gfx, Rectangle clip)
{
if (isResponsive()) {
paintTips(gfx, clip);
}
}
/**
* Paint all the appropriate tips for our scene objects.
*/
protected void paintTips (Graphics2D gfx, Rectangle clip)
{
// make sure the tips are ready
if (!_tipsLaidOut) {
ArrayList boxlist = new ArrayList();
for (Iterator iter = _tips.keySet().iterator(); iter.hasNext(); ) {
SceneObject scobj = (SceneObject)iter.next();
SceneObjectTip tip = (SceneObjectTip)_tips.get(scobj);
tip.layout(gfx, scobj, _vbounds, boxlist);
boxlist.add(tip.bounds);
}
_tipsLaidOut = true;
}
if (checkShowFlag(SHOW_TIPS)) {
// show all the tips
for (Iterator iter = _tips.values().iterator(); iter.hasNext(); ) {
paintTip(gfx, clip, (SceneObjectTip)iter.next());
}
} else {
// show maybe one tip
SceneObjectTip tip = (SceneObjectTip)_tips.get(_hobject);
if (tip != null) {
paintTip(gfx, clip, tip);
}
}
}
/**
* Paint the specified tip if it intersects the clipping rectangle.
*/
protected void paintTip (Graphics2D gfx, Rectangle clip, SceneObjectTip tip)
{
if (clip.intersects(tip.bounds)) {
tip.paint(gfx);
}
}
/**
* Applies the supplied tile operation to all tiles that intersect the
* supplied screen rectangle.
*/
protected void applyToTiles (Rectangle bounds, TileOp op)
{
// determine which tiles intersect this region: this is going to
// be nearly incomprehensible without some sort of diagram; i'll
// do what i can to comment it, but you'll want to print out a
// scene diagram (docs/miso/scene.ps) and start making notes if
// you want to follow along
// obtain our upper left tile
Point tpos = MisoUtil.screenToTile(
_metrics, bounds.x, bounds.y, new Point());
// determine which quadrant of the upper left tile we occupy
Point spos = MisoUtil.tileToScreen(
_metrics, tpos.x, tpos.y, new Point());
boolean left = (bounds.x - spos.x < _metrics.tilehwid);
boolean top = (bounds.y - spos.y < _metrics.tilehhei);
// set up our tile position counters
int dx, dy;
if (left) {
dx = 0; dy = 1;
} else {
dx = 1; dy = 0;
}
// if we're in the top-half of the tile we need to move up a row,
// either forward or back depending on whether we're in the left
// or right half of the tile
if (top) {
if (left) {
tpos.x -= 1;
} else {
tpos.y -= 1;
}
// we'll need to start zig-zagging the other way as well
dx = 1 - dx;
dy = 1 - dy;
}
// these will bound our loops
int rightx = bounds.x + bounds.width,
bottomy = bounds.y + bounds.height;
// Log.info("Preparing to apply [tpos=" + StringUtil.toString(tpos) +
// ", left=" + left + ", top=" + top +
// ", bounds=" + StringUtil.toString(bounds) +
// ", spos=" + StringUtil.toString(spos) +
// "].");
// obtain the coordinates of the tile that starts the first row
// and loop through, applying to the intersecting tiles
MisoUtil.tileToScreen(_metrics, tpos.x, tpos.y, spos);
while (spos.y < bottomy) {
// set up our row counters
int tx = tpos.x, ty = tpos.y;
_tbounds.x = spos.x;
_tbounds.y = spos.y;
// Log.info("Applying to row [tx=" + tx + ", ty=" + ty + "].");
// apply to the tiles in this row
while (_tbounds.x < rightx) {
op.apply(tx, ty, _tbounds);
// move one tile to the right
tx += 1; ty -= 1;
_tbounds.x += _metrics.tilewid;
}
// update our tile coordinates
tpos.x += dx; dx = 1-dx;
tpos.y += dy; dy = 1-dy;
// obtain the screen coordinates of the next starting tile
MisoUtil.tileToScreen(_metrics, tpos.x, tpos.y, spos);
}
}
/**
* Renders the base and fringe layer tiles that intersect the
* specified clipping rectangle.
*/
protected void paintTiles (Graphics2D gfx, Rectangle clip)
{
// go through rendering our tiles
_paintOp.setGraphics(gfx);
applyToTiles(clip, _paintOp);
_paintOp.setGraphics(null);
}
/**
* Fills the specified tile with the given color at 50% alpha.
* Intended for debug-only tile highlighting purposes.
*/
protected void fillTile (
Graphics2D gfx, int tx, int ty, Color color)
{
Composite ocomp = gfx.getComposite();
gfx.setComposite(ALPHA_FILL_TILE);
Polygon poly = MisoUtil.getTilePolygon(_metrics, tx, ty);
gfx.setColor(color);
gfx.fill(poly);
gfx.setComposite(ocomp);
}
/** Returns the base tile for the specified tile coordinate. */
protected BaseTile getBaseTile (int tx, int ty)
{
SceneBlock block = getBlock(tx, ty);
return (block == null) ? null : block.getBaseTile(tx, ty);
}
/** Returns the fringe tile for the specified tile coordinate. */
protected BaseTile getFringeTile (int tx, int ty)
{
SceneBlock block = getBlock(tx, ty);
return (block == null) ? null : block.getFringeTile(tx, ty);
}
/** Computes the fringe tile for the specified coordinate. */
protected BaseTile computeFringeTile (int tx, int ty)
{
return _ctx.getTileManager().getAutoFringer().getFringeTile(
_model, tx, ty, _masks);
}
/**
* Returns true if we're responding to user input. This is used to
* control the display of tooltips and other potential user
* interactions. By default we are always responsive.
*/
protected boolean isResponsive ()
{
return true;
}
/** Used with {@link #applyToTiles}. */
protected static interface TileOp
{
public void apply (int tx, int ty, Rectangle tbounds);
}
/** Used by {@link #paintTiles}. */
protected class PaintTileOp implements TileOp
{
public void setGraphics (Graphics2D gfx) {
_gfx = gfx;
_thw = 0;
_thh = 0;
_fhei = 0;
_fm = null;
// if we're showing coordinates, we need to do some setting up
if (gfx != null && _coordsDebug.getValue()) {
_fm = gfx.getFontMetrics(_font);
_fhei = _fm.getAscent();
_thw = _metrics.tilehwid;
_thh = _metrics.tilehhei;
gfx.setFont(_font);
}
}
public void apply (int tx, int ty, Rectangle tbounds) {
// draw the base and fringe tile images
try {
Tile tile;
boolean passable = true;
if ((tile = getBaseTile(tx, ty)) != null) {
tile.paint(_gfx, tbounds.x, tbounds.y);
passable = ((BaseTile)tile).isPassable();
} else {
// draw black where there are no tiles
Polygon poly = MisoUtil.getTilePolygon(_metrics, tx, ty);
_gfx.setColor(Color.black);
_gfx.fill(poly);
}
if ((tile = getFringeTile(tx, ty)) != null) {
tile.paint(_gfx, tbounds.x, tbounds.y);
passable = passable && ((BaseTile)tile).isPassable();
}
// highlight impassable tiles
if (_traverseDebug.getValue()) {
if (!passable) {
// highlight tiles blocked by base or fringe in yellow
fillTile(_gfx, tx, ty, Color.yellow);
} else if (!canTraverse(null, tx, ty)) {
// highlight passable non-traversable tiles in green
fillTile(_gfx, tx, ty, Color.green);
}
}
} catch (ArrayIndexOutOfBoundsException e) {
Log.warning("Whoops, booched it [tx=" + tx +
", ty=" + ty + ", tb.x=" + tbounds.x + "].");
e.printStackTrace(System.err);
}
// if we're showing coordinates, do that
if (_coordsDebug.getValue()) {
// set the color according to the scene block
int bx = MathUtil.floorDiv(tx, _metrics.blockwid);
int by = MathUtil.floorDiv(ty, _metrics.blockhei);
if (((bx % 2) ^ (by % 2)) == 0) {
_gfx.setColor(Color.white);
} else {
_gfx.setColor(Color.yellow);
}
// get the top-left screen coordinates of the tile
int sx = tbounds.x, sy = tbounds.y;
// draw x-coordinate
String str = String.valueOf(tx);
int xpos = sx + _thw - (_fm.stringWidth(str) / 2);
_gfx.drawString(str, xpos, sy + _thh);
// draw y-coordinate
str = String.valueOf(ty);
xpos = sx + _thw - (_fm.stringWidth(str) / 2);
_gfx.drawString(str, xpos, sy + _thh + _fhei);
// draw the tile polygon as well
_gfx.draw(MisoUtil.getTilePolygon(_metrics, tx, ty));
}
}
protected Graphics2D _gfx;
protected FontMetrics _fm;
protected int _thw, _thh, _fhei;
protected Font _font = new Font("Arial", Font.PLAIN, 7);
}
/** Used by {@link #rethink}. */
protected class RethinkOp implements TileOp
{
public HashSet blocks = new HashSet();
public void apply (int tx, int ty, Rectangle tbounds) {
_key.x = MathUtil.floorDiv(tx, _metrics.blockwid) *
_metrics.blockwid;
_key.y = MathUtil.floorDiv(ty, _metrics.blockhei) *
_metrics.blockhei;
if (!blocks.contains(_key)) {
blocks.add(new Point(_key.x, _key.y));
}
}
protected Point _key = new Point();
}
/** Provides access to a few things. */
protected MisoContext _ctx;
/** Contains basic scene metrics like tile width and height. */
protected MisoSceneMetrics _metrics;
/** The scene model to be displayed. */
protected MisoSceneModel _model;
/** Tracks the size at which we were last "rethunk". */
protected Dimension _rsize = new Dimension();
/** Contains the tile coords of our upper-left view coord. */
protected Point _ulpos;
/** Contains the bounds of our "area of influence" in screen coords. */
protected Rectangle _ibounds = new Rectangle();
/** Contains the bounds of our visible "area of influence" in screen
* coords. */
protected Rectangle _vibounds = new Rectangle();
/** Used by {@link #rethink}. */
protected RethinkOp _rethinkOp = new RethinkOp();
/** Contains our scene blocks. See {@link #getBlock} for details. */
protected HashIntMap _blocks = new HashIntMap();
/** A count of blocks in the process of being resolved. */
protected int _pendingBlocks;
/** Used to track visible blocks that are waiting to be resolved. */
protected HashSet _visiBlocks = new HashSet();
/** Used to avoid repaints while we don't yet have resolved all the
* blocks needed to render the visible view. */
protected boolean _delayRepaint = false;
/** A list of the potentially visible objects in the scene. */
protected ArrayList _vizobjs = new ArrayList();
/** For computing fringe tiles. */
protected HashMap _masks = new HashMap();
/** The dirty sprites and objects that need to be re-painted. */
protected DirtyItemList _dirtyItems = new DirtyItemList();
/** The working sprites list used when calculating dirty regions. */
protected ArrayList _dirtySprites = new ArrayList();
/** Used when rendering tiles. */
protected Rectangle _tbounds;
/** Used to paint tiles. */
protected PaintTileOp _paintOp = new PaintTileOp();
/** Temporary point used for intermediate calculations. */
protected Point _tcoords = new Point();
/** Used to collect the list of sprites "hit" by a particular mouse
* location. */
protected List _hitSprites = new ArrayList();
/** The list that we use to track and sort the items over which the
* mouse is hovering. */
protected DirtyItemList _hitList = new DirtyItemList();
/** Info on the object that the mouse is currently hovering over. */
protected Object _hobject;
/** The item that the user has clicked on with the mouse. */
protected Object _armedItem = null;
/** The active radial menu (or null). */
protected RadialMenu _activeMenu;
/** Used to track the tile coordinates over which the mouse is hovering. */
protected Point _hcoords = new Point();
/** Our object tips, indexed by the object that they tip for. */
protected HashMap _tips = new HashMap();
/** Have the tips been laid out? */
protected boolean _tipsLaidOut = false;
/** Flags indicating which features we should show in the scene. */
protected int _showFlags = 0;
/** A scene block resolver shared by all scene panels. */
protected static SceneBlockResolver _resolver;
// used to display debugging information on scene block resolution
protected JFrame _dframe;
protected ResolutionView _dpanel;
/** A debug hook that toggles debug rendering of traversable tiles. */
protected static RuntimeAdjust.BooleanAdjust _traverseDebug =
new RuntimeAdjust.BooleanAdjust(
"Toggles debug rendering of traversable and impassable tiles in " +
"the iso scene view.", "narya.miso.iso_traverse_debug_render",
MisoPrefs.config, false);
/** A debug hook that toggles debug rendering of tile coordinates. */
protected static RuntimeAdjust.BooleanAdjust _coordsDebug =
new RuntimeAdjust.BooleanAdjust(
"Toggles debug rendering of tile coordinates in the iso scene " +
"view.", "narya.miso.iso_coords_debug_render",
MisoPrefs.config, false);
/** A debug hook that toggles debug rendering of sprite paths. */
protected static RuntimeAdjust.BooleanAdjust _pathsDebug =
new RuntimeAdjust.BooleanAdjust(
"Toggles debug rendering of sprite paths in the iso scene view.",
"narya.miso.iso_paths_debug_render", MisoPrefs.config, false);
/** A debug hook that toggles the block resolution display. */
protected static RuntimeAdjust.BooleanAdjust _resolveDebug =
new RuntimeAdjust.BooleanAdjust(
"Enables a view displaying the status of scene block resolution.",
"narya.miso.iso_paths_debug_resolve", MisoPrefs.config, false);
/** The stroke used to draw dirty rectangles. */
protected static final Stroke DIRTY_RECT_STROKE = new BasicStroke(2);
/** The alpha used to fill tiles for debugging purposes. */
protected static final Composite ALPHA_FILL_TILE =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
/** The default size of the "box" that defines the size of our radial
* menu circles. */
protected static final Dimension DEF_RADIAL_RECT = new Dimension(80, 80);
}