images: Introduce gamma function to convert colours more precisely.
5 files changed, 31 insertions(+), 22 deletions(-)

M res/resources.json
M tools/images.js
M tools/resources.js
M tools/sprites.js
M tools/tilemaps.js
M res/resources.json +1 -0
@@ 1,6 1,7 @@ 
 {
 	"screenMode": 5,
 	"frameRate": 59.922743404312307,
+	"gamma": 2.42,
 	"tilemaps": [
 		{
 			"name": "FieldMap",

          
M tools/images.js +6 -2
@@ 153,9 153,13 @@ class PaletteColor {
 }
 
 class PNGLoader {
-	constructor(path) {
+	constructor(path, gamma) {
 		checkTypes(arguments, "string");
 		this.path = path;
+		this.valueMapping3Bit = new Array(256);
+		for (let i = 0; i < 256; i++) {
+			this.valueMapping3Bit[i] = Math.round(Math.pow(i / 255, gamma / 2.2) * 7);
+		}
 	}
 
 	async loadImage() {

          
@@ 178,7 182,7 @@ class PNGLoader {
 	toPalette(palette8bit) {
 		checkTypes(arguments, Array);
 		const palette = new Palette();
-		const palette3bit = palette8bit.map(c => Math.round(c / 255 * 7));
+		const palette3bit = palette8bit.map(c => this.valueMapping3Bit[c]);
 		for (let i = 0; i < palette3bit.length / 3; i++) {
 			const r = palette3bit[i * 3] || 0;
 			const g = palette3bit[i * 3 + 1] || 0;

          
M tools/resources.js +8 -6
@@ 21,10 21,11 @@ async function main() {
 }
 
 class Resources {
-	constructor(screenMode, frameRate) {
-		checkTypes(arguments, "number", "number");
+	constructor(screenMode, frameRate, gamma) {
+		checkTypes(arguments, "number", "number", "number");
 		this.screenMode = screenMode;
 		this.frameRate = frameRate;
+		this.gamma = gamma;
 		this.tileMaps = [];
 		this.images = [];
 		this.sprites = [];

          
@@ 86,24 87,25 @@ class ResourcesLoader {
 
 		const resources = new Resources(
 			json.screenMode,
-			json.frameRate
+			json.frameRate,
+			json.gamma
 		);
 
 		const tileMaps = Promise.all(json.tilemaps.map(async jsonTileMap => {
 			const tileMapPath = path.resolve(path.dirname(this.path), jsonTileMap.path);
-			return new Tmx(jsonTileMap.name, tileMapPath).parse();
+			return new Tmx(jsonTileMap.name, tileMapPath).parse(resources.gamma);
 		}));
 
 		const images = Promise.all(json.images.map(async jsonImage => {
 			const imagePath = path.resolve(path.dirname(this.path), jsonImage.path);
-			const image = await new PNGLoader(imagePath).loadImage();
+			const image = await new PNGLoader(imagePath, resources.gamma).loadImage();
 			image.name = jsonImage.name;
 			return image;
 		}));
 
 		const sprites = Promise.all(json.sprites.map(async jsonSprite => {
 			const spritePath = path.resolve(path.dirname(this.path), jsonSprite.path);
-			return new AsepriteSheet(jsonSprite.name, spritePath).parse();
+			return new AsepriteSheet(jsonSprite.name, spritePath).parse(resources.gamma);
 		}));
 
 		const audio = Promise.all(json.audio.map(async jsonTrack => {

          
M tools/sprites.js +7 -6
@@ 103,18 103,19 @@ class AsepriteSheet {
 		this.path = path;
 	}
 
-	async parse() {
+	async parse(gamma) {
+		checkTypes(arguments, "number");
 		const json = JSON.parse(await fs.promises.readFile(this.path));
-		const sprite = await this.parseSprite(json.meta, this.name);
+		const sprite = await this.parseSprite(json.meta, gamma);
 		this.parseFrames(json.frames, sprite);
 		return sprite;
 	}
 
-	async parseSprite(jsonMeta, name) {
-		checkTypes(arguments, Object, "string");
+	async parseSprite(jsonMeta, gamma) {
+		checkTypes(arguments, Object, "number");
 		const imagepath = path.resolve(path.dirname(this.path), jsonMeta.image);
-		const image = await new PNGLoader(imagepath).loadImage();
-		return new Sprite(name, image);
+		const image = await new PNGLoader(imagepath, gamma).loadImage();
+		return new Sprite(this.name, image);
 	}
 
 	parseFrames(jsonFrames, sprite) {

          
M tools/tilemaps.js +9 -8
@@ 128,14 128,15 @@ class Tmx {
 		this.path = path;
 	}
 
-	async parse() {
+	async parse(gamma) {
+		checkTypes(arguments, "number");
 		const xml = await xml2js.parseStringPromise(await fs.promises.readFile(this.path));
-		return this.parseMap(xml.map);
+		return this.parseMap(xml.map, gamma);
 	}
 
-	async parseMap(mapXml) {
-		checkTypes(arguments, Object);
-		const tileSet = await this.parseSet(mapXml.tileset[0]);
+	async parseMap(mapXml, gamma) {
+		checkTypes(arguments, Object, "number");
+		const tileSet = await this.parseSet(mapXml.tileset[0], gamma);
 		const tileMap = new TileMap(this.name, ~~mapXml.$.width, ~~mapXml.$.height, tileSet);
 		const indices = mapXml.layer[0].data[0]._.replace(/\s/g, "").split(",").map(i => ~~i - 1);
 		for (const index of indices) {

          
@@ 144,10 145,10 @@ class Tmx {
 		return tileMap;
 	}
 
-	async parseSet(setXml) {
-		checkTypes(arguments, Object);
+	async parseSet(setXml, gamma) {
+		checkTypes(arguments, Object, "number");
 		const imagepath = path.resolve(path.dirname(this.path), setXml.image[0].$.source);
-		const image = await new PNGLoader(imagepath).loadImage();
+		const image = await new PNGLoader(imagepath, gamma).loadImage();
 		const tileSet = new TileSet(setXml.$.name, ~~setXml.$.tilewidth, ~~setXml.$.tileheight, image.palette);
 		const tileImages = image.toTiles(tileSet.width, tileSet.height);
 		for (let i = 0; i < tileImages.length; i++) {