|
|
@@ -25,12 +25,13 @@ function CnvIdx(x, y, am, off){ |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
res.side = Math.floor(off * 0.5); |
|
|
|
res.tileidx = (res.side*32) + ((Math.floor(y/8) * 16) + Math.floor(x / 8)); |
|
|
|
off -= (off > 1) ? 2 : 0; |
|
|
|
res.tileidx = (off*128) + ((Math.floor(y/8) * 16) + Math.floor(x / 8)); |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
res.side = Math.floor(off * 0.25); |
|
|
|
off -= (off > 3) ? 4 : 0; |
|
|
|
res.tileidx = (off * 16) + ((Math.floor(y/8) * 16) + Math.floor(x / 8)); |
|
|
|
res.tileidx = (off * 64) + ((Math.floor(y/8) * 16) + Math.floor(x / 8)); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
@@ -40,30 +41,40 @@ function CnvIdx(x, y, am, off){ |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
function LRIdx2TileIdxCo(index, lid){ |
|
|
|
if (isNaN(lid) || lid < 0 || lid > 2){ |
|
|
|
lid = 2; |
|
|
|
} |
|
|
|
var res = { |
|
|
|
lid: 0, |
|
|
|
index: 0, |
|
|
|
x: 0, |
|
|
|
y: 0 |
|
|
|
}; |
|
|
|
var w = (lid == 2) ? 256 : 128; |
|
|
|
var x = Math.floor(index % w); |
|
|
|
var y = Math.floor(index / w); |
|
|
|
if (x < 128){ |
|
|
|
res.index = (Math.floor(y/8) * 16) + Math.floor(x / 8); |
|
|
|
if (lid !== 2) |
|
|
|
res.lid = lid; |
|
|
|
} else { |
|
|
|
res.index = (Math.floor(y/8) * 16) + Math.floor((x - 128) / 8); |
|
|
|
res.lid = 1; |
|
|
|
|
|
|
|
function AdjOffsetToNewMode(nmode, omode, ooff){ |
|
|
|
// NOTE: 8K never shows up because it will ALWAYS return an offset of 0, so it's easier to just let it all fall through |
|
|
|
// to the default return value. |
|
|
|
switch(nmode){ |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
if (ooff > 1){ |
|
|
|
switch(omode){ |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
return Math.floor(ooff * 0.5); |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
return Math.floor(ooff * 0.25); |
|
|
|
} |
|
|
|
} |
|
|
|
return ooff; |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
switch(omode){ |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
return ooff * 2; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
return Math.floor(ooff * 0.5); |
|
|
|
} |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
switch(omode){ |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
return ooff * 4; |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
return ooff * 2; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
res.x = x % 8; |
|
|
|
res.y = y % 8; |
|
|
|
return res; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -120,64 +131,32 @@ export default class NESBank extends ISurface{ |
|
|
|
set access_mode(m){ |
|
|
|
if (!Utils.isInt(m)) |
|
|
|
throw new TypeError("Access mode expected to be integer."); |
|
|
|
var oam = this.__AccessMode; |
|
|
|
switch(m){ |
|
|
|
case NESBank.ACCESSMODE_8K: |
|
|
|
this.__AccessMode = NESBank.ACCESSMODE_8K; |
|
|
|
this.__AccessOffset = 0; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
if (this.__AccessOffset > 1){ |
|
|
|
switch(this.__AccessMode){ |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
this.__AccessOffset = Math.floor(this.__AccessOffset * 0.5); |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
this.__AccessOffset = Math.floor(this.__AccessOffset * 0.25); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
this.__AccessMode = NESBank.ACCESSMODE_4K |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
switch(this.__AccessMode){ |
|
|
|
case NESBank.ACCESSMODE_8K: |
|
|
|
this.__AccessOffset = 0; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
this.__AccessOffset *= 2; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
this.__AccessOffset = Math.floor(this.__AccessOffset * 0.5); |
|
|
|
break; |
|
|
|
} |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
this.__AccessMode = NESBank.ACCESSMODE_2K; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_1K: |
|
|
|
switch(this.__AccessMode){ |
|
|
|
case NESBank.ACCESSMODE_8K: |
|
|
|
this.__AccessOffset = 0; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_4K: |
|
|
|
this.__AccessOffset *= 4; |
|
|
|
break; |
|
|
|
case NESBank.ACCESSMODE_2K: |
|
|
|
this.__AccessOffset *= 2; |
|
|
|
break; |
|
|
|
} |
|
|
|
this.__AccessMode = NESBank.ACCESSMODE_1K; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
throw new ValueError("Unknown Access Mode."); |
|
|
|
} |
|
|
|
|
|
|
|
this.__AccessOffset = AdjOffsetToNewMode(m, oam, this.__AccessOffset); |
|
|
|
if (this.__emitsEnabled) |
|
|
|
this.emit("data_changed"); |
|
|
|
} |
|
|
|
|
|
|
|
get access_offset(){return this.__AccessOffset;} |
|
|
|
set access_offset(o){ |
|
|
|
if (!Utils.isInt(m)) |
|
|
|
if (!Utils.isInt(o)) |
|
|
|
throw new TypeError("Access offset expected to be integer."); |
|
|
|
switch (this.__AccessMode){ |
|
|
|
case NESBank.ACCESSMODE_8K: |
|
|
@@ -198,7 +177,7 @@ export default class NESBank extends ISurface{ |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
this.__AccessOffset = m; |
|
|
|
this.__AccessOffset = o; |
|
|
|
if (this.__emitsEnabled) |
|
|
|
this.emit("data_changed"); |
|
|
|
} |
|
|
@@ -272,21 +251,11 @@ export default class NESBank extends ISurface{ |
|
|
|
return buff; |
|
|
|
} |
|
|
|
|
|
|
|
/*set chr(buff){ |
|
|
|
set chr(buff){ |
|
|
|
if (!(buff instanceof Uint8Array)) |
|
|
|
throw new TypeError("Expected Uint8Array buffer."); |
|
|
|
if (buff.length !== 8192) |
|
|
|
throw new RangeError("Data buffer has invalid byte length."); |
|
|
|
var offset = 0; |
|
|
|
this.__LP.forEach((i) => { |
|
|
|
i.chr = buff.slice(offset, offset+15); |
|
|
|
offset += 16; |
|
|
|
}); |
|
|
|
this.__RP.forEach((i) => { |
|
|
|
i.chr = buff.slice(offset, offset+15); |
|
|
|
offset += 16; |
|
|
|
}); |
|
|
|
}*/ |
|
|
|
this.setCHR(buff); |
|
|
|
} |
|
|
|
|
|
|
|
get base64(){ |
|
|
|
var b = ""; |
|
|
@@ -461,49 +430,57 @@ export default class NESBank extends ISurface{ |
|
|
|
} |
|
|
|
|
|
|
|
setCHR(buff, offset){ |
|
|
|
if (!Utils.isInt(offset) || offset < 0) |
|
|
|
offset = 0; |
|
|
|
if (!Utils.isInt(offset)) |
|
|
|
offset = -1; |
|
|
|
|
|
|
|
var idx = 0; |
|
|
|
switch(buff.length){ |
|
|
|
case 8192: |
|
|
|
if (offset < 0) |
|
|
|
offset = AdjOffsetToNewMode(NESBank.ACCESSMODE_8K, this.__AccessMode, this.__AccessOffset); |
|
|
|
this.__LP.forEach((i) => { |
|
|
|
i.chr = buff.slice(idx, idx+15); |
|
|
|
i.chr = buff.slice(idx, idx+16); |
|
|
|
idx += 16; |
|
|
|
}); |
|
|
|
this.__RP.forEach((i) => { |
|
|
|
i.chr = buff.slice(idx, idx+15); |
|
|
|
i.chr = buff.slice(idx, idx+16); |
|
|
|
idx += 16; |
|
|
|
}); |
|
|
|
break; |
|
|
|
case 4096: |
|
|
|
if (offset < 0) |
|
|
|
offset = AdjOffsetToNewMode(NESBank.ACCESSMODE_4K, this.__AccessMode, this.__AccessOffset); |
|
|
|
if (offset >= 2) |
|
|
|
throw new RangeError("Offset mismatch based on Buffer length."); |
|
|
|
var list = (offset === 0) ? this.__LP : this.__RP; |
|
|
|
list.forEach((i) => { |
|
|
|
i.chr = buff.slice(idx, idx+15); |
|
|
|
i.chr = buff.slice(idx, idx+16); |
|
|
|
idx += 16; |
|
|
|
}); |
|
|
|
break; |
|
|
|
case 2048: |
|
|
|
if (offset < 0) |
|
|
|
offset = AdjOffsetToNewMode(NESBank.ACCESSMODE_2K, this.__AccessMode, this.__AccessOffset); |
|
|
|
if (offset >= 4) |
|
|
|
throw new RangeError("Offset mismatch based on Buffer length."); |
|
|
|
var list = (offset < 2) ? this.__LP : this.__RP; |
|
|
|
var s = Math.floor(offset * 0.5) * 128; |
|
|
|
var e = s + 128; |
|
|
|
for (let i=s; i < e; i++){ |
|
|
|
list[i].chr = buff.slice(idx, idx+15); |
|
|
|
list[i].chr = buff.slice(idx, idx+16); |
|
|
|
idx += 16; |
|
|
|
} |
|
|
|
break; |
|
|
|
case 1024: |
|
|
|
if (offset < 0) |
|
|
|
offset = AdjOffsetToNewMode(NESBank.ACCESSMODE_1K, this.__AccessMode, this.__AccessOffset); |
|
|
|
if (offset >= 8) |
|
|
|
throw new RangeError("Offset mismatch based on Buffer length."); |
|
|
|
var list = (offset < 4) ? this.__LP : this.__RP; |
|
|
|
var s = Math.floor(this.__AccessOffset * 0.25) * 64; |
|
|
|
var e = s + 64; |
|
|
|
for (let i=s; i < e; i++){ |
|
|
|
list[i].chr = buff.slice(idx, idx+15); |
|
|
|
list[i].chr = buff.slice(idx, idx+16); |
|
|
|
idx += 16; |
|
|
|
} |
|
|
|
break; |