mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-29 14:51:17 +00:00
fixed VDP
This commit is contained in:
parent
8a1c88f3de
commit
385cb7acc2
@ -137,7 +137,7 @@ const _ColecoVisionPlatform = function(mainElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
vdp = new TMS9918A(video.canvas, cru, true); // true = 4 sprites/line
|
vdp = new TMS9918A(video.getFrameData(), cru, true); // true = 4 sprites/line
|
||||||
setKeyboardFromMap(video, inputs, COLECOVISION_KEYCODE_MAP);
|
setKeyboardFromMap(video, inputs, COLECOVISION_KEYCODE_MAP);
|
||||||
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||||
}
|
}
|
||||||
@ -149,10 +149,9 @@ const _ColecoVisionPlatform = function(mainElement) {
|
|||||||
advance(novideo : boolean) {
|
advance(novideo : boolean) {
|
||||||
for (var sl=0; sl<numTotalScanlines; sl++) {
|
for (var sl=0; sl<numTotalScanlines; sl++) {
|
||||||
this.runCPU(cpu, cpuCyclesPerLine);
|
this.runCPU(cpu, cpuCyclesPerLine);
|
||||||
if (sl < numVisibleScanlines)
|
|
||||||
vdp.drawScanline(sl);
|
vdp.drawScanline(sl);
|
||||||
}
|
}
|
||||||
vdp.updateCanvas();
|
video.updateFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
|
@ -121,7 +121,7 @@ const _SG1000Platform = function(mainElement, isSMS:boolean) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var vdpclass = isSMS ? SMSVDP : TMS9918A;
|
var vdpclass = isSMS ? SMSVDP : TMS9918A;
|
||||||
vdp = new vdpclass(video.canvas, cru, true); // true = 4 sprites/line
|
vdp = new vdpclass(video.getFrameData(), cru, true); // true = 4 sprites/line
|
||||||
setKeyboardFromMap(video, inputs, SG1000_KEYCODE_MAP);
|
setKeyboardFromMap(video, inputs, SG1000_KEYCODE_MAP);
|
||||||
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||||
}
|
}
|
||||||
@ -134,10 +134,9 @@ const _SG1000Platform = function(mainElement, isSMS:boolean) {
|
|||||||
for (var sl=0; sl<numTotalScanlines; sl++) {
|
for (var sl=0; sl<numTotalScanlines; sl++) {
|
||||||
this.currentScanline = sl;
|
this.currentScanline = sl;
|
||||||
this.runCPU(cpu, cpuCyclesPerLine);
|
this.runCPU(cpu, cpuCyclesPerLine);
|
||||||
if (sl < numVisibleScanlines)
|
|
||||||
vdp.drawScanline(sl);
|
vdp.drawScanline(sl);
|
||||||
}
|
}
|
||||||
vdp.updateCanvas();
|
video.updateFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadROM(title, data) {
|
loadROM(title, data) {
|
||||||
|
@ -17,18 +17,17 @@ enum TMS9918A_Mode {
|
|||||||
TEXT = 1,
|
TEXT = 1,
|
||||||
BITMAP = 2,
|
BITMAP = 2,
|
||||||
MULTICOLOR = 3,
|
MULTICOLOR = 3,
|
||||||
BITMAP_TEXT = 4,
|
MODE4 = 4,
|
||||||
BITMAP_MULTICOLOR = 5,
|
BITMAP_TEXT = 5,
|
||||||
ILLEGAL = 6,
|
BITMAP_MULTICOLOR = 6,
|
||||||
MODE4 = 7,
|
ILLEGAL = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
interface CPUInterface {
|
||||||
* @constructor
|
setVDPInterrupt(b:boolean);
|
||||||
*/
|
}
|
||||||
export class TMS9918A {
|
|
||||||
|
|
||||||
canvas;
|
export class TMS9918A {
|
||||||
|
|
||||||
cru : { setVDPInterrupt: (b:boolean) => void };
|
cru : { setVDPInterrupt: (b:boolean) => void };
|
||||||
enableFlicker : boolean;
|
enableFlicker : boolean;
|
||||||
@ -63,16 +62,14 @@ export class TMS9918A {
|
|||||||
flicker : boolean;
|
flicker : boolean;
|
||||||
redrawRequired : boolean;
|
redrawRequired : boolean;
|
||||||
|
|
||||||
canvasContext;
|
fb32 : Uint32Array;
|
||||||
imageData;
|
|
||||||
datau32;
|
|
||||||
|
|
||||||
width : number;
|
width : number;
|
||||||
height : number;
|
height : number;
|
||||||
|
|
||||||
constructor(canvas, cru, enableFlicker:boolean) {
|
constructor(fb32:Uint32Array, cru:CPUInterface, enableFlicker:boolean) {
|
||||||
|
|
||||||
this.canvas = canvas;
|
this.fb32 = fb32;
|
||||||
this.cru = cru;
|
this.cru = cru;
|
||||||
this.enableFlicker = enableFlicker;
|
this.enableFlicker = enableFlicker;
|
||||||
|
|
||||||
@ -95,7 +92,6 @@ export class TMS9918A {
|
|||||||
RGBA(255, 255, 255)
|
RGBA(255, 255, 255)
|
||||||
];
|
];
|
||||||
|
|
||||||
this.canvasContext = this.canvas.getContext("2d");
|
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,33 +129,12 @@ export class TMS9918A {
|
|||||||
this.flicker = this.enableFlicker;
|
this.flicker = this.enableFlicker;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
|
|
||||||
this.canvas.width = 304;
|
this.width = 304;
|
||||||
this.canvas.height = 240;
|
this.height = 240;
|
||||||
this.canvasContext.fillStyle = '#'+hex(this.palette[7],6);
|
|
||||||
this.canvasContext.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
|
|
||||||
// Build the array containing the canvas bitmap (256 * 192 * 4 bytes (r,g,b,a) format each pixel)
|
|
||||||
this.imageData = this.canvasContext.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
this.datau32 = new Uint32Array(this.imageData.data.buffer);
|
|
||||||
this.width = this.canvas.width;
|
|
||||||
this.height = this.canvas.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
drawFrame(timestamp:number) {
|
|
||||||
if (this.redrawRequired) {
|
|
||||||
for (var y = 0; y < this.height; y++) {
|
|
||||||
this.drawScanline(y);
|
|
||||||
}
|
|
||||||
this.updateCanvas();
|
|
||||||
this.redrawRequired = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initFrame(timestamp:number) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawScanline(y:number) {
|
drawScanline(y:number) {
|
||||||
var imageData = this.datau32,
|
var imageData = this.fb32,
|
||||||
width = this.width,
|
width = this.width,
|
||||||
imageDataAddr = (y * width),
|
imageDataAddr = (y * width),
|
||||||
screenMode = this.screenMode,
|
screenMode = this.screenMode,
|
||||||
@ -350,10 +325,6 @@ export class TMS9918A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCanvas() {
|
|
||||||
this.canvasContext.putImageData(this.imageData, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
setReadAddress(i:number) {
|
setReadAddress(i:number) {
|
||||||
this.addressRegister = ((i & 0x3f) << 8) | (this.addressRegister & 0x00FF);
|
this.addressRegister = ((i & 0x3f) << 8) | (this.addressRegister & 0x00FF);
|
||||||
this.prefetchByte = this.ram[this.addressRegister++];
|
this.prefetchByte = this.ram[this.addressRegister++];
|
||||||
@ -533,7 +504,7 @@ export class TMS9918A {
|
|||||||
|
|
||||||
readStatus() : number {
|
readStatus() : number {
|
||||||
var i = this.statusRegister;
|
var i = this.statusRegister;
|
||||||
this.statusRegister = 0x1F;
|
this.statusRegister = 0x1F; // TODO: &= 0x1f?
|
||||||
if (this.interruptsOn) {
|
if (this.interruptsOn) {
|
||||||
this.cru.setVDPInterrupt(false);
|
this.cru.setVDPInterrupt(false);
|
||||||
}
|
}
|
||||||
@ -572,7 +543,16 @@ export class TMS9918A {
|
|||||||
return 0x800;
|
return 0x800;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getDebugTables() {
|
||||||
|
var tables : [string,number,number][] = [
|
||||||
|
["Pattern Table", this.charPatternTable, this.patternTableSize()],
|
||||||
|
["Name Table", this.nameTable, 0x300],
|
||||||
|
["Color Table", this.colorTable, this.colorTableSize()],
|
||||||
|
["Sprite Patterns", this.spritePatternTable, 64*32],
|
||||||
|
["Sprite Attributes", this.spriteAttributeTable, 4*32],
|
||||||
|
];
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
getRegsString() : string {
|
getRegsString() : string {
|
||||||
const w = 20;
|
const w = 20;
|
||||||
var s = "Registers:";
|
var s = "Registers:";
|
||||||
@ -580,13 +560,7 @@ export class TMS9918A {
|
|||||||
s += " " + hex(this.registers[i],2);
|
s += " " + hex(this.registers[i],2);
|
||||||
}
|
}
|
||||||
s += "\n\n";
|
s += "\n\n";
|
||||||
var tables : [string,number,number][] = [
|
var tables = this.getDebugTables();
|
||||||
["Pattern Table", this.charPatternTable, this.patternTableSize()],
|
|
||||||
["Image Table", this.nameTable, 0x300],
|
|
||||||
["Color Table", this.colorTable, this.colorTableSize()],
|
|
||||||
["Sprite Patterns", this.spritePatternTable, 64*32],
|
|
||||||
["Sprite Attributes", this.spriteAttributeTable, 4*32],
|
|
||||||
];
|
|
||||||
for (var row of tables) {
|
for (var row of tables) {
|
||||||
if (row[2] > 0)
|
if (row[2] > 0)
|
||||||
s += lpad(row[0], w) + ": $" + hex(row[1],4) + " - $" + hex(row[1]+row[2]-1,4) + "\n";
|
s += lpad(row[0], w) + ": $" + hex(row[1],4) + " - $" + hex(row[1]+row[2]-1,4) + "\n";
|
||||||
@ -701,14 +675,15 @@ export class SMSVDP extends TMS9918A {
|
|||||||
writeToCRAM : boolean;
|
writeToCRAM : boolean;
|
||||||
cram = new Uint8Array(32); // color RAM
|
cram = new Uint8Array(32); // color RAM
|
||||||
cpalette = new Uint32Array(32); // color RAM (RGBA)
|
cpalette = new Uint32Array(32); // color RAM (RGBA)
|
||||||
registers = new Uint8Array(16); // 8 more registers
|
registers = new Uint8Array(16); // 8 more registers (actually only 5)
|
||||||
|
vramUntwiddled = new Uint8Array(0x8000);
|
||||||
|
spriteBufferBackground = new Uint8Array(256);
|
||||||
|
|
||||||
updateMode(reg0:number, reg1:number) {
|
updateMode(reg0:number, reg1:number) {
|
||||||
if (reg0 & 0x04) {
|
if (reg0 & 0x04) {
|
||||||
this.screenMode = TMS9918A_Mode.MODE4;
|
this.screenMode = TMS9918A_Mode.MODE4;
|
||||||
this.nameTable = (this.registers[2] & 0xf) << 10;
|
this.nameTable = ((this.registers[2] & 0xf) << 10) & 0x3800;
|
||||||
this.spriteAttributeTable = (this.registers[5] & 0x7f) << 7;
|
this.spriteAttributeTable = (this.registers[5] & 0x7e) << 7;
|
||||||
this.spritePatternTable = (this.registers[6] & 0x7) << 11;
|
|
||||||
} else {
|
} else {
|
||||||
super.updateMode(reg0, reg1);
|
super.updateMode(reg0, reg1);
|
||||||
}
|
}
|
||||||
@ -724,6 +699,7 @@ export class SMSVDP extends TMS9918A {
|
|||||||
setVDPWriteRegister(i:number) {
|
setVDPWriteRegister(i:number) {
|
||||||
super.setVDPWriteRegister(i);
|
super.setVDPWriteRegister(i);
|
||||||
this.writeToCRAM = false;
|
this.writeToCRAM = false;
|
||||||
|
this.ramMask = 0x3fff;
|
||||||
}
|
}
|
||||||
setVDPWriteCommand3(i:number) {
|
setVDPWriteCommand3(i:number) {
|
||||||
this.writeToCRAM = true;
|
this.writeToCRAM = true;
|
||||||
@ -736,7 +712,25 @@ export class SMSVDP extends TMS9918A {
|
|||||||
this.addressRegister &= this.ramMask;
|
this.addressRegister &= this.ramMask;
|
||||||
this.redrawRequired = true;
|
this.redrawRequired = true;
|
||||||
} else {
|
} else {
|
||||||
|
var oldAddress = this.addressRegister;
|
||||||
super.writeData(i);
|
super.writeData(i);
|
||||||
|
this.writeTwiddled(oldAddress, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeTwiddled(vdp_addr:number, val:number) {
|
||||||
|
var planarBase = vdp_addr & 0x3ffc;
|
||||||
|
var twiddledBase = planarBase * 2;
|
||||||
|
var val0 = this.ram[planarBase];
|
||||||
|
var val1 = this.ram[planarBase + 1];
|
||||||
|
var val2 = this.ram[planarBase + 2];
|
||||||
|
var val3 = this.ram[planarBase + 3];
|
||||||
|
for (var i = 0; i < 8; ++i) {
|
||||||
|
var effectiveBit = 7 - i;
|
||||||
|
var index = (((val0 >>> effectiveBit) & 1))
|
||||||
|
| (((val1 >>> effectiveBit) & 1) << 1)
|
||||||
|
| (((val2 >>> effectiveBit) & 1) << 2)
|
||||||
|
| (((val3 >>> effectiveBit) & 1) << 3);
|
||||||
|
this.vramUntwiddled[twiddledBase + i] = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getState() {
|
getState() {
|
||||||
@ -750,12 +744,13 @@ export class SMSVDP extends TMS9918A {
|
|||||||
}
|
}
|
||||||
drawScanline(y:number) {
|
drawScanline(y:number) {
|
||||||
if (this.screenMode == TMS9918A_Mode.MODE4) // TODO: check for other uses
|
if (this.screenMode == TMS9918A_Mode.MODE4) // TODO: check for other uses
|
||||||
this.drawScanlineMode4(y); // special mode 4
|
//this.drawScanlineMode4(y);
|
||||||
|
this.rasterize_line(y); // special mode 4
|
||||||
else
|
else
|
||||||
super.drawScanline(y);
|
super.drawScanline(y);
|
||||||
}
|
}
|
||||||
drawScanlineMode4(y:number) {
|
drawScanlineMode4(y:number) {
|
||||||
var imageData = this.datau32,
|
var imageData = this.fb32,
|
||||||
width = this.width,
|
width = this.width,
|
||||||
imageDataAddr = (y * width),
|
imageDataAddr = (y * width),
|
||||||
drawWidth = 256,
|
drawWidth = 256,
|
||||||
@ -814,7 +809,6 @@ export class SMSVDP extends TMS9918A {
|
|||||||
var sx = ram[spriteAttributeTable + s*2 + 0x80];
|
var sx = ram[spriteAttributeTable + s*2 + 0x80];
|
||||||
var sPatternNo = ram[spriteAttributeTable + s*2 + 0x81];
|
var sPatternNo = ram[spriteAttributeTable + s*2 + 0x81];
|
||||||
var sColor = 0; // TODO
|
var sColor = 0; // TODO
|
||||||
//var sColor = ram[spriteAttributeAddr + 3] & 0x0F;
|
|
||||||
//if ((ram[spriteAttributeAddr + 3] & 0x80) !== 0) {
|
//if ((ram[spriteAttributeAddr + 3] & 0x80) !== 0) {
|
||||||
// sx -= 32;
|
// sx -= 32;
|
||||||
//}
|
//}
|
||||||
@ -857,15 +851,7 @@ export class SMSVDP extends TMS9918A {
|
|||||||
var nameOfs = nameTable + rowOffset + ((x1 >> 3) << 1);
|
var nameOfs = nameTable + rowOffset + ((x1 >> 3) << 1);
|
||||||
name = ram[nameOfs] + (ram[nameOfs+1] << 8);
|
name = ram[nameOfs] + (ram[nameOfs+1] << 8);
|
||||||
var patofs = ((((name & 0x1ff) << 3) + lineOffset) << 2);
|
var patofs = ((((name & 0x1ff) << 3) + lineOffset) << 2);
|
||||||
var pat0 = ram[patofs+0];
|
color = this.vramUntwiddled[patofs*2 + (x1&7)];
|
||||||
var pat1 = ram[patofs+1];
|
|
||||||
var pat2 = ram[patofs+2];
|
|
||||||
var pat3 = ram[patofs+3];
|
|
||||||
pat0 >>= x1 & 7;
|
|
||||||
pat1 >>= x1 & 7;
|
|
||||||
pat2 >>= x1 & 7;
|
|
||||||
pat3 >>= x1 & 7;
|
|
||||||
color = (pat0&1) | ((pat1&1)<<1) | ((pat2&1)<<2) | ((pat3&1)<<3);
|
|
||||||
if (color === 0) {
|
if (color === 0) {
|
||||||
color = bgColor;
|
color = bgColor;
|
||||||
}
|
}
|
||||||
@ -908,5 +894,232 @@ export class SMSVDP extends TMS9918A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findSprites(line:number) {
|
||||||
|
var spriteInfo = this.spriteAttributeTable;
|
||||||
|
var active = [];
|
||||||
|
var spriteHeight = 8;
|
||||||
|
var i;
|
||||||
|
if (this.registers[1] & 2) {
|
||||||
|
spriteHeight = 16;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
var y = this.ram[spriteInfo + i];
|
||||||
|
if (y === 208) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (y >= 240) y -= 256;
|
||||||
|
if (line >= y && line < (y + spriteHeight)) {
|
||||||
|
if (active.length === 8) {
|
||||||
|
this.statusRegister |= 0x40; // Sprite overflow
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
active.push([
|
||||||
|
this.ram[spriteInfo + 128 + i * 2],
|
||||||
|
this.ram[spriteInfo + 128 + i * 2 + 1],
|
||||||
|
y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rasterize_background(lineAddr:number, pixelOffset:number, tileData:number, tileDef:number, transparent:boolean) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
pixelOffset = pixelOffset | 0;
|
||||||
|
tileData = tileData | 0;
|
||||||
|
tileDef = (tileDef | 0) * 2;
|
||||||
|
var i, tileDefInc;
|
||||||
|
if ((tileData & (1 << 9))) {
|
||||||
|
tileDefInc = -1;
|
||||||
|
tileDef += 7;
|
||||||
|
} else {
|
||||||
|
tileDefInc = 1;
|
||||||
|
}
|
||||||
|
const paletteOffset = (tileData & (1 << 11)) ? 16 : 0;
|
||||||
|
var index;
|
||||||
|
if (transparent && paletteOffset === 0) {
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
index = this.vramUntwiddled[tileDef];
|
||||||
|
tileDef += tileDefInc;
|
||||||
|
if (index !== 0) this.fb32[lineAddr + pixelOffset] = this.cpalette[index];
|
||||||
|
pixelOffset = (pixelOffset + 1) & 255;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
index = this.vramUntwiddled[tileDef] + paletteOffset;
|
||||||
|
tileDef += tileDefInc;
|
||||||
|
this.fb32[lineAddr + pixelOffset] = this.cpalette[index];
|
||||||
|
pixelOffset = (pixelOffset + 1) & 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clear_background(lineAddr:number, pixelOffset:number) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
pixelOffset = pixelOffset | 0;
|
||||||
|
var i;
|
||||||
|
const rgb = this.cpalette[0];
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
this.fb32[lineAddr + pixelOffset] = rgb;
|
||||||
|
pixelOffset = (pixelOffset + 1) & 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rasterize_background_line(lineAddr:number, pixelOffset:number, nameAddr:number, yMod:number) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
pixelOffset = pixelOffset | 0;
|
||||||
|
nameAddr = nameAddr | 0;
|
||||||
|
const yOffset = (yMod | 0) * 4;
|
||||||
|
for (var i = 0; i < 32; i++) {
|
||||||
|
// TODO: static left-hand rows.
|
||||||
|
var tileData = this.ram[nameAddr + i * 2] | (this.ram[nameAddr + i * 2 + 1] << 8);
|
||||||
|
var tileNum = tileData & 511;
|
||||||
|
var tileDef = 32 * tileNum;
|
||||||
|
if (tileData & (1 << 10)) {
|
||||||
|
tileDef += 28 - yOffset;
|
||||||
|
} else {
|
||||||
|
tileDef += yOffset;
|
||||||
|
}
|
||||||
|
if ((tileData & (1 << 12)) === 0) {
|
||||||
|
this.rasterize_background(lineAddr, pixelOffset, tileData, tileDef, false);
|
||||||
|
} else {
|
||||||
|
this.clear_background(lineAddr, pixelOffset);
|
||||||
|
}
|
||||||
|
pixelOffset = (pixelOffset + 8) & 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rasterize_foreground_line(lineAddr:number, pixelOffset:number, nameAddr:number, yMod:number) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
pixelOffset = pixelOffset | 0;
|
||||||
|
nameAddr = nameAddr | 0;
|
||||||
|
const yOffset = (yMod | 0) * 4;
|
||||||
|
for (var i = 0; i < 32; i++) {
|
||||||
|
// TODO: static left-hand rows.
|
||||||
|
var tileData = this.ram[nameAddr + i * 2] | (this.ram[nameAddr + i * 2 + 1] << 8);
|
||||||
|
if ((tileData & (1 << 12)) === 0) continue;
|
||||||
|
var tileNum = tileData & 511;
|
||||||
|
var tileDef = 32 * tileNum;
|
||||||
|
if (tileData & (1 << 10)) {
|
||||||
|
tileDef += 28 - yOffset;
|
||||||
|
} else {
|
||||||
|
tileDef += yOffset;
|
||||||
|
}
|
||||||
|
this.rasterize_background(lineAddr, ((i * 8) + pixelOffset & 0xff), tileData, tileDef, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rasterize_sprites(line:number, lineAddr:number, pixelOffset:number, sprites) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
pixelOffset = pixelOffset | 0;
|
||||||
|
const spriteBase = (this.registers[6] & 4) ? 0x2000 : 0;
|
||||||
|
// TODO: sprite X-8 shift
|
||||||
|
// TODO: sprite double size
|
||||||
|
for (var i = 0; i < 256; ++i) {
|
||||||
|
var xPos = i;//(i + this.registers[8]) & 0xff;
|
||||||
|
var spriteFoundThisX = false;
|
||||||
|
var writtenTo = false;
|
||||||
|
var minDistToNext = 256;
|
||||||
|
for (var k = 0; k < sprites.length; k++) {
|
||||||
|
var sprite = sprites[k];
|
||||||
|
var offset = xPos - sprite[0];
|
||||||
|
// Sprite to the right of the current X?
|
||||||
|
if (offset < 0) {
|
||||||
|
// Find out how far it would be to skip to this sprite
|
||||||
|
var distToSprite = -offset;
|
||||||
|
// Keep the minimum distance to the next sprite to the right.
|
||||||
|
if (distToSprite < minDistToNext) minDistToNext = distToSprite;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (offset >= 8) continue;
|
||||||
|
spriteFoundThisX = true;
|
||||||
|
var spriteLine = line - sprite[2];
|
||||||
|
var spriteAddr = spriteBase + sprite[1] * 32 + spriteLine * 4;
|
||||||
|
var untwiddledAddr = spriteAddr * 2 + offset;
|
||||||
|
var index = this.vramUntwiddled[untwiddledAddr];
|
||||||
|
if (index === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (writtenTo) {
|
||||||
|
// We have a collision!.
|
||||||
|
this.statusRegister |= 0x20;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.fb32[lineAddr + ((pixelOffset + i - this.registers[8]) & 0xff)] = this.cpalette[16 + index];
|
||||||
|
writtenTo = true;
|
||||||
|
}
|
||||||
|
if (!spriteFoundThisX && minDistToNext > 1) {
|
||||||
|
// If we didn't find a sprite on this X, then we can skip ahead by the minimum
|
||||||
|
// dist to next (minus one to account for loop add)
|
||||||
|
i += minDistToNext - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
border_clear(lineAddr:number, count:number) {
|
||||||
|
lineAddr = lineAddr | 0;
|
||||||
|
count = count | 0;
|
||||||
|
const borderIndex = 16 + (this.registers[7] & 0xf);
|
||||||
|
const borderRGB = this.cpalette[borderIndex];
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
this.fb32[lineAddr + i] = borderRGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
rasterize_line(line:number) {
|
||||||
|
var vdp_regs = this.registers;
|
||||||
|
var drawHeight = 192; // TODO?
|
||||||
|
var hBorder = (this.width - 256) >> 1;
|
||||||
|
var vBorder = (this.height - 192) >> 1; // TODO?
|
||||||
|
line = (line - vBorder) | 0; // TODO?
|
||||||
|
const lineAddr = (line * this.width + hBorder) | 0;
|
||||||
|
if (!(line >= 0 && line < 224 && this.displayOn)) {
|
||||||
|
this.border_clear(lineAddr, this.width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((vdp_regs[1] & 64) === 0) {
|
||||||
|
this.border_clear(lineAddr, this.width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var effectiveLine = line + vdp_regs[9];
|
||||||
|
if (effectiveLine >= 224) {
|
||||||
|
effectiveLine -= 224;
|
||||||
|
}
|
||||||
|
const sprites = this.findSprites(line);
|
||||||
|
const pixelOffset = ((vdp_regs[0] & 64) && line < 16) ? 0 : vdp_regs[8];
|
||||||
|
const nameAddr = this.nameTable + (effectiveLine >>> 3) * 64;
|
||||||
|
const yMod = effectiveLine & 7;
|
||||||
|
|
||||||
|
this.rasterize_background_line(lineAddr, pixelOffset, nameAddr, yMod);
|
||||||
|
this.rasterize_sprites(line, lineAddr, pixelOffset, sprites);
|
||||||
|
this.rasterize_foreground_line(lineAddr, pixelOffset, nameAddr, yMod);
|
||||||
|
|
||||||
|
if (vdp_regs[0] & (1 << 5)) {
|
||||||
|
// Blank out left hand column.
|
||||||
|
this.border_clear(lineAddr, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == drawHeight) {
|
||||||
|
this.statusRegister |= 0x80;
|
||||||
|
if (this.interruptsOn) {
|
||||||
|
this.cru.setVDPInterrupt(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDebugTables() {
|
||||||
|
if (this.screenMode == TMS9918A_Mode.MODE4) {
|
||||||
|
var tables : [string,number,number][] = [
|
||||||
|
["Pattern Table", 0, 512*32],
|
||||||
|
["Name Table", this.nameTable, 32*32*2], // TODO: size
|
||||||
|
["Sprite Attributes", this.spriteAttributeTable, 256],
|
||||||
|
]
|
||||||
|
return tables;
|
||||||
|
} else {
|
||||||
|
return super.getDebugTables();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user