skip to Main Content

Converting a DOS intro to JavaScript/HTML5

One day I had the idea of converting my fr29b DOS intro to JavaScript. Using the canvas element of HTML5, this should be an easy task and offer a good performance as well. To make the port as similar as possible, the standard VGA DOS palette should be supported. Drawing the ARGB values into the canvas can be speed up by using JavaScript typed arrays with an int32 view to write into the image data buffer. The DOS palette can be found in DOSBox source code and converted to a JavaScript usable format with this small code:

#include <stdio.h>

static unsigned char vga_palette[256][3]= {
  // put array content from file DOSBox source file src\ints\int10_modes.cpp here
};

int main() {
  for (int i = 0; i < 256; i++)
    printf("0xFF%02X%02X%02X,\n", vga_palette[i][0], vga_palette[i][1], vga_palette[i][2]);
}

The initial framework JavaScript code:

<canvas height="200" id="vga" width="320">
<script type="text/javascript">
vgapalette=[
0xFF000000,
0xFF00002A,
0xFF002A00,
// ... full palette that was giving out by the conversion tool here
];

var canvas = document.getElementById('vga');
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0, 0, 320, 200);
var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var buf32 = new Uint32Array(buf);
var dosvmem = new ArrayBuffer(320*200);
for (i = 0; i < 320*200; i++) { // init screen with black
  buf32[i] = 0xFF000000;
  dosvmem[i] = 0;
}

The DOSBox VGA palette is given in 6-bit RGB and needs to be converted to modern RGB 8-bit:

for (i = 0; i < 256; i++) {
  color = vgapalette[i];
  r = (color >> 16) & 0xff;
  r = (r << 2) | (r >> 4)
  g = (color >> 8) & 0xff;
  g = (g << 2) | (g >> 4)
  b = (color >> 0) & 0xff;
  b = (b << 2) | (b >> 4)
  colornew = (r << 16) + (g << 8) + (b << 0) + 0xFF000000;
  vgapalette[i] = colornew;
}

The main loop and the effect itself:

setInterval(function() {
  offset = Math.floor(Math.random() * 103981) & 0xffff; // generate random offset to screen
  for (i = 0; i < 140; i++, offset += 180) {
    for (j = 0; j < 140; j++, offset++) {       if (offset > 320*200) { // offset is outside of screen?
        if (offset <= 0xffff { // no 16 bit overflow?
          continue;
        }
        offset -= 0xffff; // simulate overflow
      }
      colorindex = (((dosvmem[offset] + 1) & 0xff) | 0x80); // increase palette index
      dosvmem[offset] = colorindex; // store the new index
      color = vgapalette[colorindex]; // get argb color value from palette
      buf32[offset] = color; // set pixel on screen
    }
  }

  imageData.data.set(buf8);
  ctx.putImageData(imageData, 0, 0);
}, 1000 / 35); // 35 fps

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top