Ported some PCjs drawing code to PC8080, still needs work though

This commit is contained in:
Jeff Parsons 2016-05-02 09:01:06 -07:00
commit 59b6dd3be6
23 changed files with 781 additions and 499 deletions

View file

@ -9,7 +9,7 @@
<rom id="romF" addr="0x1000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-F.json"/>
<rom id="romE" addr="0x1800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-E.json"/>
<ram id="ram" addr="0x2000" size="0x0400"/>
<video id="video" screenWidth="224" screenHeight="256" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" interruptRate="120" rotation="90" width="40%" pos="left" padding="8px">
<video id="video" screenWidth="896" screenHeight="1024" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" interruptRate="120" rotation="90" width="40%" pos="left" padding="8px">
<menu>
<title>224x256 Screen (Rotated)</title>
</menu>

View file

@ -9,7 +9,9 @@ PCjs ChipSet Component
Format
---
```xml
<chipset>...</chipset>
```
Purpose
---
@ -103,15 +105,20 @@ Bindings
Example
---
```xml
<chipset id="chipset" model="5150" sw1="01000001" sw2="11110000"/>
```
Output
---
```html
<div id="..." class="pc-chipset pc-component">
<div class="pc-container">
<div class="pcjs-chipset" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'"></div>
<div class="pcjs-chipset" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Component
Format
---
```xml
<component>...</component>
```
Purpose
---
@ -35,14 +37,20 @@ Attributes
Example
---
<component id="ibm5150" class="pcjs" width="740px" pos="center" border="1">...</component>
```xml
<component id="ibm5150" class="pcjs" width="740px" pos="center" border="1">
...
</component>
```
Output
---
```html
<div id="..." class="pc-component">
<div class="pc-container">
...
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs Computer Component
Format
---
```xml
<computer>...</computer>
```
Purpose
---
@ -51,16 +53,20 @@ Bindings
Example
---
```xml
<computer id="pc" name="IBM PC"/>
```
Output
---
```html
<div id="..." class="pc-computer pc-component" style="">
<div class="pc-container" style="">
<div class="pcjs-computer" data-value="id:'...',name:'...',resume:'...',state:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs CPU Component
Format
---
```xml
<cpu>...</cpu>
```
Purpose
---
@ -19,7 +21,7 @@ Attributes
---
* *model* (optional; default is 8088; supported values include: 8086, 8088, 80186, 80286, and 80386)
* Defines the CPU model, adjusting the CPU's capabilities accordingly.
* *stepping* (optional; if specified, it must be a 2-character string, such as "A0" or "B1")
* *stepping* (optional; if specified, it should be a 2-character string, such as "A0" or "B1")
* Defines the CPU stepping, adjusting the CPU's capabilities accordingly.
* Currently supported only on the 80386 model.
* *cycles* (optional; default is 4772727)
@ -44,26 +46,30 @@ Bindings
*[Computer](/docs/pcjs/computer/)* component, because every component is reset, but the CPU offers the binding
for convenience.
* *speed*
* For use with any control with an *innerHTML* property, to display the current CPU speed.
* For use with any control with an *textContent* property, to display the current CPU speed.
* *setSpeed*
* For use with a control of type *button*, to increase the CPU speed.
* *AX*, *BX*, *CX*, *DX*, *SP*, *BP*, *SI*, *DI*, *CS*, *DS*, *SS*, *ES*, *PC*, *PS*, *C*, *P*, *A*, *Z*, *S*, *T*, *I*, *D*, *O*
* For use with any control with an *innerHTML* property, to display the corresponding register's contents.
* For use with any control with an *textContent* property, to display the corresponding register's contents.
Example
---
```xml
<cpu id="cpu8088" model="8088" autoStart="true">
<control type="button" class="input" binding="run">Run</control>
</cpu>
```
Output
---
```html
<div id="..." class="pc-cpu pc-component" style="">
<div class="pc-container" style="">
<div class="pcjs-cpu" data-value="id:'...',name:'...',model:'...',cycles:'...',multiplier:'...',autoStart:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Debugger Component
Format
---
```xml
<debugger>...</debugger>
```
Purpose
---
@ -17,7 +19,7 @@ Creates an instance of the Debugger component.
Attributes
---
* *message* (optional)
* *messages* (optional)
* One or more message categories to enable, separated by |. By default, all message categories are disabled.
See the Debugger's "m" command for a current list of message categories.
@ -40,16 +42,20 @@ Use the Debugger's built-in help for a list of commands.
Example
---
```xml
<debugger/>
```
Output
---
```html
<div id="..." class="pc-debugger pc-component" style="">
<div class="pc-container" style="">
<div class="pcjs-debugger" data-value="id:'...',name:'...',message:'...'">
<div class="pcjs-debugger" data-value="id:'...',name:'...',messages:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9,7 +9,9 @@ PCjs Floppy Drive Controller (FDC) Component
Format
---
```xml
<fdc>...</fdc>
```
Purpose
---
@ -53,24 +55,28 @@ Bindings
Example
---
```xml
<fdc id="fdcNEC" autoMount="'{A: {name: "PC-DOS 1.0", path: "pcdos-1.00.json"}}'">
<control type="container">
<control type="list" class="input" binding="listDrives"/>
<control type="list" class="input" binding="listDisks">
<disk path="">None</disk>
<disk path="pcdos-1.00.json">PC-DOS 1.0</disk>
</control>
<control type="button" class="input" binding="loadDrive">Load Drive</control>
</control>
</fdc>
```
Output
---
```html
<div id="..." class="pc-fdc pc-component">
<div class="pc-container">
<div class="pcjs-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDrive:'...'"></div>
<div class="pcjs-fdc" data-value="id:'...',name:'...',listDrives:'...',listDisks:'...',loadDrive:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Hard Drive Controller (HDC) Component
Format
---
```xml
<hdc>...</hdc>
```
Purpose
---
@ -46,11 +48,15 @@ Attributes
For the Xebec (*'xt'*) controller, you should install the Xebec ROM; eg:
```xml
<rom id="romHDC" addr="0xc8000" size="0x2000" file="/devices/pc/hdc/ibm-xebec-1982.json"/>
```
For the Western Digital (*'at'*) controller, use a Model 5170 (or newer) ROM module; eg:
```xml
<rom id="romBIOS" addr="0xf0000" size="0x10000" alias="0xff0000" file="/devices/pc/rom/5170/1984-01-10/1984-01-10.json"/>
```
The default *type* setting is *'xt'*.
@ -62,15 +68,20 @@ This component has no bindings. Fixed disks cannot be loaded or unloaded once th
Example
---
```xml
<hdc id="hdcXT" drives="[{name:'10Mb Hard Drive',type:3}]"/>
```
Output
---
```html
<div id="..." class="pc-hdc pc-component">
<div class="pc-container">
<div class="pcjs-hdc" data-value="id:'...',name:'...',drives:'...'"></div>
<div class="pcjs-hdc" data-value="id:'...',name:'...',drives:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Keyboard Component
Format
---
```xml
<keyboard>...</keyboard>
```
Purpose
---
@ -41,18 +43,23 @@ for the specified model.
Example
---
```xml
<keyboard id="keyboard" model="us83"/>
```
See [/devices/pc/keyboard/us83-softkeys.xml](/devices/pc/keyboard/us83-softkeys.xml) for an example that provides a
complete "soft keyboard".
Output
---
```html
<div id="..." class="pc-keyboard pc-component">
<div class="pc-container">
<div class="pcjs-keyboard" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'"></div>
<div class="pcjs-keyboard" data-value="id:'...',name:'...',model:'...',sw1:'...',sw2:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Machine Component
Format
---
```xml
<machine>...</machine>
```
Purpose
---
@ -32,14 +34,18 @@ None.
Example
---
```xml
<machine id="ibm5150" class="pcjs" width="740px" pos="center" border="1" style="background-color:#FAEBD7">...</machine>
```
Output
---
```html
<div id="..." class="pc-machine pc-component" style="">
<div class="pc-container" style="">
...
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs Mouse Component
Format
---
```xml
<mouse>...</mouse>
```
Purpose
---
@ -30,14 +32,19 @@ None.
Example
---
```xml
<mouse serial="com1"/>
```
Output
---
```html
<div id="..." class="pc-mouse pc-component">
<div class="pc-container">
<div class="pcjs-mouse" data-value="id:'...',name:'...',serial:'...'></div>
<div class="pcjs-mouse" data-value="id:'...',name:'...',serial:'...'>
</div>
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs Control Panel Component
Format
---
```xml
<panel>...</panel>
```
Purpose
---
@ -28,27 +30,32 @@ and [Debugger](/docs/pcjs/debugger/) components.
Example
---
```xml
<panel id="panel" pos="center" width="900px" padleft="8px">
<name>Control Panel</name>
<control type="container" width="500px" pos="left" padbottom="10px">
<control type="textarea" class="output" binding="print" width="480px" height="200px"/>
<control type="container">
<control type="text" class="input" binding="debugInput" width="360px"/>
control type="text" class="input" binding="debugInput" width="360px"/>
<control type="button" class="input" binding="debugEnter">Enter</control>
<control type="button" class="input" binding="clear">Clear</control>
</control>
</control>
</panel>
```
See [/devices/pc/panel/default.xml](/devices/pc/panel/default.xml) for a more complete example.
Output
---
```html
<div id="..." class="pc-panel pc-component">
<div class="pc-container">
<div class="pcjs-panel" data-value="id:'...',name:'...'"></div>
<div class="pcjs-panel" data-value="id:'...',name:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs ParallelPort Component
Format
---
```xml
<parallel>...</parallel>
```
Purpose
---
@ -39,14 +41,19 @@ Bindings
Example
---
```xml
<parallel id="lpt1" adapter="2" binding="print"/>
```
Output
---
```html
<div id="..." class="pc-parallel pc-component">
<div class="pc-container">
<div class="pcjs-parallel" data-value="id:'...',name:'...',adapter:'...',binding:'...'"></div>
<div class="pcjs-parallel" data-value="id:'...',name:'...',adapter:'...',binding:'...'">
</div>
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs Random-Access Memory (RAM) Component
Format
---
```xml
<ram>...</ram>
```
Purpose
---
@ -43,15 +45,20 @@ Bindings
Example
---
```xml
<ram id="ramLow" addr="0x00000"/>
```
Output
---
```html
<div id="..." class="pc-ram pc-component">
<div class="pc-container">
<div class="pcjs-ram" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
<div class="pcjs-ram" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -9,7 +9,9 @@ PCjs Read-Only Memory (ROM) Component
Format
---
```xml
<rom>...</rom>
```
Purpose
---
@ -43,14 +45,19 @@ None.
Example
---
```xml
<rom id="romBIOS" addr="0xfe000" size="0x02000" file="/devices/pc/rom/5150/bios/1981-04-24.json"/>
```
Output
---
```html
<div id="..." class="pc-rom pc-component">
<div class="pc-container">
<div class="pcjs-rom" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
<div class="pcjs-rom" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'">
</div>
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs SerialPort Component
Format
---
```xml
<serial>...</serial>
```
Purpose
---
@ -39,14 +41,19 @@ Bindings
Example
---
```xml
<serial id="com1" adapter="1" binding="print"/>
```
Output
---
```html
<div id="..." class="pc-serial pc-component">
<div class="pc-container">
<div class="pcjs-serial" data-value="id:'...',name:'...',adapter:'...',binding:'...'"></div>
<div class="pcjs-serial" data-value="id:'...',name:'...',adapter:'...',binding:'...'">
</div>
</div>
</div>
```
[Return to [PCjs Documentation](..)]

