Space Invaders works on the desktop now
This commit is contained in:
parent
bc7ec763ca
commit
f09189c121
9 changed files with 269 additions and 116 deletions
|
|
@ -107,24 +107,24 @@ Component.subclass(ChipSet);
|
|||
|
||||
ChipSet.SI_1978 = {
|
||||
MODEL: 1978.1,
|
||||
STATUS0: {
|
||||
STATUS0: { // NOTE: STATUS0 not used by the SI_1978 ROMs; refer to STATUS1 instead
|
||||
PORT: 0,
|
||||
DIP4: 0x01, // self-test request at power up?
|
||||
ALWAYS_SET: 0x0E, // always set
|
||||
FIRE: 0x10, // 1 = fire
|
||||
LEFT: 0x20, // 1 = move left
|
||||
RIGHT: 0x40, // 1 = move right
|
||||
PORT7: 0x80 // some connection to (undocumented) port 7
|
||||
LEFT: 0x20, // 1 = left
|
||||
RIGHT: 0x40, // 1 = right
|
||||
PORT7: 0x80, // some connection to (undocumented) port 7
|
||||
ALWAYS_SET: 0x0E // always set
|
||||
},
|
||||
STATUS1: {
|
||||
PORT: 1,
|
||||
CREDIT: 0x01, // credit (coin slot)
|
||||
P2: 0x02, // 1 = 2P start
|
||||
P1: 0x04, // 1 = 1P start
|
||||
ALWAYS_SET: 0x08, // always set
|
||||
P1_FIRE: 0x10, // 1 = P1 fire (cocktail machines only?)
|
||||
P1_LEFT: 0x20, // 1 = P1 left (cocktail machines only?)
|
||||
P1_RIGHT: 0x40 // 1 = P1 right (cocktail machines only?)
|
||||
P1_FIRE: 0x10, // 1 = fire (P1 fire if cocktail machine?)
|
||||
P1_LEFT: 0x20, // 1 = left (P1 left if cocktail machine?)
|
||||
P1_RIGHT: 0x40, // 1 = right (P1 right if cocktail machine?)
|
||||
ALWAYS_SET: 0x08 // always set
|
||||
},
|
||||
STATUS2: {
|
||||
PORT: 2,
|
||||
|
|
@ -134,7 +134,8 @@ ChipSet.SI_1978 = {
|
|||
P2_FIRE: 0x10, // 1 = P2 fire (cocktail machines only?)
|
||||
P2_LEFT: 0x20, // 1 = P2 left (cocktail machines only?)
|
||||
P2_RIGHT: 0x40, // 1 = P2 right (cocktail machines only?)
|
||||
DIP7: 0x80 // 0 = display coin info on demo ("attract") screen
|
||||
DIP7: 0x80, // 0 = display coin info on demo ("attract") screen
|
||||
ALWAYS_SET: 0x00
|
||||
},
|
||||
SHIFT_RESULT: { // bits 0-7 of barrel shifter result
|
||||
PORT: 3
|
||||
|
|
@ -273,9 +274,9 @@ ChipSet.prototype.powerDown = function(fSave, fShutdown)
|
|||
*/
|
||||
ChipSet.prototype.reset = function()
|
||||
{
|
||||
this.bStatus0 = 0;
|
||||
this.bStatus1 = 0;
|
||||
this.bStatus2 = 0;
|
||||
this.bStatus0 = ChipSet.SI_1978.STATUS0.ALWAYS_SET;
|
||||
this.bStatus1 = ChipSet.SI_1978.STATUS1.ALWAYS_SET;
|
||||
this.bStatus2 = ChipSet.SI_1978.STATUS2.ALWAYS_SET;
|
||||
this.wShiftData = 0;
|
||||
this.bShiftCount = 0;
|
||||
this.bSound1 = this.bSound2 = 0;
|
||||
|
|
@ -351,6 +352,45 @@ ChipSet.prototype.stop = function()
|
|||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus0(bit, fSet)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} bit
|
||||
* @param {boolean} fSet
|
||||
*/
|
||||
ChipSet.prototype.updateStatus0 = function(bit, fSet)
|
||||
{
|
||||
this.bStatus0 &= ~bit;
|
||||
if (fSet) this.bStatus0 |= bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus1(bit, fSet)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} bit
|
||||
* @param {boolean} fSet
|
||||
*/
|
||||
ChipSet.prototype.updateStatus1 = function(bit, fSet)
|
||||
{
|
||||
this.bStatus1 &= ~bit;
|
||||
if (fSet) this.bStatus1 |= bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus2(bit, fSet)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {number} bit
|
||||
* @param {boolean} fSet
|
||||
*/
|
||||
ChipSet.prototype.updateStatus2 = function(bit, fSet)
|
||||
{
|
||||
this.bStatus2 &= ~bit;
|
||||
if (fSet) this.bStatus2 |= bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* inSIStatus0(port, addrFrom)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ if (NODE) {
|
|||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Messages = require("./messages");
|
||||
var State = require("./state");
|
||||
var CPU = require("./cpu");
|
||||
var ChipSet = require("./chipset");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -52,6 +51,8 @@ function Keyboard(parmsKbd)
|
|||
{
|
||||
Component.call(this, "Keyboard", parmsKbd, Keyboard, Messages.KEYBOARD);
|
||||
|
||||
this.reset();
|
||||
|
||||
this.setReady();
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +123,16 @@ Keyboard.KEYCODE = {
|
|||
/* 0x2E */ DEL: 46,
|
||||
/* 0x2E */ FF_PERIOD: 46,
|
||||
/* 0x2F */ FF_SLASH: 47,
|
||||
/* 0x30 */ ZERO: 48,
|
||||
/* 0x31 */ ONE: 49,
|
||||
/* 0x32 */ TWO: 50,
|
||||
/* 0x33 */ THREE: 51,
|
||||
/* 0x34 */ FOUR: 52,
|
||||
/* 0x35 */ FIVE: 53,
|
||||
/* 0x36 */ SIX: 54,
|
||||
/* 0x37 */ SEVEN: 55,
|
||||
/* 0x38 */ EIGHT: 56,
|
||||
/* 0x39 */ NINE: 57,
|
||||
/* 0x3B */ FF_SEMI: 59,
|
||||
/* 0x3D */ FF_EQUALS: 61,
|
||||
/* 0x5B */ CMD: 91, // aka WIN
|
||||
|
|
@ -210,6 +221,62 @@ Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.RBRACK] = Keyboard.ASCII[']']; // 2
|
|||
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.QUOTE] = Keyboard.ASCII["'"]; // 222 -> 39
|
||||
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.FF_DASH] = Keyboard.ASCII['-'];
|
||||
|
||||
/**
|
||||
* Maps SOFTCODE (string) to KEYCODE (number).
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
Keyboard.SOFTCODES = {
|
||||
'1p': Keyboard.KEYCODE.ONE,
|
||||
'2p': Keyboard.KEYCODE.TWO,
|
||||
'coin': Keyboard.KEYCODE.FIVE,
|
||||
'left': Keyboard.KEYCODE.LEFT,
|
||||
'right': Keyboard.KEYCODE.RIGHT,
|
||||
'fire': Keyboard.KEYCODE.SPACE
|
||||
};
|
||||
|
||||
/**
|
||||
* Alternate keyCode mappings (to support the popular WASD directional mappings)
|
||||
*
|
||||
* TODO: ES6 computed property name support may now be in all mainstream browsers, allowing us to use
|
||||
* a simple object literal for this and all other object initializations.
|
||||
*/
|
||||
Keyboard.ALTCODES = {};
|
||||
Keyboard.ALTCODES[Keyboard.ASCII.A] = Keyboard.KEYCODE.LEFT;
|
||||
Keyboard.ALTCODES[Keyboard.ASCII.D] = Keyboard.KEYCODE.RIGHT;
|
||||
Keyboard.ALTCODES[Keyboard.ASCII.L] = Keyboard.KEYCODE.SPACE;
|
||||
|
||||
/**
|
||||
* getSoftCode(keyCode)
|
||||
*
|
||||
* @this {Keyboard}
|
||||
* @return {string|null}
|
||||
*/
|
||||
Keyboard.prototype.getSoftCode = function(keyCode)
|
||||
{
|
||||
keyCode = Keyboard.ALTCODES[keyCode] || keyCode;
|
||||
for (var sSoftCode in Keyboard.SOFTCODES) {
|
||||
if (Keyboard.SOFTCODES[sSoftCode] === keyCode) {
|
||||
return sSoftCode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* reset()
|
||||
*
|
||||
* @this {Keyboard}
|
||||
*/
|
||||
Keyboard.prototype.reset = function()
|
||||
{
|
||||
/*
|
||||
* As SOFTCODE keyDown events are encountered, a corresponding property is set to true in
|
||||
* keysPressed, and as SOFTCODE keyUp events are encountered, the property is set to false.
|
||||
*/
|
||||
this.keysPressed = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control, sValue)
|
||||
*
|
||||
|
|
@ -257,68 +324,24 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
control.onkeydown = function onKeyDown(event) {
|
||||
return kbd.onKeyDown(event, true);
|
||||
};
|
||||
control.onkeypress = function onKeyPressKbd(event) {
|
||||
return kbd.onKeyPress(event);
|
||||
};
|
||||
control.onkeyup = function onKeyUp(event) {
|
||||
return kbd.onKeyDown(event, false);
|
||||
};
|
||||
return true;
|
||||
|
||||
case "caps-lock":
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function onClickCapsLock(event) {
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
return kbd.toggleCapsLock();
|
||||
};
|
||||
return true;
|
||||
|
||||
case "num-lock":
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function onClickNumLock(event) {
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
return kbd.toggleNumLock();
|
||||
};
|
||||
return true;
|
||||
|
||||
case "scroll-lock":
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function onClickScrollLock(event) {
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
return kbd.toggleScrollLock();
|
||||
};
|
||||
return true;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Maintain support for older button codes; eg, map button code "ctrl-c" to CLICKCODE "CTRL_C"
|
||||
*/
|
||||
var sCode = sBinding.toUpperCase().replace(/-/g, '_');
|
||||
if (Keyboard.CLICKCODES[sCode] !== undefined && sHTMLType == "button") {
|
||||
if (Keyboard.SOFTCODES[sBinding] !== undefined) {
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function(kbd, sKey, simCode) {
|
||||
return function onClickKeyboard(event) {
|
||||
if (!COMPILED && kbd.messageEnabled()) kbd.printMessage(sKey + " clicked", Messages.KEYS);
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
kbd.updateShiftState(simCode, true); // future-proofing if/when any LOCK keys are added to CLICKCODES
|
||||
kbd.addActiveKey(simCode, true);
|
||||
};
|
||||
}(this, sCode, Keyboard.CLICKCODES[sCode]);
|
||||
return true;
|
||||
}
|
||||
else if (Keyboard.SOFTCODES[sBinding] !== undefined) {
|
||||
this.cSoftCodes++;
|
||||
this.bindings[id] = control;
|
||||
var fnDown = function(kbd, sKey, simCode) {
|
||||
var fnDown = function(kbd, sSoftCode) {
|
||||
return function onMouseOrTouchDownKeyboard(event) {
|
||||
kbd.addActiveKey(simCode);
|
||||
kbd.onSoftKeyDown(sSoftCode, true);
|
||||
};
|
||||
}(this, sBinding, Keyboard.SOFTCODES[sBinding]);
|
||||
var fnUp = function (kbd, sKey, simCode) {
|
||||
}(this, sBinding);
|
||||
var fnUp = function (kbd, sSoftCode) {
|
||||
return function onMouseOrTouchUpKeyboard(event) {
|
||||
kbd.removeActiveKey(simCode);
|
||||
kbd.onSoftKeyDown(sSoftCode, false);
|
||||
};
|
||||
}(this, sBinding, Keyboard.SOFTCODES[sBinding]);
|
||||
}(this, sBinding);
|
||||
if ('ontouchstart' in window) {
|
||||
control.ontouchstart = fnDown;
|
||||
control.ontouchend = fnUp;
|
||||
|
|
@ -328,19 +351,92 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
else if (sValue) {
|
||||
/*
|
||||
* Instead of just having a dedicated "test" control, we now treat any unrecognized control with
|
||||
* a data value as a test control. The only caveat is that such controls must have binding IDs that
|
||||
* do not conflict with predefined controls (which, of course, is the only way you can get here).
|
||||
*/
|
||||
this.bindings[id] = control;
|
||||
control.onclick = function onClickTest(event) {
|
||||
if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
return kbd.injectKeys(sValue);
|
||||
};
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* initBus(cmp, bus, cpu, dbg)
|
||||
*
|
||||
* @this {Keyboard}
|
||||
* @param {Computer} cmp
|
||||
* @param {Bus} bus
|
||||
* @param {CPUState} cpu
|
||||
* @param {Debugger} dbg
|
||||
*/
|
||||
Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.dbg = dbg; // NOTE: The "dbg" property must be set for the message functions to work
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
};
|
||||
|
||||
/**
|
||||
* onKeyDown(event, fDown)
|
||||
*
|
||||
* @this {Keyboard}
|
||||
* @param {Object} event
|
||||
* @param {boolean} fDown is true for a keyDown event, false for a keyUp event
|
||||
* @return {boolean} true to pass the event along, false to consume it
|
||||
*/
|
||||
Keyboard.prototype.onKeyDown = function(event, fDown)
|
||||
{
|
||||
var fPass = true;
|
||||
var keyCode = event.keyCode;
|
||||
var sSoftCode = this.getSoftCode(keyCode);
|
||||
|
||||
if (sSoftCode) {
|
||||
fPass = this.onSoftKeyDown(sSoftCode, fDown);
|
||||
}
|
||||
|
||||
if (!fPass) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (!COMPILED && this.messageEnabled(Messages.KEYS)) {
|
||||
this.printMessage("onKey" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "true" : "false"), true);
|
||||
}
|
||||
|
||||
return fPass;
|
||||
};
|
||||
|
||||
/**
|
||||
* onSoftKeyDown(sSoftCode, fDown)
|
||||
*
|
||||
* @this {Keyboard}
|
||||
* @param {string} sSoftCode
|
||||
* @param {boolean} fDown is true for a down event, false for an up event
|
||||
* @return {boolean} true to pass the event along, false to consume it
|
||||
*/
|
||||
Keyboard.prototype.onSoftKeyDown = function(sSoftCode, fDown)
|
||||
{
|
||||
this.keysPressed[sSoftCode] = fDown;
|
||||
|
||||
if (this.chipset) {
|
||||
switch(sSoftCode) {
|
||||
case '1p':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1, fDown);
|
||||
break;
|
||||
|
||||
case '2p':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P2, fDown);
|
||||
break;
|
||||
|
||||
case 'coin':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.CREDIT, fDown);
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_LEFT, fDown);
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_RIGHT, fDown);
|
||||
break;
|
||||
|
||||
case 'fire':
|
||||
this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_FIRE, fDown);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,6 +245,16 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
|
||||
this.initCache();
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have an associated keyboard, then ensure that the keyboard will be notified whenever the canvas
|
||||
* gets focus and receives input.
|
||||
*/
|
||||
this.kbd = cmp.getMachineComponent("Keyboard");
|
||||
if (this.kbd && this.canvasScreen) {
|
||||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "kbd", this.inputScreen);
|
||||
}
|
||||
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -566,6 +566,11 @@ Keyboard.KEYSTATES[Keyboard.SIMCODE.SCROLL_LOCK] = Keyboard.STATE.SCROLL_LOCK;
|
|||
/**
|
||||
* Maps CLICKCODE (string) to SIMCODE (number).
|
||||
*
|
||||
* NOTE: Unlike SOFTCODES, CLICKCODES are upper-case and use underscores instead of dashes, so that this
|
||||
* and other components can reference them using "dot" property syntax; using upper-case merely adheres to
|
||||
* our convention for constants. setBinding() will automatically convert any incoming CLICKCODE bindings
|
||||
* that use lower-case and dashes to upper-case and underscores before performing property lookup.
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
Keyboard.CLICKCODES = {
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ function Video(parmsVideo, canvas, context, textarea, container)
|
|||
*/
|
||||
var fSmoothing = parmsVideo['smoothing'];
|
||||
var sSmoothing = Component.parmsURL['smoothing'];
|
||||
if (sSmoothing) fSmoothing = (sSmoothing == "true")? true : false;
|
||||
if (sSmoothing) fSmoothing = (sSmoothing == "true");
|
||||
if (fSmoothing != null) {
|
||||
for (i = 0; i < asWebPrefixes.length; i++) {
|
||||
sEvent = asWebPrefixes[i];
|
||||
|
|
@ -4560,8 +4560,8 @@ Video.prototype.removeCursor = function()
|
|||
/*
|
||||
* If we're using an off-screen buffer in text mode, then we need to keep it in sync with "reality".
|
||||
*/
|
||||
if (this.contextScreenBuffer) {
|
||||
this.updateChar(col, row, data, this.contextScreenBuffer);
|
||||
if (this.contextBuffer) {
|
||||
this.updateChar(col, row, data, this.contextBuffer);
|
||||
}
|
||||
/*
|
||||
* While updating the on-screen canvas directly could open us up to potential subpixel artifacts again,
|
||||
|
|
@ -4856,11 +4856,11 @@ Video.prototype.setDimensions = function()
|
|||
}
|
||||
|
||||
/*
|
||||
* In text modes, we have the option of setting all the *ScreenBuffer variables to null instead of
|
||||
* In text modes, we have the option of setting all the *Buffer variables to null instead of
|
||||
* allocating them, because updateChar(), as currently written, is capable of writing characters to
|
||||
* either an off-screen or on-screen context.
|
||||
*
|
||||
* this.imageScreenBuffer = this.canvasScreenBuffer = this.contextScreenBuffer = null;
|
||||
* this.imageBuffer = this.canvasBuffer = this.contextBuffer = null;
|
||||
*/
|
||||
this.cxBuffer = this.cyBuffer = 0;
|
||||
if (font) {
|
||||
|
|
@ -4888,11 +4888,11 @@ Video.prototype.setDimensions = function()
|
|||
/*
|
||||
* Allocate the off-screen buffers
|
||||
*/
|
||||
this.imageScreenBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
|
||||
this.canvasScreenBuffer = document.createElement("canvas");
|
||||
this.canvasScreenBuffer.width = this.cxBuffer;
|
||||
this.canvasScreenBuffer.height = this.cyBuffer;
|
||||
this.contextScreenBuffer = this.canvasScreenBuffer.getContext("2d");
|
||||
this.imageBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
|
||||
this.canvasBuffer = document.createElement("canvas");
|
||||
this.canvasBuffer.width = this.cxBuffer;
|
||||
this.canvasBuffer.height = this.cyBuffer;
|
||||
this.contextBuffer = this.canvasBuffer.getContext("2d");
|
||||
|
||||
/*
|
||||
* Since cxCell and cyCell were originally defined in terms of cxScreen/nCols and cyScreen/nRows, you might think
|
||||
|
|
@ -5676,7 +5676,7 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
|
|||
if (!this.fCellCacheValid || data !== this.aCellCache[iCell]) {
|
||||
var col = iCell % this.nCols;
|
||||
var row = (iCell / this.nCols)|0;
|
||||
this.updateChar(col, row, data, this.contextScreenBuffer);
|
||||
this.updateChar(col, row, data, this.contextBuffer);
|
||||
this.aCellCache[iCell] = data;
|
||||
cUpdated++;
|
||||
}
|
||||
|
|
@ -5686,8 +5686,8 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
|
|||
|
||||
this.fCellCacheValid = true;
|
||||
|
||||
if (cUpdated && this.contextScreenBuffer) {
|
||||
this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.cxBuffer, this.cyBuffer, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
|
||||
if (cUpdated && this.contextBuffer) {
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -5725,7 +5725,7 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
|
|||
if (x < xDirty) xDirty = x;
|
||||
for (var iPixel = 0; iPixel < nPixelsPerCell; iPixel++) {
|
||||
var bPixel = (wPixels & (wMask >>= nPixelShift)) >> (nShift -= nPixelShift);
|
||||
this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]);
|
||||
this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
|
||||
}
|
||||
if (x > xMaxDirty) xMaxDirty = x;
|
||||
if (y < yDirty) yDirty = y;
|
||||
|
|
@ -5748,30 +5748,30 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
|
|||
this.fCellCacheValid = true;
|
||||
|
||||
/*
|
||||
* Instead of blasting the ENTIRE imageScreenBuffer into contextScreenBuffer, and then blasting the ENTIRE
|
||||
* canvasScreenBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about
|
||||
* Instead of blasting the ENTIRE imageBuffer into contextBuffer, and then blasting the ENTIRE
|
||||
* canvasBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about
|
||||
* the update (well, to the extent that the canvas APIs permit).
|
||||
*/
|
||||
if (xDirty < this.nCols) {
|
||||
var cxDirty = xMaxDirty - xDirty;
|
||||
var cyDirty = yMaxDirty - yDirty;
|
||||
// this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0);
|
||||
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
// this.contextBuffer.putImageData(this.imageBuffer, 0, 0);
|
||||
this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
/*
|
||||
* While ideally I would draw only the dirty portion of canvasScreenBuffer, there usually isn't a 1-1 pixel mapping
|
||||
* between canvasScreenBuffer and contextScreen. In fact, the WHOLE POINT of the canvasScreenBuffer is to leverage
|
||||
* While ideally I would draw only the dirty portion of canvasBuffer, there usually isn't a 1-1 pixel mapping
|
||||
* between canvasBuffer and contextScreen. In fact, the WHOLE POINT of the canvasBuffer is to leverage
|
||||
* drawImage()'s scaling ability; for example, a CGA graphics mode might be 640x200, whereas the canvas representing
|
||||
* the screen might be 960x400. In those situations, if we draw interior rectangles, we often end up with subpixel
|
||||
* artifacts along the edges of those rectangles. So it appears I must continue to redraw the entire canvasScreenBuffer
|
||||
* artifacts along the edges of those rectangles. So it appears I must continue to redraw the entire canvasBuffer
|
||||
* on every change.
|
||||
*
|
||||
var xScreen = (((xDirty * this.cxScreen) / this.nCols) | 0);
|
||||
var yScreen = (((yDirty * this.cyScreen) / this.nRows) | 0);
|
||||
var cxScreen = (((cxDirty * this.cxScreen) / this.nCols) | 0);
|
||||
var cyScreen = (((cyDirty * this.cyScreen) / this.nRows) | 0);
|
||||
this.contextScreen.drawImage(this.canvasScreenBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
|
||||
this.contextScreen.drawImage(this.canvasBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
|
||||
*/
|
||||
this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -5863,7 +5863,7 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
|
|||
* index, which is what this code requires.
|
||||
*/
|
||||
var bPixel = Video.aEGADWToByte[dwPixel] || 0;
|
||||
this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]);
|
||||
this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
|
||||
data <<= 1;
|
||||
}
|
||||
if (x > xMaxDirty) xMaxDirty = x;
|
||||
|
|
@ -5888,8 +5888,8 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
|
|||
if (xDirty < this.nCols) {
|
||||
var cxDirty = xMaxDirty - xDirty;
|
||||
var cyDirty = yMaxDirty - yDirty;
|
||||
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -5957,7 +5957,7 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
|
|||
if (nPixels) {
|
||||
if (x < xDirty) xDirty = x;
|
||||
for (iPixel = 0; iPixel < nPixels; iPixel++) {
|
||||
this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[data & 0xff]);
|
||||
this.setPixel(this.imageBuffer, x++, y, aPixelColors[data & 0xff]);
|
||||
data >>= 8;
|
||||
}
|
||||
if (x > xMaxDirty) xMaxDirty = x;
|
||||
|
|
@ -5984,8 +5984,8 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
|
|||
if (xDirty < this.nCols) {
|
||||
var cxDirty = xMaxDirty - xDirty;
|
||||
var cyDirty = yMaxDirty - yDirty;
|
||||
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
|
||||
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue