Break SceneBlock and RethinkOp out of MisoScenePanel so the blocks in a visible region can be resolved without an underlying panel
git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@512 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -99,15 +99,14 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
super(ctx.getFrameManager());
|
||||
_ctx = ctx;
|
||||
_metrics = metrics;
|
||||
_rethinkOp = new RethinkOp(_metrics);
|
||||
_applicator = new TileOpApplicator(_metrics);
|
||||
|
||||
// set ourselves up
|
||||
setOpaque(true);
|
||||
addMouseListener(this);
|
||||
addMouseMotionListener(this);
|
||||
|
||||
// handy rectangle
|
||||
_tbounds = new Rectangle(0, 0, _metrics.tilewid, _metrics.tilehei);
|
||||
|
||||
// create the resolver if it's not already around
|
||||
if (_resolver == null) {
|
||||
_resolver = new SceneBlockResolver();
|
||||
@@ -803,7 +802,7 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
}
|
||||
|
||||
// compute the intersecting set of blocks
|
||||
applyToTiles(_ibounds, _rethinkOp);
|
||||
_applicator.applyToTiles(_ibounds, _rethinkOp);
|
||||
// Log.info("Influential blocks " +
|
||||
// StringUtil.toString(_rethinkOp.blocks) + ".");
|
||||
|
||||
@@ -852,34 +851,39 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
log.debug("Rethunk [pending=" + _pendingBlocks + ", visible=" + _visiBlocks.size() + "].");
|
||||
return _visiBlocks.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during the {@link #rethink} process, configures {@link
|
||||
* #_ibounds} to contain the bounds of the potentially "influential"
|
||||
* world and {@link #_vibounds} to contain bounds that are used to
|
||||
* determine which blocks should be resolved before making the view
|
||||
* visible.
|
||||
*
|
||||
* <p> 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.
|
||||
* Calls through to {@link #computeInfluentialBounds(Rectangle, Rectangle, Rectangle)} with
|
||||
* _vbounds, _ibounds and _vibounds.
|
||||
*/
|
||||
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);
|
||||
computeInfluentialBounds(_vbounds, _ibounds, _vibounds);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures <code>influentialBounds</code> to contain the bounds of the potentially
|
||||
* "influential" world and <code>visibleBlockBounds</code> to contain bounds that are used to
|
||||
* determine which blocks should be resolved before making the view visible.
|
||||
*
|
||||
* <p> 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.
|
||||
*/
|
||||
public static void computeInfluentialBounds (Rectangle visibleBounds,
|
||||
Rectangle influentualBounds, Rectangle visibleBlockBounds)
|
||||
{
|
||||
int infborx = 3 * visibleBounds.width / 4;
|
||||
int infbory = visibleBounds.height / 2;
|
||||
// we go extra on the height because objects below can influence fairly high up
|
||||
influentualBounds.setBounds(visibleBounds.x - infborx, visibleBounds.y - infbory,
|
||||
visibleBounds.width + 2 * infborx, visibleBounds.height + 3 * infbory);
|
||||
visibleBlockBounds.setBounds(visibleBounds.x - visibleBounds.width / 4,
|
||||
visibleBounds.y, visibleBounds.width + visibleBounds.width / 2,
|
||||
visibleBounds.height + infbory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1357,87 +1361,6 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -1446,7 +1369,7 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
{
|
||||
// go through rendering our tiles
|
||||
_paintOp.setGraphics(gfx);
|
||||
applyToTiles(clip, _paintOp);
|
||||
_applicator.applyToTiles(clip, _paintOp);
|
||||
_paintOp.setGraphics(null);
|
||||
}
|
||||
|
||||
@@ -1482,26 +1405,18 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
/** Computes the fringe tile for the specified coordinate. */
|
||||
protected BaseTile computeFringeTile (int tx, int ty)
|
||||
{
|
||||
return _ctx.getTileManager().getAutoFringer().getFringeTile(
|
||||
_model, tx, ty, _masks);
|
||||
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.
|
||||
* 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
|
||||
{
|
||||
@@ -1597,24 +1512,6 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
protected Font _font = new Font("Arial", Font.PLAIN, 7);
|
||||
}
|
||||
|
||||
/** Used by {@link #rethink}. */
|
||||
protected class RethinkOp implements TileOp
|
||||
{
|
||||
public Set<Point> blocks = Sets.newHashSet();
|
||||
|
||||
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;
|
||||
|
||||
@@ -1638,7 +1535,7 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
protected Rectangle _vibounds = new Rectangle();
|
||||
|
||||
/** Used by {@link #rethink}. */
|
||||
protected RethinkOp _rethinkOp = new RethinkOp();
|
||||
protected RethinkOp _rethinkOp;
|
||||
|
||||
/** Contains our scene blocks. See {@link #getBlock} for details. */
|
||||
protected HashIntMap<SceneBlock> _blocks = new HashIntMap<SceneBlock>();
|
||||
@@ -1665,9 +1562,6 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
/** The working sprites list used when calculating dirty regions. */
|
||||
protected List<Sprite> _dirtySprites = Lists.newArrayList();
|
||||
|
||||
/** Used when rendering tiles. */
|
||||
protected Rectangle _tbounds;
|
||||
|
||||
/** Used to paint tiles. */
|
||||
protected PaintTileOp _paintOp = new PaintTileOp();
|
||||
|
||||
@@ -1709,6 +1603,8 @@ public class MisoScenePanel extends VirtualMediaPanel
|
||||
// used to display debugging information on scene block resolution
|
||||
protected JFrame _dframe;
|
||||
protected ResolutionView _dpanel;
|
||||
|
||||
protected TileOpApplicator _applicator;
|
||||
|
||||
/** A debug hook that toggles debug rendering of traversable tiles. */
|
||||
protected static RuntimeAdjust.BooleanAdjust _traverseDebug =
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.threerings.miso.client;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import com.threerings.media.util.MathUtil;
|
||||
import com.threerings.miso.util.MisoSceneMetrics;
|
||||
|
||||
/**
|
||||
* Constructs the set of blocks that intersect the op bounds.
|
||||
*/
|
||||
public class RethinkOp
|
||||
implements TileOp
|
||||
{
|
||||
public Set<Point> blocks = Sets.newHashSet();
|
||||
|
||||
public RethinkOp (MisoSceneMetrics metrics)
|
||||
{
|
||||
_metrics = metrics;
|
||||
}
|
||||
|
||||
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();
|
||||
protected MisoSceneMetrics _metrics;
|
||||
}
|
||||
@@ -36,40 +36,46 @@ import com.threerings.geom.GeomUtil;
|
||||
import com.threerings.media.tile.NoSuchTileSetException;
|
||||
import com.threerings.media.tile.ObjectTile;
|
||||
import com.threerings.media.tile.Tile;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.media.tile.TileSet;
|
||||
import com.threerings.media.tile.TileUtil;
|
||||
import com.threerings.media.util.MathUtil;
|
||||
|
||||
import com.threerings.miso.data.MisoSceneModel;
|
||||
import com.threerings.miso.data.ObjectInfo;
|
||||
import com.threerings.miso.tile.BaseTile;
|
||||
import com.threerings.miso.util.MisoSceneMetrics;
|
||||
import com.threerings.miso.util.MisoUtil;
|
||||
import com.threerings.miso.util.ObjectSet;
|
||||
|
||||
import static com.threerings.miso.Log.log;
|
||||
|
||||
/**
|
||||
* Contains the base and object tile information on a particular
|
||||
* rectangular region of a scene.
|
||||
* Contains the base and object tile information on a particular rectangular region of a scene.
|
||||
*/
|
||||
public class SceneBlock
|
||||
{
|
||||
/**
|
||||
* Creates a scene block and resolves the base and object tiles that
|
||||
* reside therein.
|
||||
* Creates a scene block belonging to panel in preparation for its later resolution.
|
||||
*/
|
||||
public SceneBlock (
|
||||
MisoScenePanel panel, int tx, int ty, int width, int height)
|
||||
public SceneBlock (MisoScenePanel panel, int tx, int ty, int width, int height)
|
||||
{
|
||||
_panel = panel;
|
||||
this(panel.getSceneModel(), panel.getSceneMetrics(), panel.getTileManager(), tx, ty,
|
||||
width, height);
|
||||
}
|
||||
|
||||
public SceneBlock (MisoSceneModel model, MisoSceneMetrics metrics, TileManager tileMgr,
|
||||
int tx, int ty, int width, int height)
|
||||
{
|
||||
_model = model;
|
||||
_metrics = metrics;
|
||||
_tileMgr = tileMgr;
|
||||
_bounds = new Rectangle(tx, ty, width, height);
|
||||
_base = new BaseTile[width*height];
|
||||
_fringe = new BaseTile[width*height];
|
||||
_covered = new boolean[width*height];
|
||||
|
||||
// compute our screen-coordinate footprint polygon
|
||||
_footprint = MisoUtil.getFootprintPolygon(
|
||||
panel.getSceneMetrics(), tx, ty, width, height);
|
||||
_footprint = MisoUtil.getFootprintPolygon(_metrics, tx, ty, width, height);
|
||||
|
||||
// the rest of our resolution will happen in resolve()
|
||||
}
|
||||
@@ -88,15 +94,17 @@ public class SceneBlock
|
||||
* block resolution thread to allow us to load up our image data
|
||||
* without blocking the AWT thread.
|
||||
*/
|
||||
protected boolean resolve ()
|
||||
public boolean resolve ()
|
||||
{
|
||||
// if we got canned before we were resolved, go ahead and bail now
|
||||
if (_panel.getBlock(_bounds.x, _bounds.y) != this) {
|
||||
// Log.info("Not resolving abandoned block " + this + ".");
|
||||
_panel.blockAbandoned(this);
|
||||
return false;
|
||||
if (_panel != null) {
|
||||
if (_panel.getBlock(_bounds.x, _bounds.y) != this) {
|
||||
// Log.info("Not resolving abandoned block " + this + ".");
|
||||
_panel.blockAbandoned(this);
|
||||
return false;
|
||||
}
|
||||
_panel.blockResolving(this);
|
||||
}
|
||||
_panel.blockResolving(this);
|
||||
|
||||
// start with the bounds of the footprint polygon
|
||||
Rectangle sbounds = new Rectangle(_footprint.getBounds());
|
||||
@@ -105,11 +113,10 @@ public class SceneBlock
|
||||
// resolve our base tiles
|
||||
long now = System.currentTimeMillis();
|
||||
int baseCount = 0, fringeCount = 0;
|
||||
MisoSceneModel model = _panel.getSceneModel();
|
||||
for (int yy = 0; yy < _bounds.height; yy++) {
|
||||
for (int xx = 0; xx < _bounds.width; xx++) {
|
||||
int x = _bounds.x + xx, y = _bounds.y + yy;
|
||||
int fqTileId = model.getBaseTileId(x, y);
|
||||
int fqTileId = _model.getBaseTileId(x, y);
|
||||
if (fqTileId <= 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -125,7 +132,7 @@ public class SceneBlock
|
||||
}
|
||||
|
||||
// compute the fringe for this tile
|
||||
_fringe[tidx] = _panel.computeFringeTile(x, y);
|
||||
_fringe[tidx] = computeFringeTile(x, y);
|
||||
fringeCount++;
|
||||
}
|
||||
}
|
||||
@@ -142,11 +149,11 @@ public class SceneBlock
|
||||
|
||||
// resolve our objects
|
||||
ObjectSet set = new ObjectSet();
|
||||
model.getObjects(_bounds, set);
|
||||
_model.getObjects(_bounds, set);
|
||||
ArrayList<SceneObject> scobjs = new ArrayList<SceneObject>();
|
||||
now = System.currentTimeMillis();
|
||||
for (int ii = 0, ll = set.size(); ii < ll; ii++) {
|
||||
SceneObject scobj = new SceneObject(_panel, set.get(ii));
|
||||
SceneObject scobj = makeSceneObject(set.get(ii));
|
||||
// ignore this object if it failed to resolve
|
||||
if (scobj.bounds == null) {
|
||||
continue;
|
||||
@@ -168,10 +175,10 @@ public class SceneBlock
|
||||
_objects = scobjs.toArray(new SceneObject[scobjs.size()]);
|
||||
|
||||
// resolve our default tileset
|
||||
int bsetid = model.getDefaultBaseTileSet();
|
||||
int bsetid = _model.getDefaultBaseTileSet();
|
||||
try {
|
||||
if (bsetid > 0) {
|
||||
_defset = _panel.getTileManager().getTileSet(bsetid);
|
||||
_defset = _tileMgr.getTileSet(bsetid);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warning("Unable to fetch default base tileset [tsid=" + bsetid +
|
||||
@@ -187,10 +194,22 @@ public class SceneBlock
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected SceneObject makeSceneObject (ObjectInfo info)
|
||||
{
|
||||
return new SceneObject(_metrics, _tileMgr,
|
||||
_panel == null ? null : _panel.getColorizer(info), info);
|
||||
}
|
||||
|
||||
/** Computes the fringe tile for the specified coordinate. */
|
||||
protected BaseTile computeFringeTile (int tx, int ty)
|
||||
{
|
||||
return _panel == null ? null : _panel.computeFringeTile(tx, ty);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by the {@link SceneBlockResolver} on the AWT thread
|
||||
* when our resolution has completed. We inform our containing panel.
|
||||
* This is called by the {@link SceneBlockResolver} on the AWT thread when our resolution has
|
||||
* completed. We inform our containing panel.
|
||||
*/
|
||||
protected void wasResolved ()
|
||||
{
|
||||
@@ -292,8 +311,7 @@ public class SceneBlock
|
||||
if (fqTileId <= 0) {
|
||||
_base[tidx] = null;
|
||||
} else {
|
||||
_base[tidx] = (BaseTile)
|
||||
_panel.getTileManager().getTile(fqTileId);
|
||||
_base[tidx] = (BaseTile)_tileMgr.getTile(fqTileId);
|
||||
}
|
||||
// clear out the fringe (it must be recomputed by the caller)
|
||||
_fringe[tidx] = null;
|
||||
@@ -318,7 +336,7 @@ public class SceneBlock
|
||||
{
|
||||
int tidx = index(tx, ty);
|
||||
if (_base[tidx] != null) {
|
||||
_fringe[tidx] = _panel.computeFringeTile(tx, ty);
|
||||
_fringe[tidx] = computeFringeTile(tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +358,7 @@ public class SceneBlock
|
||||
}
|
||||
}
|
||||
|
||||
_objects = ArrayUtil.append(_objects, new SceneObject(_panel, info));
|
||||
_objects = ArrayUtil.append(_objects, makeSceneObject(info));
|
||||
|
||||
// clear out our neighbors array so that the subsequent update
|
||||
// causes us to recompute our coverage
|
||||
@@ -554,8 +572,14 @@ public class SceneBlock
|
||||
_covered[index(tx, ty)] = true;
|
||||
}
|
||||
|
||||
/** The panel for which we contain a block. */
|
||||
/** The panel for which we contain a block or null if we aren't backed by a panel. */
|
||||
protected MisoScenePanel _panel;
|
||||
|
||||
protected MisoSceneMetrics _metrics;
|
||||
|
||||
protected MisoSceneModel _model;
|
||||
|
||||
protected TileManager _tileMgr;
|
||||
|
||||
/** The bounds of (in tile coordinates) of this block. */
|
||||
protected Rectangle _bounds;
|
||||
|
||||
@@ -29,13 +29,15 @@ import java.awt.Point;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.swing.RuntimeAdjust;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.samskivert.swing.RuntimeAdjust;
|
||||
|
||||
import com.threerings.media.tile.NoSuchTileSetException;
|
||||
import com.threerings.media.tile.ObjectTile;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.media.tile.TileUtil;
|
||||
|
||||
import com.threerings.media.tile.TileSet.Colorizer;
|
||||
import com.threerings.miso.MisoPrefs;
|
||||
import com.threerings.miso.data.ObjectInfo;
|
||||
import com.threerings.miso.util.MisoSceneMetrics;
|
||||
@@ -59,16 +61,21 @@ public class SceneObject
|
||||
public Rectangle bounds;
|
||||
|
||||
/**
|
||||
* Creates a scene object for display by the specified panel. The
|
||||
* appropriate object tile is resolved and the object's in-situ bounds
|
||||
* are computed.
|
||||
* Creates a scene object for display by the specified panel. The appropriate object tile is
|
||||
* resolved and the object's in-situ bounds are computed.
|
||||
*/
|
||||
public SceneObject (MisoScenePanel panel, ObjectInfo info)
|
||||
{
|
||||
this(panel.getSceneMetrics(), panel.getTileManager(), panel.getColorizer(info), info);
|
||||
}
|
||||
|
||||
public SceneObject (MisoSceneMetrics metrics, TileManager mgr, Colorizer colorizer,
|
||||
ObjectInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
|
||||
// resolve our object tile
|
||||
refreshObjectTile(panel);
|
||||
refreshObjectTile(metrics, mgr, colorizer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,30 +248,38 @@ public class SceneObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads and recolorizes our object tile. It is not intended for the
|
||||
* actual object tile used by a scene object to change in its
|
||||
* lifetime, only attributes of that object like its colorizations. So
|
||||
* don't do anything crazy like change our {@link ObjectInfo}'s
|
||||
* Reloads and recolorizes our object tile. It is not intended for the actual object tile used
|
||||
* by a scene object to change in its lifetime, only attributes of that object like its
|
||||
* colorizations. So don't do anything crazy like change our {@link ObjectInfo}'s
|
||||
* <code>tileId</code> and call this method or things might break.
|
||||
*/
|
||||
public void refreshObjectTile (MisoScenePanel panel)
|
||||
{
|
||||
refreshObjectTile(panel.getSceneMetrics(), panel.getTileManager(),
|
||||
panel.getColorizer(info));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads and recolorizes our object tile. It is not intended for the actual object tile used
|
||||
* by a scene object to change in its lifetime, only attributes of that object like its
|
||||
* colorizations. So don't do anything crazy like change our {@link ObjectInfo}'s
|
||||
* <code>tileId</code> and call this method or things might break.
|
||||
*/
|
||||
public void refreshObjectTile (MisoSceneMetrics metrics, TileManager mgr, Colorizer colorizer)
|
||||
{
|
||||
int tsid = TileUtil.getTileSetId(info.tileId);
|
||||
int tidx = TileUtil.getTileIndex(info.tileId);
|
||||
try {
|
||||
tile = (ObjectTile)panel.getTileManager().getTile(
|
||||
tsid, tidx, panel.getColorizer(info));
|
||||
computeInfo(panel.getSceneMetrics());
|
||||
tile = (ObjectTile)mgr.getTile(tsid, tidx, colorizer);
|
||||
computeInfo(metrics);
|
||||
|
||||
} catch (NoSuchTileSetException te) {
|
||||
log.warning("Scene contains non-existent object tileset " +
|
||||
"[info=" + info + "].");
|
||||
log.warning("Scene contains non-existent object tileset [info=" + info + "].");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes our screen bounds, tile footprint and other useful cached
|
||||
* metrics.
|
||||
* Computes our screen bounds, tile footprint and other useful cached metrics.
|
||||
*/
|
||||
protected void computeInfo (MisoSceneMetrics metrics)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.threerings.miso.client;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Exposes an operation to be applied to tiles by {@link TileOpApplicator}.
|
||||
*/
|
||||
public interface TileOp
|
||||
{
|
||||
public void apply (int tx, int ty, Rectangle tbounds);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.threerings.miso.client;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.threerings.miso.util.MisoSceneMetrics;
|
||||
import com.threerings.miso.util.MisoUtil;
|
||||
|
||||
/**
|
||||
* Applies a TileOp to all tiles within a region.
|
||||
*/
|
||||
public class TileOpApplicator
|
||||
{
|
||||
|
||||
public TileOpApplicator (MisoSceneMetrics metrics)
|
||||
{
|
||||
_metrics = metrics;
|
||||
_tbounds = new Rectangle(0, 0, _metrics.tilewid, _metrics.tilehei);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the supplied tile operation to all tiles that intersect the supplied screen
|
||||
* rectangle.
|
||||
*/
|
||||
public void applyToTiles (Rectangle region, 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, region.x, region.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 = (region.x - spos.x < _metrics.tilehwid);
|
||||
boolean top = (region.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 = region.x + region.width, bottomy = region.y + region.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);
|
||||
}
|
||||
}
|
||||
|
||||
protected MisoSceneMetrics _metrics;
|
||||
|
||||
/** Used when rendering tiles. */
|
||||
protected Rectangle _tbounds;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user