From 3d70c731a538799d6a8c7da81de8836d460cb527 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Thu, 15 Jul 2010 19:03:55 +0000 Subject: [PATCH] Get AS fringing actually working. We end up with a double-layer of sprites on the base tiles for the background as one and all the fringing as another. This is definitely pretty slow in the debug player, so still need to track down what's spending all that time. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@954 ed5b42cb-e716-0410-a449-f6a68f950b19 --- .../media/tile/DataPackTileSetRepository.as | 15 +++++ .../media/tile/NoSuchTileSetError.as | 5 +- src/as/com/threerings/media/tile/TileSet.as | 5 +- .../media/tile/bundle/TileSetBundle.as | 5 ++ .../miso/client/BaseTileIsoSprite.as | 6 +- .../threerings/miso/client/MisoScenePanel.as | 13 +++++ .../com/threerings/miso/client/SceneBlock.as | 30 +++++++--- .../threerings/miso/client/TileIsoSprite.as | 21 ++++++- .../com/threerings/miso/tile/AutoFringer.as | 56 ++++++++++++++----- .../miso/tile/FringeConfiguration.as | 25 ++++++++- .../com/threerings/miso/tile/FringeRecord.as | 2 +- .../miso/tile/FringeTileSetRecord.as | 3 +- .../threerings/miso/tile/MisoTileManager.as | 25 ++++++++- 13 files changed, 172 insertions(+), 39 deletions(-) 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; } }