View file

@ -9,7 +9,9 @@ PCjs Video Component
Format
---
```xml
<video>...</video>
```
Purpose
---
@ -22,24 +24,6 @@ Creates an instance of the Video component. This component is responsible for:
Attributes
---
* *addr* (required)
The ROM starting address (e.g., 0xfe000).
* *size* (required)
The length of ROM, in bytes (e.g., 0x02000 for an 8Kb ROM). This must match the length of the ROM image file.
* *file* (required)
URL of the ROM image file to load at the specified addr.
* *notify* (optional)
The *id* of a component to notify when *file* has been loaded. For example, the Video component may need
to know when an external video ROM has been loaded. Any component can load its own files, including ROM image files,
but it's simpler to use the ROM component and request notification.
* *model* (optional)
* "mda" (Monochrome Display Adapter)
@ -49,17 +33,13 @@ Attributes
If *model* is not set, the SW1 switch block settings from the [ChipSet](/docs/pcjs/chipset/) component will
determine the video model to use ("mda" or "cga" only).
* *scale* (optional; default is false)
true scales text modes to fill the canvas;
false centers text modes on the canvas (this generally provides the sharpest rendering).
* *screenwidth*, *screenheight* (required)
* *screenWidth*, *screenHeight* (required)
The width and height of the canvas, in pixels (these are numbers, not style attributes, so do not include
a "px" suffix).
a "px" suffix); the canvas resolution does not need to match the *model* resolution (in fact, it should probably
be closer to the resolution of modern monitors, but still proportional to the resolution of the *model* being used).
* *fontrom* (formerly *charset*; required for models "mda" and "cga")
* *fontROM* (formerly *charset*; required for models "mda" and "cga")
The name of a character generator (font ROM) file. The MDA and CGA adapters did not contain a separate
system ROM, but they did contain on-board font data in ROM that the adapter used internally to generate character
@ -68,6 +48,11 @@ Attributes
The EGA uses font data stored in its system ROM, which is loaded by the ROM component, so do not use this
setting with model "ega".
* *scale* (optional; default is false)
true scales text modes to fill the canvas;
false centers text modes on the canvas (this generally provides the sharpest rendering).
Also supports the attributes of *[Component](/docs/pcjs/component/)*.
Bindings
@ -79,17 +64,22 @@ Bindings
Example
---
<video id="videoMDA" screenwidth="720" screenheight="350" scale="true" fontrom="ibm-mda-cga.json">
```xml
<video id="videoMDA" screenWidth="720" screenHeight="350" fontROM="ibm-mda-cga.json" scale="true">
<name>Monochrome Display</name>
</video>
```
Output
---
```html
<div id="..." class="pc-video pc-component">
<div class="pc-container">
<div class="pcjs-video" data-value="id:'...',name:'...',addr:'...',size:'...',test:'...'"></div>
<div class="pcjs-video" data-value="...">
</div>
</div>
</div>
```
Also, if any controls are defined, another &lt;div&gt; of class="pc-controls" is created in the container &lt;div&gt;,
with each control inside a &lt;div&gt; of class="pc-control".

