diff --git a/src/as/com/threerings/media/tile/DataPackTileSetRepository.as b/src/as/com/threerings/media/tile/DataPackTileSetRepository.as index 64503ec0..7110abf0 100644 --- a/src/as/com/threerings/media/tile/DataPackTileSetRepository.as +++ b/src/as/com/threerings/media/tile/DataPackTileSetRepository.as @@ -87,6 +87,18 @@ public class DataPackTileSetRepository loadTileSetsFromPack(bundleName.substr(0, bundleName.length - 11)); } } + + // Notify them all and clear our list. + for each (var func :Function in _notifyOnLoad) { + func(); + } + _notifyOnLoad = []; + } + + + public function notifyOnLoad (func :Function) :void + { + _notifyOnLoad.push(func); } public function enumerateTileSetIds () :Array @@ -244,5 +256,8 @@ public class DataPackTileSetRepository /** The map of packs we've already loaded up and resolved. */ protected var _packs :Map = Maps.newMapOf(String); + + /** Everyone who cares when we're loaded. */ + protected var _notifyOnLoad :Array = []; } } \ No newline at end of file diff --git a/src/as/com/threerings/media/tile/NoSuchTileSetError.as b/src/as/com/threerings/media/tile/NoSuchTileSetError.as index f811df6e..27f9b8ec 100644 --- a/src/as/com/threerings/media/tile/NoSuchTileSetError.as +++ b/src/as/com/threerings/media/tile/NoSuchTileSetError.as @@ -23,9 +23,8 @@ public class NoSuchTileSetError extends Error { public function NoSuchTileSetError (tileSet :*) { - (tileSet is int) ? - super("No tile set with id '" + int(tileSet) + "'") : - super("No tile set named'" + String(tileSet) + "'"); + super((tileSet is int) ? ("No tile set with id '" + int(tileSet) + "'") : + ("No tile set named'" + String(tileSet) + "'")); } } } \ No newline at end of file diff --git a/src/as/com/threerings/media/tile/TileSet.as b/src/as/com/threerings/media/tile/TileSet.as index 84f54bfb..6b770c0a 100644 --- a/src/as/com/threerings/media/tile/TileSet.as +++ b/src/as/com/threerings/media/tile/TileSet.as @@ -19,6 +19,7 @@ package com.threerings.media.tile { +import flash.display.Bitmap; import flash.display.DisplayObject; import flash.geom.Rectangle; @@ -196,13 +197,13 @@ public /* abstract */ class TileSet if (checkTileIndex(tileIndex)) { if (_improv == null) { log.warning("Aiya! Tile set missing image provider [path=" + _imagePath + "]."); - callback(ImageUtil.createErrorImage(bounds.width, bounds.height)); + callback(new Bitmap(ImageUtil.createErrorBitmap())); } else { _improv.getTileImage(_imagePath, bounds, zations, function(result :DisplayObject) :void { if (result == null) { - result = ImageUtil.createErrorImage(bounds.width, bounds.height); + result = new Bitmap(ImageUtil.createErrorBitmap()); } callback(result); }); diff --git a/src/as/com/threerings/media/tile/bundle/TileSetBundle.as b/src/as/com/threerings/media/tile/bundle/TileSetBundle.as index e626d553..6d0e3f64 100644 --- a/src/as/com/threerings/media/tile/bundle/TileSetBundle.as +++ b/src/as/com/threerings/media/tile/bundle/TileSetBundle.as @@ -28,6 +28,7 @@ import com.threerings.util.DataPack; import com.threerings.util.maps.DictionaryMap; import com.threerings.media.tile.BaseTileSet; import com.threerings.media.tile.ObjectTileSet; +import com.threerings.media.tile.SwissArmyTileSet; import com.threerings.media.tile.TileSet; import com.threerings.media.tile.TileSetIdMap; @@ -49,6 +50,10 @@ public class TileSetBundle extends DictionaryMap var baseId :int = idMap.getTileSetId(baseXml.@name); bundle.put(baseId, BaseTileSet.fromXml(baseXml)); } + for each (var fringeXml :XML in xml.fringe.tileset) { + var fringeId :int = idMap.getTileSetId(fringeXml.@name); + bundle.put(fringeId, SwissArmyTileSet.fromXml(fringeXml)); + } return bundle; } diff --git a/src/as/com/threerings/miso/client/BaseTileIsoSprite.as b/src/as/com/threerings/miso/client/BaseTileIsoSprite.as index 37e36526..46426044 100644 --- a/src/as/com/threerings/miso/client/BaseTileIsoSprite.as +++ b/src/as/com/threerings/miso/client/BaseTileIsoSprite.as @@ -19,15 +19,17 @@ package com.threerings.miso.client { +import flash.display.DisplayObject; + import com.threerings.media.tile.Tile; import com.threerings.miso.util.MisoSceneMetrics; public class BaseTileIsoSprite extends TileIsoSprite { public function BaseTileIsoSprite (x :int, y :int, tileId :int, tile :Tile, - metrics :MisoSceneMetrics) + metrics :MisoSceneMetrics, fringe :Tile) { - super(x, y, tileId, tile, 0, metrics); + super(x, y, tileId, tile, 0, metrics, fringe); } public override function layout (x :int, y :int, tile :Tile) :void diff --git a/src/as/com/threerings/miso/client/MisoScenePanel.as b/src/as/com/threerings/miso/client/MisoScenePanel.as index 1b2b5981..a381a7bf 100644 --- a/src/as/com/threerings/miso/client/MisoScenePanel.as +++ b/src/as/com/threerings/miso/client/MisoScenePanel.as @@ -53,6 +53,8 @@ import com.threerings.util.MathUtil; import com.threerings.util.Set; import com.threerings.util.Sets; import com.threerings.util.StringUtil; +import com.threerings.util.maps.WeakValueMap; +import com.threerings.media.tile.BaseTile; import com.threerings.media.tile.Colorizer; import com.threerings.media.tile.NoSuchTileSetError; import com.threerings.media.tile.TileSet; @@ -61,6 +63,7 @@ import com.threerings.miso.client.MisoMetricsTransformation; import com.threerings.miso.client.PrioritizedSceneLayoutRenderer; import com.threerings.miso.data.MisoSceneModel; import com.threerings.miso.data.ObjectInfo; +import com.threerings.miso.tile.FringeTile; import com.threerings.miso.util.MisoContext; import com.threerings.miso.util.ObjectSet; import com.threerings.miso.util.MisoSceneMetrics; @@ -151,6 +154,13 @@ public class MisoScenePanel extends Sprite { } + /** Computes the fringe tile for the specified coordinate. */ + public function computeFringeTile (tx :int, ty :int) :BaseTile + { + return _ctx.getTileManager().getFringer().getFringeTile(_model, tx, ty, _fringes, + _masks); + } + protected function getBaseBlocks () :Set { var blocks :Set = Sets.newSetOf(int); @@ -306,6 +316,9 @@ public class MisoScenePanel extends Sprite protected var _pendingBlocks :Set = Sets.newSetOf(SceneBlock); protected var _readyBlocks :Set = Sets.newSetOf(SceneBlock); + protected var _masks :Map = Maps.newMapOf(int); + protected var _fringes :Map = new WeakValueMap(Maps.newMapOf(FringeTile)); + protected const DEF_WIDTH :int = 985; protected const DEF_HEIGHT :int = 560; diff --git a/src/as/com/threerings/miso/client/SceneBlock.as b/src/as/com/threerings/miso/client/SceneBlock.as index 200425a4..a41a21bf 100644 --- a/src/as/com/threerings/miso/client/SceneBlock.as +++ b/src/as/com/threerings/miso/client/SceneBlock.as @@ -105,7 +105,7 @@ public class SceneBlock continue; } - createBaseSprite(tileSet, ii, jj, tileId); + createBaseSprite(tileSet, ii, jj, tileId, panel); } } @@ -161,19 +161,31 @@ public class SceneBlock } } - protected function createBaseSprite (tileSet :TileSet, x :int, y :int, tileId :int) :void + protected function createBaseSprite (tileSet :TileSet, x :int, y :int, tileId :int, + panel :MisoScenePanel) :void { + var fringeTile :Tile = panel.computeFringeTile(x, y); + var tile :Tile = tileSet.getTile(TileUtil.getTileIndex(tileId)); - if (tile.getImage() != null) { - _baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics)); + var maybeLoaded :Function = function (loaded :Tile) :void { + if (tile.getImage() != null && (fringeTile == null || fringeTile.getImage() != null)) { + _baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics, + fringeTile)); + noteTileLoaded(); + } + }; + + if (tile.getImage() != null && (fringeTile == null || fringeTile.getImage() != null)) { + _baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics, fringeTile)); } else { noteTileToLoad(); - - tile.notifyOnLoad(function (tile :Tile) :void { - _baseScene.addChild(new BaseTileIsoSprite(x, y, tileId, tile, _metrics)); - noteTileLoaded(); - }); + if (tile.getImage() == null) { + tile.notifyOnLoad(maybeLoaded); + } + if (fringeTile != null && fringeTile.getImage() == null) { + fringeTile.notifyOnLoad(maybeLoaded); + } } } diff --git a/src/as/com/threerings/miso/client/TileIsoSprite.as b/src/as/com/threerings/miso/client/TileIsoSprite.as index a8d17ef2..9bcd5af2 100644 --- a/src/as/com/threerings/miso/client/TileIsoSprite.as +++ b/src/as/com/threerings/miso/client/TileIsoSprite.as @@ -38,11 +38,12 @@ public class TileIsoSprite extends IsoSprite private static var log :Log = Log.getLog(TileIsoSprite); public function TileIsoSprite (x :int, y :int, tileId :int, tile :Tile, priority :int, - metrics :MisoSceneMetrics) + metrics :MisoSceneMetrics, fringe :Tile = null) { _tileId = tileId; _metrics = metrics; _priority = priority; + _fringe = fringe; layout(x, y, tile); @@ -67,10 +68,22 @@ public class TileIsoSprite extends IsoSprite var image :DisplayObject = tile.getImage(); // as3isolib uses top instead of bottom. image.x = -tile.getOriginX() + _metrics.tilewid * - ((tile.getBaseWidth() - tile.getBaseHeight())/2);; + ((tile.getBaseWidth() - tile.getBaseHeight())/2); image.y = -tile.getOriginY() + _metrics.tilehei * ((tile.getBaseWidth() + tile.getBaseHeight())/2); - sprites = [image]; + + if (_fringe == null) { + sprites = [image]; + } else { + var fringeImg :DisplayObject = _fringe.getImage(); + // as3isolib uses top instead of bottom. + fringeImg.x = -_fringe.getOriginX() + _metrics.tilewid * + ((_fringe.getBaseWidth() - _fringe.getBaseHeight())/2); + fringeImg.y = -_fringe.getOriginY() + _metrics.tilehei * + ((_fringe.getBaseWidth() + _fringe.getBaseHeight())/2); + + sprites = [image, fringeImg]; + } render(); } @@ -83,6 +96,8 @@ public class TileIsoSprite extends IsoSprite protected var _priority :int; + protected var _fringe :Tile; + protected var _metrics :MisoSceneMetrics; } } \ No newline at end of file diff --git a/src/as/com/threerings/miso/tile/AutoFringer.as b/src/as/com/threerings/miso/tile/AutoFringer.as index 10419276..0ae3d76b 100644 --- a/src/as/com/threerings/miso/tile/AutoFringer.as +++ b/src/as/com/threerings/miso/tile/AutoFringer.as @@ -37,6 +37,9 @@ import com.threerings.util.Integer; import com.threerings.util.Log; import com.threerings.util.Maps; import com.threerings.util.Map; +import com.threerings.util.Sets; +import com.threerings.util.Set; +import com.threerings.util.StringUtil; import com.threerings.util.WeakReference; import com.threerings.miso.data.MisoSceneModel; @@ -72,6 +75,25 @@ public class AutoFringer return _fringeConf; } + /** + * Returns all the tilesets that fringe on the specified tilesets. + */ + public function getFringeSets (tilesets :Set) :Set + { + var fringeSets :Set = Sets.newSetOf(int); + + tilesets.forEach(function(o :int) :void { + var fringes :Array = _fringeConf.getFringeSets(o); + if (fringes != null) { + for each (var fringe :int in fringes) { + fringeSets.add(fringe); + } + } + }); + + return fringeSets; + } + /** * Compute and return the fringe tile to be inserted at the specified location. */ @@ -79,7 +101,9 @@ public class AutoFringer masks :Map) :BaseTile { // get the tileset id of the base tile we are considering - var underset :int = adjustTileSetId(scene.getBaseTileId(col, row) >> 16); + var utid :int = scene.getBaseTileId(col, row); + var underset :int = adjustTileSetId((utid <= 0) ? + scene.getDefaultBaseTileSet() : (utid >> 16)); // start with a clean temporary fringer map _fringers.clear(); @@ -135,13 +159,7 @@ public class AutoFringer } // otherwise compose a FringeTile from the specified fringes - var frecs :Array = new Array(numfringers); - for (var ii :int = 0, pp :int = 0; ii < 16; ii++) { - var rec :FringerRec = FringerRec(_fringers.get(ii)); - if (rec != null) { - frecs[pp++] = rec; - } - } + var frecs :Array = _fringers.values(); return composeFringeTile(frecs, fringes, TileUtil.getTileHash(col, row), passable, masks); } @@ -197,10 +215,11 @@ public class AutoFringer var tsr :FringeTileSetRecord = _fringeConf.getFringe(fringer.baseset, hashValue); getTileImageHelper0(img, tsr, fringer.baseset, hashValue, masks, indexes, 0, function (result :Bitmap) :void { - if (fringerIdx == fringers.size() - 1) { + if (fringerIdx == fringers.length - 1) { callback(result); } else { - getTileImageHelper1(img, hashValue, masks, fringers, fringerIdx + 1, callback); + getTileImageHelper1(result, hashValue, masks, fringers, fringerIdx + 1, + callback); } }); } @@ -212,10 +231,10 @@ public class AutoFringer try { getTileImage(img, tsr, baseset, indexes[indexIdx], hashValue, masks, function (result :Bitmap) :void { - if (indexIdx == indexes.size() - 1) { + if (indexIdx == indexes.length - 1) { callback(result); } else { - getTileImageHelper0(img, tsr, baseset, hashValue, masks, indexes, + getTileImageHelper0(result, tsr, baseset, hashValue, masks, indexes, indexIdx + 1, callback); } }); @@ -231,12 +250,19 @@ public class AutoFringer protected function getTileImage (img :Bitmap, tsr :FringeTileSetRecord , baseset :int, index :int, hashValue :int, masks :Map, callback :Function) :void { + var fringeset :int = tsr.fringe_tsid; var fset :TileSet = _tMgr.getTileSet(fringeset); if (!tsr.mask) { // oh good, this is easy var stamp :Tile = fset.getTile(index); - callback(stampTileImage(stamp, img, stamp.getWidth(), stamp.getHeight())); + if (stamp.getImage() != null) { + callback(stampTileImage(stamp, img, stamp.getWidth(), stamp.getHeight())); + } else { + stamp.notifyOnLoad(function(tile :Tile) :void { + callback(stampTileImage(stamp, img, stamp.getWidth(), stamp.getHeight())); + }); + } return; } @@ -325,7 +351,7 @@ public class AutoFringer } else if (weebits != 0) { index = BITS_TO_INDEX[weebits]; if (index != -1) { - indexes.add(index); + indexes.push(index); } weebits = 0; } @@ -333,7 +359,7 @@ public class AutoFringer if (weebits != 0) { index = BITS_TO_INDEX[weebits]; if (index != -1) { - indexes.add(index); + indexes.push(index); } } diff --git a/src/as/com/threerings/miso/tile/FringeConfiguration.as b/src/as/com/threerings/miso/tile/FringeConfiguration.as index 9db60711..5ee5c5b2 100644 --- a/src/as/com/threerings/miso/tile/FringeConfiguration.as +++ b/src/as/com/threerings/miso/tile/FringeConfiguration.as @@ -53,13 +53,18 @@ public class FringeConfiguration */ public function fringesOn (first :int, second :int) :int { + // Short-circuit if we're fringing on ourselves. + if (first == second) { + return -1; + } + var f1 :FringeRecord = _frecs.get(first); // we better have a fringe record for the first if (null != f1) { // it had better have some tilesets defined - if (f1.tilesets.size() > 0) { + if (f1.tilesets.length > 0) { var f2 :FringeRecord = _frecs.get(second); @@ -81,7 +86,23 @@ public class FringeConfiguration public function getFringe (baseset :int, hashValue :int) :FringeTileSetRecord { var f :FringeRecord = _frecs.get(baseset); - return f.tilesets.get(hashValue % f.tilesets.size()); + return f.tilesets[hashValue % f.tilesets.length]; + } + + /** + * Returns all the tilesets used to fringe with this baseset. + */ + public function getFringeSets (baseset :int) :Array + { + var f :FringeRecord = _frecs.get(baseset); + if (f == null) { + return []; + } else { + return f.tilesets.map( + function (element :FringeTileSetRecord, index:int, arr:Array) :int { + return element.fringe_tsid; + }); + } } /** The mapping from base tileset id to fringerecord. */ diff --git a/src/as/com/threerings/miso/tile/FringeRecord.as b/src/as/com/threerings/miso/tile/FringeRecord.as index 6e0b1fef..dd3a1cbb 100644 --- a/src/as/com/threerings/miso/tile/FringeRecord.as +++ b/src/as/com/threerings/miso/tile/FringeRecord.as @@ -31,7 +31,7 @@ public class FringeRecord public var priority :int; /** A list of the possible tilesets that can be used for fringing. */ - public var tilesets :Array; + public var tilesets :Array = []; public static function fromXml (xml :XML, idMap :TileSetIdMap) :FringeRecord { diff --git a/src/as/com/threerings/miso/tile/FringeTileSetRecord.as b/src/as/com/threerings/miso/tile/FringeTileSetRecord.as index 4dddc7ff..3baa9dd5 100644 --- a/src/as/com/threerings/miso/tile/FringeTileSetRecord.as +++ b/src/as/com/threerings/miso/tile/FringeTileSetRecord.as @@ -20,6 +20,7 @@ package com.threerings.miso.tile { import com.threerings.media.tile.TileSetIdMap; +import com.threerings.util.XmlUtil; public class FringeTileSetRecord { @@ -33,7 +34,7 @@ public class FringeTileSetRecord { var rec :FringeTileSetRecord = new FringeTileSetRecord(); rec.fringe_tsid = idMap.getTileSetId(xml.@name); - rec.mask = xml.@mask; + rec.mask = XmlUtil.getBooleanAttr(xml, "mask", false); return rec; } diff --git a/src/as/com/threerings/miso/tile/MisoTileManager.as b/src/as/com/threerings/miso/tile/MisoTileManager.as index 80143c4d..a0885d20 100644 --- a/src/as/com/threerings/miso/tile/MisoTileManager.as +++ b/src/as/com/threerings/miso/tile/MisoTileManager.as @@ -20,6 +20,7 @@ package com.threerings.miso.tile { import com.threerings.media.tile.TileManager; +import com.threerings.util.Set; /** * Extends the basic tile manager and provides support for automatically generating fringes in @@ -27,6 +28,28 @@ import com.threerings.media.tile.TileManager; */ public class MisoTileManager extends TileManager { - // TODO: Fringing. + public function setFringer (fringer :AutoFringer) :void + { + _fringer = fringer; + } + + public function getFringer () :AutoFringer + { + return _fringer; + } + + override public function ensureLoaded (tileSets :Set, completeCallback :Function, + progressCallback :Function) :void + { + // Get those we'll use to fringe with us, too. + var fringeSets :Set = _fringer.getFringeSets(tileSets); + fringeSets.forEach(function (tsetId :int) :void { + tileSets.add(tsetId); + }); + + super.ensureLoaded(tileSets, completeCallback, progressCallback); + } + + protected var _fringer :AutoFringer; } }