Second pass on AS recoloring, fixed a bunch of bugs and tied to tiles/tilesets.

git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@936 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Mike Thomas
2010-07-07 18:04:52 +00:00
parent 91b0a812ba
commit 1254841995
10 changed files with 89 additions and 50 deletions
@@ -138,13 +138,14 @@ public class ClassRecord
public static function fromXml (xml :XML) :ClassRecord public static function fromXml (xml :XML) :ClassRecord
{ {
var rec :ClassRecord = new ClassRecord(); var rec :ClassRecord = new ClassRecord();
rec.classId = xml.@classId;
for each (var colorXml :XML in xml.color) { for each (var colorXml :XML in xml.color) {
rec.colors.put(colorXml.@colorId, ColorRecord.fromXml(colorXml)); rec.colors.put(int(colorXml.@colorId), ColorRecord.fromXml(colorXml, rec));
} }
rec.name = xml.@name; rec.name = xml.@name;
var srcStr :String = xml.@source; var srcStr :String = xml.@source;
rec.source = parseInt(srcStr.substring(1, srcStr.length - 1), 16); rec.source = parseInt(srcStr.substr(1, srcStr.length - 1), 16);
rec.range = toNumArray(xml.@range); rec.range = toNumArray(xml.@range);
rec.defaultId = xml.@defaultId; rec.defaultId = xml.@defaultId;
@@ -157,7 +158,7 @@ public class ClassRecord
return null; return null;
} }
return str.split(",").map(function(element :*, index :int, arr :Array) :int { return str.split(",").map(function(element :*, index :int, arr :Array) :Number {
return Number(element); return Number(element);
}); });
} }
@@ -22,6 +22,7 @@ package com.threerings.media.image {
import com.threerings.util.Log; import com.threerings.util.Log;
import com.threerings.util.Map; import com.threerings.util.Map;
import com.threerings.util.Maps; import com.threerings.util.Maps;
import com.threerings.util.StringUtil;
public class ColorPository public class ColorPository
{ {
@@ -120,12 +121,27 @@ public class ColorPository
return null; return null;
} }
/**
* Looks up a colorization by class and color Id.
*/
public function getColorizationByNameAndId (className :String, colorId :int) :Colorization
{
var crec :ClassRecord = getClassRecordByName(className);
if (crec != null) {
var color :ColorRecord = crec.colors.get(colorId);
if (color != null) {
return color.getColorization();
}
}
return null;
}
/** /**
* Loads up a colorization class by name and logs a warning if it doesn't exist. * Loads up a colorization class by name and logs a warning if it doesn't exist.
*/ */
public function getClassRecordByName (className :String) :ClassRecord public function getClassRecordByName (className :String) :ClassRecord
{ {
for each (var crec :ClassRecord in _classes) { for each (var crec :ClassRecord in _classes.values()) {
if (crec.name == className) { if (crec.name == className) {
return crec; return crec;
} }
@@ -72,13 +72,14 @@ public class ColorRecord
} }
public static function fromXml (xml :XML) :ColorRecord public static function fromXml (xml :XML, cclass :ClassRecord) :ColorRecord
{ {
var rec :ColorRecord = new ColorRecord(); var rec :ColorRecord = new ColorRecord();
rec.colorId = xml.@colorId; rec.colorId = xml.@colorId;
rec.name = xml.@name; rec.name = xml.@name;
rec.offsets = toNumArray(xml.@offsets); rec.offsets = toNumArray(xml.@offsets);
rec.starter = xml.@starter; rec.starter = xml.@starter;
rec.cclass = cclass;
return rec; return rec;
} }
@@ -89,8 +90,8 @@ public class ColorRecord
return null; return null;
} }
return str.split(",").map(function(element :*, index :int, arr :Array) :int { return str.split(",").map(function(element :String, index :int, arr :Array) :Number {
return Number(element); return Number(StringUtil.trim(element));
}); });
} }
@@ -55,7 +55,7 @@ public class Colorization
// compute our HSV and fixed HSV // compute our HSV and fixed HSV
_hsv = ColorUtil.RGBtoHSB(ColorUtil.getRed(rootColor), ColorUtil.getGreen(rootColor), _hsv = ColorUtil.RGBtoHSB(ColorUtil.getRed(rootColor), ColorUtil.getGreen(rootColor),
ColorUtil.getBlue(rootColor)); ColorUtil.getBlue(rootColor));
_fhsv = toFixedHSV(_hsv, null); _fhsv = toFixedHSV(_hsv);
} }
/** /**
@@ -154,14 +154,12 @@ public class Colorization
* @return the <code>fhsv</code> parameter if it was non-null or the * @return the <code>fhsv</code> parameter if it was non-null or the
* newly created target array. * newly created target array.
*/ */
public static function toFixedHSV (hsv :Array, fhsv :Array) :Array public static function toFixedHSV (hsv :Array) :Array
{ {
if (fhsv == null) { var fhsv :Array = new Array(hsv.length);
fhsv = new Array(hsv.length);
}
for (var ii :int = 0; ii < hsv.length; ii++) { for (var ii :int = 0; ii < hsv.length; ii++) {
// fhsv[i] = (int)(hsv[i]*Integer.MAX_VALUE); fhsv[ii] = int(hsv[ii] * Short.MAX_VALUE);
fhsv[ii] = (int)(hsv[ii]*Short.MAX_VALUE);
} }
return fhsv; return fhsv;
} }
@@ -78,23 +78,23 @@ public class PngRecolorUtil
} }
public static function recolorPNG (pngBytes :ByteArray, public static function recolorPNG (pngBytes :ByteArray,
colors :Array/* of Colorization */) :void colors :Array/* of Colorization */) :ByteArray
{ {
if (colors.length == 0) { if (colors == null || colors.length == 0) {
return; return pngBytes;
} }
// first, lets make sure we really have a PNG // first, lets make sure we really have a PNG
if (!isPng(pngBytes)) { if (!isPng(pngBytes)) {
log.warning("recolorPNG received invalid pngBytes", new Error()); log.warning("recolorPNG received invalid pngBytes", new Error());
return; return pngBytes;
} }
var chunks :Array = findChunks(pngBytes, [HEADER_CHUNK, PALETTE_CHUNK]); var chunks :Array = findChunks(pngBytes, [HEADER_CHUNK, PALETTE_CHUNK]);
if (chunks.length != 2 || (chunks[0] as PngChunk).type != HEADER_CHUNK) { if (chunks.length != 2 || (chunks[0] as PngChunk).type != HEADER_CHUNK) {
log.warning("recolorPNG received an unexected PNG format", "requiredChunksFound", log.warning("recolorPNG received an unexected PNG format", "requiredChunksFound",
chunks.length, new Error()); chunks.length, new Error());
return; return pngBytes;
} }
var header :PngChunk = chunks[0] as PngChunk; var header :PngChunk = chunks[0] as PngChunk;
var palette :PngChunk = chunks[1] as PngChunk; var palette :PngChunk = chunks[1] as PngChunk;
@@ -103,7 +103,7 @@ public class PngRecolorUtil
if (colorType != INDEXED_COLOR_TYPE) { if (colorType != INDEXED_COLOR_TYPE) {
log.warning( log.warning(
"Color Type in PNG header is not indexed-color", "type", colorType, new Error()); "Color Type in PNG header is not indexed-color", "type", colorType, new Error());
return; return pngBytes;
} }
initializeCRCTable(); initializeCRCTable();
@@ -118,12 +118,16 @@ public class PngRecolorUtil
var green :uint = pngBytes.readUnsignedByte(); var green :uint = pngBytes.readUnsignedByte();
var blue :uint = pngBytes.readUnsignedByte(); var blue :uint = pngBytes.readUnsignedByte();
var hsb :Array = ColorUtil.RGBtoHSB(red, green, blue); var hsv :Array = ColorUtil.RGBtoHSB(red, green, blue);
var fhsv :Array = Colorization.toFixedHSV(hsv);
for each (var color :Colorization in colors) { for each (var color :Colorization in colors) {
var newRgb :uint = color.recolorColor(hsb); if (color != null && color.matches(hsv, fhsv)) {
pngBytes[ii] = ColorUtil.getRed(newRgb); var newRgb :uint = color.recolorColor(hsv);
pngBytes[ii + 1] = ColorUtil.getGreen(newRgb); pngBytes[ii] = red = ColorUtil.getRed(newRgb);
pngBytes[ii + 2] = ColorUtil.getBlue(newRgb); pngBytes[ii + 1] = green = ColorUtil.getGreen(newRgb);
pngBytes[ii + 2] = blue = ColorUtil.getBlue(newRgb);
break;
}
} }
crc = F.foldl([red, green, blue], crc, crcCalc); crc = F.foldl([red, green, blue], crc, crcCalc);
@@ -132,6 +136,8 @@ public class PngRecolorUtil
// write out the CRC for the modified color table // write out the CRC for the modified color table
pngBytes.position = palette.idx + palette.length; pngBytes.position = palette.idx + palette.length;
pngBytes.writeUnsignedInt(crc); pngBytes.writeUnsignedInt(crc);
return pngBytes;
} }
protected static function initializeCRCTable () :void protected static function initializeCRCTable () :void
@@ -172,8 +178,6 @@ public class PngRecolorUtil
protected static const COLOR_TYPE_IDX :int = 9; protected static const COLOR_TYPE_IDX :int = 9;
protected static const INDEXED_COLOR_TYPE :int = 3; protected static const INDEXED_COLOR_TYPE :int = 3;
protected static const JAVA_SHORT_MAX :int = 0x7FFF;
protected static var _crcTable :Array; protected static var _crcTable :Array;
} }
} }
@@ -264,9 +264,12 @@ public class ObjectTileSet extends SwissArmyTileSet
_yspots = toIntArray(xml.ySpots); _yspots = toIntArray(xml.ySpots);
_sorients = toIntArray(xml.sorients); _sorients = toIntArray(xml.sorients);
var constraintStrArr :Array = toStrArray(xml.constraints); var constraintStrArr :Array = toStrArray(xml.constraints);
_constraints = constraintStrArr.map(function(element :*, index :int, arr :Array) :Array { if (constraintStrArr != null) {
return element.split("|"); _constraints =
}); constraintStrArr.map(function(element :*, index :int, arr :Array) :Array {
return element.split("|");
});
}
} }
/** The width (in tile units) of our object tiles. */ /** The width (in tile units) of our object tiles. */
@@ -177,24 +177,34 @@ public class SwissArmyTileSet extends TileSet
_widths = toIntArray(xml.widths); _widths = toIntArray(xml.widths);
_heights = toIntArray(xml.heights); _heights = toIntArray(xml.heights);
var offsetPosArr :Array = toIntArray(xml.offsetPos); var offsetPosArr :Array = toIntArray(xml.offsetPos);
_offsetPos = new Point(offsetPosArr[0], offsetPosArr[1]); if (offsetPosArr != null) {
_offsetPos = new Point(offsetPosArr[0], offsetPosArr[1]);
} else {
_offsetPos = new Point(0, 0);
}
var gapSizeArr :Array = toIntArray(xml.gapSize); var gapSizeArr :Array = toIntArray(xml.gapSize);
_gapSize = new Point(gapSizeArr[0], gapSizeArr[1]); if (gapSizeArr != null) {
_gapSize = new Point(gapSizeArr[0], gapSizeArr[1]);
} else {
_gapSize = new Point(0, 0);
}
computeTileCount(); computeTileCount();
} }
protected static function toStrArray (str :String) :Array protected static function toStrArray (str :String) :Array
{ {
if (str == null) { if (str == null || str.length == 0) {
return null; return null;
} }
return str.split(","); return str.split(",").map(function(element :String, index :int, arr :Array) :String {
return StringUtil.trim(element);
});
} }
protected static function toBoolArray (str :String) :Array protected static function toBoolArray (str :String) :Array
{ {
if (str == null) { if (str == null || str.length == 0) {
return null; return null;
} }
@@ -205,7 +215,7 @@ public class SwissArmyTileSet extends TileSet
protected static function toIntArray (str :String) :Array protected static function toIntArray (str :String) :Array
{ {
if (str == null) { if (str == null || str.length == 0) {
return null; return null;
} }
@@ -34,6 +34,7 @@ import nochump.util.zip.ZipEntry;
import nochump.util.zip.ZipError; import nochump.util.zip.ZipError;
import nochump.util.zip.ZipFile; import nochump.util.zip.ZipFile;
import com.threerings.media.image.PngRecolorUtil;
import com.threerings.util.DataPack; import com.threerings.util.DataPack;
import com.threerings.util.MultiLoader; import com.threerings.util.MultiLoader;
@@ -85,23 +86,17 @@ public class TileDataPack extends DataPack
public function getTileSetImage (path :String, zations :Array, callback :Function) :void public function getTileSetImage (path :String, zations :Array, callback :Function) :void
{ {
// TODO - DO SOMETHING WITH ZATIONS MultiLoader.getContents(PngRecolorUtil.recolorPNG(getFile(path), zations), callback);
getDisplayObjects(path, callback);
} }
public function getTileImage (path :String, bounds :Rectangle, zations :Array, public function getTileImage (path :String, bounds :Rectangle, zations :Array,
callback :Function) :void callback :Function) :void
{ {
getTileSetImage(path, zations, function(result :DisplayObject) :void { getTileSetImage(path, zations, function(result :Bitmap) :void {
// TODO - DO SOMETHING TO SUB_REGION THIS var data :BitmapData =
if (result is Bitmap) { new BitmapData(bounds.width, bounds.height, true, 0x00000000);
var data :BitmapData = data.copyPixels(Bitmap(result).bitmapData, bounds, new Point(0, 0));
new BitmapData(bounds.width, bounds.height, true, 0x00000000); callback(new Bitmap(data));
data.copyPixels(Bitmap(result).bitmapData, bounds, new Point(0, 0));
callback(new Bitmap(data));
} else {
callback(result);
}
}); });
} }
} }
@@ -32,6 +32,7 @@ import flash.events.MouseEvent;
import com.threerings.crowd.client.PlaceView; import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject; import com.threerings.crowd.data.PlaceObject;
import com.threerings.media.tile.Colorizer;
import com.threerings.media.tile.NoSuchTileSetError; import com.threerings.media.tile.NoSuchTileSetError;
import com.threerings.media.tile.TileSet; import com.threerings.media.tile.TileSet;
import com.threerings.media.tile.TileUtil; import com.threerings.media.tile.TileUtil;
@@ -166,7 +167,8 @@ public class MisoScenePanel extends Sprite
scene.addChild( scene.addChild(
new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId, new ObjectTileIsoSprite(objInfo.x, objInfo.y, objTileId,
objTileSet.getTile(TileUtil.getTileIndex(objTileId)), _metrics)); objTileSet.getTile(TileUtil.getTileIndex(objTileId), getColorizer(objInfo)),
_metrics));
} }
time = getTimer(); time = getTimer();
@@ -175,6 +177,15 @@ public class MisoScenePanel extends Sprite
_isoView.addScene(scene); _isoView.addScene(scene);
} }
/**
* Derived classes can override this method and provide a colorizer that will be used to
* colorize the supplied scene object when rendering.
*/
protected function getColorizer (oinfo :ObjectInfo) :Colorizer
{
return null;
}
protected var _model :MisoSceneModel; protected var _model :MisoSceneModel;
protected var _isoView :IsoView; protected var _isoView :IsoView;
@@ -86,7 +86,7 @@ public class TileIsoSprite extends IsoDisplayObject
image.x = -tile.getOriginX() + _metrics.tilewid * image.x = -tile.getOriginX() + _metrics.tilewid *
((tile.getBaseWidth() - tile.getBaseHeight())/2);; ((tile.getBaseWidth() - tile.getBaseHeight())/2);;
image.y = -tile.getOriginY() + _metrics.tilehei * image.y = -tile.getOriginY() + _metrics.tilehei *
(1 + (tile.getBaseWidth() + tile.getBaseHeight())/2); ((tile.getBaseWidth() + tile.getBaseHeight())/2);
sprite.sprites = [image]; sprite.sprites = [image];
sprite.setSize(tile.getBaseWidth(), tile.getBaseHeight(), 1); sprite.setSize(tile.getBaseWidth(), tile.getBaseHeight(), 1);
addChild(sprite); addChild(sprite);