View file

@ -1091,11 +1091,11 @@ CPUSim.prototype.updateStatus = function(fForce)
this.updateReg("PC", this.getPC(), 4);
var regPS = this.getPS();
this.updateReg("PS", regPS, 4);
this.updateReg("SF", (regPS & CPUDef.PS.SF), 1);
this.updateReg("ZF", (regPS & CPUDef.PS.ZF), 1);
this.updateReg("AF", (regPS & CPUDef.PS.AF), 1);
this.updateReg("PF", (regPS & CPUDef.PS.PF), 1);
this.updateReg("CF", (regPS & CPUDef.PS.CF), 1);
this.updateReg("SF", (regPS & CPUDef.PS.SF)? 1 : 0, 1);
this.updateReg("ZF", (regPS & CPUDef.PS.ZF)? 1 : 0, 1);
this.updateReg("AF", (regPS & CPUDef.PS.AF)? 1 : 0, 1);
this.updateReg("PF", (regPS & CPUDef.PS.PF)? 1 : 0, 1);
this.updateReg("CF", (regPS & CPUDef.PS.CF)? 1 : 0, 1);
}
}
var controlSpeed = this.bindings["speed"];

View file

@ -55,7 +55,7 @@ if (NODE) {
* bufferAddr: the starting address of the frame buffer (eg, 0x2400)
* bufferCols: the width of a single frame buffer row, in pixels (eg, 256)
* bufferRows: the number of frame buffer rows (eg, 224)
* bufferBits: the number of bits per pixel (eg, 1)
* bufferBits: the number of bits per pixel (default is 1 if omitted)
* interruptRate: normally the same as (or some multiple of) the refreshRate (eg, 120)
* refreshRate: how many times updateScreen() should be called per second (eg, 60)
*
@ -75,9 +75,35 @@ if (NODE) {
function Video(parmsVideo, canvas, context, textarea, container)
{
Component.call(this, "Video", parmsVideo, Video, Messages.VIDEO);
this.cxScreen = parmsVideo['screenWidth'];
this.cyScreen = parmsVideo['screenHeight'];
this.addrBuffer = parmsVideo['bufferAddr'];
this.cxBuffer = parmsVideo['bufferCols'];
this.cyBuffer = parmsVideo['bufferRows'];
this.nBitsPerPixel = parmsVideo['bufferBits'] || 1;
this.interruptRate = parmsVideo['interruptRate'];
this.refreshRate = parmsVideo['refreshRate'] || 60;
this.setReady();
this.canvasScreen = canvas;
this.contextScreen = context;
this.textareaScreen = textarea;
this.inputScreen = textarea || canvas || null;
this.initColors();
/*
* Allocate off-screen buffers.
*
* TODO: Do this only if there is a mismatch between the screen's (canvas) dimensions and the frame buffer's.
*/
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");
}
Component.subclass(Video);
@ -97,6 +123,20 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
/*
* Compute the size of the frame buffer and allocate.
*/
this.sizeBuffer = ((this.cxBuffer * this.nBitsPerPixel) >> 3) * this.cyBuffer;
if (this.bus.addMemory(this.addrBuffer, this.sizeBuffer, Memory.TYPE.VIDEO)) {
/*
* Compute the number of cells and initialize the cell cache.
*/
this.nCellCache = this.sizeBuffer >> 1;
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
this.initCache();
}
this.setReady();
};
/**
@ -110,6 +150,62 @@ Video.prototype.getRefreshRate = function()
return Math.max(this.refreshRate, this.interruptRate);
};
/**
* initCache()
*
* Initializes the contents of our internal cell cache.
*
* @this {Video}
*/
Video.prototype.initCache = function()
{
this.fCellCacheValid = false;
if (this.aCellCache === undefined || this.aCellCache.length != this.nCellCache) {
this.aCellCache = new Array(this.nCellCache);
}
};
/**
* initColors()
*
* @this {Video}
*/
Video.prototype.initColors = function()
{
this.aRGB = [
[0x00, 0x00, 0x00, 0xff], // black
[0xff, 0xff, 0xff, 0xff] // white
];
};
/**
* getColors()
*
* @this {Video}
*/
Video.prototype.getColors = function()
{
return this.aRGB;
};
/**
* setPixel(imageData, x, y, rgb)
*
* @this {Video}
* @param {Object} imageData
* @param {number} x
* @param {number} y
* @param {Array.<number>} rgb is a 4-element array containing the red, green, blue and alpha values
*/
Video.prototype.setPixel = function(imageData, x, y, rgb)
{
var index = (x + y * imageData.width) * rgb.length;
imageData.data[index] = rgb[0];
imageData.data[index+1] = rgb[1];
imageData.data[index+2] = rgb[2];
imageData.data[index+3] = rgb[3];
};
/**
* updateScreen(n)
*
@ -126,6 +222,7 @@ Video.prototype.getRefreshRate = function()
*/
Video.prototype.updateScreen = function(n)
{
if (n >= 0) {
if (!(n & 1)) {
/*
* On even updates, call cpu.requestINTR(1), and also update our copy of the screen.
@ -138,6 +235,87 @@ Video.prototype.updateScreen = function(n)
* update the bottom half of the frame buffer after acknowledging this interrupt.
*/
this.cpu.requestINTR(2);
return;
}
/*
* Since this is not a forced update, if our cell cache is valid AND the buffer is clean, then do nothing.
*/
if (this.fCellCacheValid && this.bus.cleanMemory(this.addrBuffer, this.sizeBuffer)) {
return;
}
}
/*
* If we're still here, then either this is a forced update, or our cell cache hasn't been filled yet, or
* the frame buffer is dirty. Time to actually update the screen.
*/
var addr = this.addrBuffer;
var addrLimit = addr + this.sizeBuffer;
var iCell = 0;
var wPixelMask = 0x10000;
var nPixelShift = 1;
var aPixelColors = this.getColors();
var x = 0, y = 0;
var xDirty = this.cxBuffer, xMaxDirty = 0, yDirty = this.cyBuffer, yMaxDirty = 0;
while (addr < addrLimit) {
var data = this.bus.getShortDirect(addr);
this.assert(iCell < this.aCellCache.length);
if (this.fCellCacheValid && data === this.aCellCache[iCell]) {
x += this.nPixelsPerCell;
} else {
this.aCellCache[iCell] = data;
var wPixels = (data >> 8) | ((data & 0xff) << 8);
var wMask = wPixelMask, nShift = 16;
if (x < xDirty) xDirty = x;
for (var iPixel = 0; iPixel < this.nPixelsPerCell; iPixel++) {
var bPixel = (wPixels & (wMask >>= nPixelShift)) >> (nShift -= nPixelShift);
this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
}
if (x > xMaxDirty) xMaxDirty = x;
if (y < yDirty) yDirty = y;
if (y >= yMaxDirty) yMaxDirty = y + 1;
}
addr += 2;
iCell++;
if (x >= this.cxBuffer) {
x = 0;
y++;
if (y > this.cyBuffer) break;
}
}
this.fCellCacheValid = true;
/*
* 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.cxBuffer) {
var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty;
// 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 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 canvasBuffer
* on every change.
*
var xScreen = (((xDirty * this.cxScreen) / this.cxBuffer) | 0);
var yScreen = (((yDirty * this.cyScreen) / this.cyBuffer) | 0);
var cxScreen = (((cxDirty * this.cxScreen) / this.cxBuffer) | 0);
var cyScreen = (((cyDirty * this.cyScreen) / this.cyBuffer) | 0);
this.contextScreen.drawImage(this.canvasBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
*/
this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer, 0, 0, this.cxScreen, this.cyScreen);
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long