|
- import Utils from "/app/js/common/Utils.js";
- import {EventCaller} from "/app/js/common/EventCaller.js";
- import NESPalette from "/app/js/models/NESPalette.js";
-
-
- function BitMask(offset, inv){
- switch(offset){
- case 0:
- return parseInt((inv === true) ? '01111111' : '10000000', 2);
- case 1:
- return parseInt((inv === true) ? '10111111' : '01000000', 2);
- case 2:
- return parseInt((inv === true) ? '11011111' : '00100000', 2);
- case 3:
- return parseInt((inv === true) ? '11101111' : '00010000', 2);
- case 4:
- return parseInt((inv === true) ? '11110111' : '00001000', 2);
- case 5:
- return parseInt((inv === true) ? '11111011' : '00000100', 2);
- case 6:
- return parseInt((inv === true) ? '11111101' : '00000010', 2);
- }
- return parseInt((inv === true) ? '11111110' : '00000001', 2);
- }
-
-
- var BLOCK_CHANGE_EMIT = false; // This will block the "data_changed" event when class is processing
- // lots of changes.
-
-
- export default class NESTile extends EventCaller{
- constructor(){
- super();
- this.__paletteIndex = 0;
- this.__data = new Uint8Array(16);
-
- this.__pixels = new Proxy(this, {
- get: function(obj, prop){
- if (prop === "length")
- return 64;
- if (!Utils.isInt(prop))
- throw new TypeError("Expected integer index.");
- if (prop < 0 || prop >= 64)
- throw new RangeError("Index out of bounds.");
- var dindex = Math.floor(prop*0.125);
- var bitoffset = 7 - (prop%8);
- var v = (obj.__data[dindex] & (1 << bitoffset)) >> bitoffset;
- v += 2*((obj.__data[8+dindex] & (1 << bitoffset)) >> bitoffset);
- return v;
- },
-
-
- set: function(obj, prop, value){
- if (!Utils.isInt(prop))
- throw new TypeError("Expected integer index.");
- prop = parseInt(prop);
- if (!Utils.isInt(value))
- throw new TypeError("Color index expected to be integer.");
- if (prop < 0 || prop >= 64)
- throw new RangeError("Index out of bounds.");
- if (value < 0 || value >= 4)
- throw new RangeError("Color index out of bounds.");
- var dindex = Math.floor(prop*0.125);
- var bitoffset = (prop % 8);
- if (value == 1 || value == 3){
- obj.__data[dindex] |= BitMask(bitoffset);
- } else {
- obj.__data[dindex] &= BitMask(bitoffset, true);
- }
- if (value == 2 || value == 3){
- obj.__data[8+dindex] |= BitMask(bitoffset);
- } else {
- obj.__data[8+dindex] &= BitMask(bitoffset, true);
- }
- if (!BLOCK_CHANGE_EMIT)
- obj.emit("data_changed");
- return true;
- }
- });
- }
-
- get width(){return 8;}
- get height(){return 8;}
-
- get pixels(){
- return this.__pixels;
- }
-
- get dataArray(){
- var d = [];
- for (var y = 0; y < 8; y++){
- for (var x = 0; x < 8; x++){
- d.push(this.getPixelIndex(x, y));
- }
- }
- return d;
- }
-
- get chr(){
- return new Uint8Array(this.__data);
- }
-
- set chr(buff){
- if (!(buff instanceof Uint8Array))
- throw new TypeError("Expected Uint8Array buffer");
- if (buff.length !== 16)
- throw new RangeError("Buffer contains invalid byte length.");
- this.__data = new Uint8Array(buff);
- this.emit("data_changed");
- }
-
- get base64(){
- var b = ""
- for (var i = 0; i < this.__data.length; i++) {
- b += String.fromCharCode(this.__data[i]);
- }
- b += String.fromCharCode(this.__paletteIndex);
- return window.btoa(b);
- }
- set base64(s){
- var b = window.atob(s);
- var len = b.length;
- if (b.length !== 17){
- throw new Error("Base64 string contains invalid byte count.");
- }
- var bytes = new Uint8Array(b.length-1);
- for (var i=0; i < b.length-1; i++){
- bytes[i] = b.charCodeAt(i);
- }
- this.__data = bytes;
- this.__paletteIndex = b.charCodeAt(b.length-1);
- this.emit("data_changed");
- }
-
-
- get paletteIndex(){return this.__paletteIndex;}
- set paletteIndex(pi){
- if (!Utils.isInt(pi))
- throw new TypeError("Palette index expected to be an integer.");
- if (pi < 0 || pi >= 4){
- throw new RangeError("Palette index out of bounds.");
- }
- this.__paletteIndex = pi;
- this.emit("data_changed");
- }
-
- setPixelIndex(x, y, ci){
- if (x < 0 || x >= 8 || y < 0 || y >= 8){
- throw new ValueError("Coordinates out of bounds.");
- }
- if (ci < 0 || ci >= 4){
- throw new ValueError("Color index out of bounds.");
- }
- this.__pixels[(y*8)+x] = ci;
- return this;
- }
-
- getPixelIndex(x, y){
- if (x < 0 || x >= 8 || y < 0 || y >= 8){
- throw new ValueError("Coordinates out of bounds.");
- }
- return this.__pixels[(8*y) + x];
- }
-
- flip(flag){
- if (flag >= 1 && flag <= 3){
- var oldData = this.__data;
- var newData = new Uint8Array(16);
- BLOCK_CHANGE_EMIT = true;
- for (var x = 0; x < 8; x++){
- for (var y = 0; y < 8; y++){
- this.__data = oldData;
- var ci = this.getPixelIndex(x, y);
- this.__data = newData;
- this.setPixelIndex(
- (flag == 1 || flag == 3) ? 7 - x : x,
- (flag == 2 || flag == 3) ? 7 - y : y,
- ci
- );
- }
- }
- BLOCK_CHANGE_EMIT = false;
- this.emit("data_changed");
- }
- return this;
- }
-
-
- clone(){
- return (new NESTile()).copy(this);
- }
-
- copy(t){
- if (!(t instanceof NESTile))
- throw new TypeError("Expected NESTile object.");
- this.__data.set(t.__data);
- this.emit("data_changed");
- return this;
- }
-
- clear(){
- this.__data = new Uint8Array(16);
- this.emit("data_changed");
- return this;
- }
-
- isEmpty(){
- for (let i=0; i < this.__data.length; i++){
- if (this.__data[i] !== 0)
- return false;
- }
- return true;
- }
-
- isEq(tile, sameOrientation){
- if (!(tile instanceof NESTile)){
- throw new TypeError("Expected NESTile instance.");
- }
- sameOrientation = (sameOrientation === true);
- var b64 = this.base64;
- if (tile.base64 === b64){
- return 0;
- }
- if (!sameOrientation){
- var tc = tile.clone().flip(1); // Flip horizontal.
- if (tc.base64 === b64){
- return 1;
- }
-
- tc.flip(3); // Flip horizontal AND verticle. Net effect is the same as tile.clone().flip(2) ... Flip Verticle
- if (tc.base64 === b64){
- return 2;
- }
-
- tc.flip(1); // Flip horizontal again. Net effect is the same as tile.clone().flip(3) ... flip H & V
- if (tc.base64 === b64){
- return 3;
- }
- }
- return -1;
- }
- }
-
-
|