About Me

Curriculum Vitae

A brief list of my current skill set

Bloggybits

Entering a 13k HTML5 Game Competition
Tuesday, 4th September 2012, 16:31

I'm so tempted to have a go at this

Faster Loops and Faster Iterations in Node.js and V8
Wednesday, 29th August 2012, 13:16

Is Object.keys faster than For...In?

And the Fastworks.js framework is Born!
Wednesday, 22nd August 2012, 16:23

Well I'm excited, even if you aren't

Libxmljs Update on CentOS 3.8 throws an SELinux Wobbley Fit
Monday, 20th August 2012, 15:40

The right way to fix this sort of issue

TV Land Doesn't Understand Technology
Friday, 17th August 2012, 17:09

Or maybe it does and thinks we don't?

Yet More Benchmarking - Function Chains vs Object Chains
Wednesday, 15th August 2012, 13:34

Working towards a faster Node.js framework

More Benchmarking in Node.js and V8
Tuesday, 14th August 2012, 12:19

Working out the fastest way to route

MinnaHTML.js Benchmarking for Speed in Node.js
Monday, 13th August 2012, 17:55

Don't believe it, test it

Playing Around With HTML5's Canvas
Friday, 10th August 2012, 16:19

Speccy loading screens in a browser!

Scripting in Node.js AKA How to Watch for Olympic Tickets Using a Script
Tuesday, 7th August 2012, 23:37

Let Node refresh the webpage so you don't have to!

A Javascript Confirm/Alert Replacement jQuery Plugin
Monday, 6th August 2012, 23:06

Much prettier than the horrible alert and confirm dialogs

A Few Node.js Essential Modules
Friday, 3rd August 2012, 14:40

As essential as they can be anyway

Retro Coding Corner: Loading ZX Spectrum Snapshots off Microdrives - Part 2
Tuesday, 31st July 2012, 18:20

It's like juggling 8 balls with one hand behind your back

One Layout To Rule Them All
Monday, 30th July 2012, 16:03

Designing a layout to fit every screen

Retro Coding Corner: Loading ZX Spectrum Snapshots off Microdrives - Part 1
Thursday, 26th July 2012, 16:57

From emulation to super fast tape

Projects and Sillyness

MAME Cabinet Diary

How I built my own arcade cabinet

Loading Screen Simulator

I don't miss the ZX Spectrum, I still use it!

The Little Guy Chat Room

It's a Pitfall inspired chat room

GPMad MP3

A fully featured MP3 player what I wrote

GP Space Invaders

My first little emulator

GP32 Development Page

Some info and links about this cute little handheld

Disney Nasties

Uncensored images, you must be 18 to view them

Diary of a Hamster

Learn about how hamsters think, first hand

Utilities

Time Calculator

A simple little online utility for working out how many hours to bill a client

A Few Links

Playing Around With HTML5's Canvas
Friday, 10th August 2012, 16:19

I've read and played with some HTML5 demos, in particular Canvas related ones, but never really quite had a call to use it yet. But since playing around with stuff is always fun, it occurred to me a few days ago that a good thing to check it out with would be simulating the loading screen process of the ZX Spectrum. If you don't know what that is, watch this...

Now you have the idea, just a note on what I was initially trying to achieve as a first stab. It's important to aim for something achievable, so for now sound is out, because that would require generating an mp3 server side, and then synchronising it with the loading process. Not impossible, and I'll definitely look at it when I explore the sound side of things, but for now, sound is out.

Also not immediately achievable is the flashing border effects. The nature of these is such that to accurately emulate the border we'd need to time T-states, which is heavily into the realms of emulator territory. I can think of a few shortcuts that might be possible to approximate it, but too complicated for now.

TL;DR

Here is the link to the first version of my ZX Spectrum Loading Screen Simulator:
http://www.robertsworld.org.uk/spectrum_loading_screen_simulator

The <Canvas> Element

First job of the day, create a Canvas tag and give it a width and height. After some experimentation, it appears when you set the width and height attributes, that is the underlying resolution of the bitmap representation of the element. If you want to scale it, then you can do that by specifying width and heights in CSS.

canvas#spectrum
{
width: 512px;
height: 384px;
}
<canvas width="256" height="192" id="spectrum">
Your browser does not appear to support HTML5 :(
</canvas>

So this gives us a 1:2 mapping of pixels on our element, which means we can treat the Canvas itself as being the same resolution as our ZX Spectrum screen, but it will be displayed twice the size on the actual page.

The downside of this, anti-aliasing makes pixel images look rather poop, we need to double the size. So we change the latter width and height to 512x384, matching the CSS for it.

Next we need to get the context for the canvas object, which we do via jQuery, and create an image data object which will become a virtual screen for our Speccy:

var conCanvas = $("canvas#spectrum")[0].getContext("2d");
var imgData = conCanvas.createImageData(256 * 2, 192 * 2);

Every virtual screen update period, in our case 25 times a second, we will put this image back to the canvas with the following:

conCanvas.putImageData(imgData, 0, 0);

Then we'll use two functions which "poke" our data. Normally we'd just need one, but here we actually have to set 4 pixels for every 1, because our bitmap is twice the width and height.

function setPixel(x, y, colour)
{
var pos = ((x * 2) + ((y * 2) * (2 * 256))) * 4;

pokePixel(pos, colour);
pokePixel(pos + 4, colour);
pos += (256 * 2) * 4;
pokePixel(pos, colour);
pokePixel(pos + 4, colour);
};

function pokePixel(pos, colour)
{
// Red
imgData.data[pos++] = colour.r;
// Green
imgData.data[pos++] = colour.g;
// Blue
imgData.data[pos++] = colour.b;
// Alpha
imgData.data[pos++] = 255;
};

To simulate the speed, we will calculate the amount of screen bytes updated every screen update (25th of a second) based on the standard baud rate for the Spectrum loader in the ROM. From there, the rest is pretty simple!

Everything gets wrapped up in a jQuery plugin, my preferred method for implementing this sort of thing. And the only thing left to explain really is the Speccy screen memory side of things.

The ZX Spectrum Screen Memory Layout

At first glance, the Speccy video memory is a real confusing bag of tricks. It starts at 16384 (0x4000, the second 16K memory address and the start of RAM), is 6912 bytes long (the first 6k is the bitmap, the last 768 are colour attributes), and rows are far from contiguous.

With a screen resolution of 256 x 192, a quick bit of maths tells you that the values are far from arbitrary, being easily divisible by 8.

Putting colours aside, each pixel can be on or off, and horizontally the screen is divided into 32 rows of 8 pixels, where each set of 8 pixels is a byte in the screen memory. So far, much like many monochromatic displays of the era, easy peasy.

So the first 32 bytes of screen RAM, represent the first 256 pixels from the top left of the screen. The second 32 bytes, represent NOT the second row of 256 pixels, but the 8th row, and the third 32 bytes represent the 16th row.

If that wasn't confusing enough, once you get to the eighth set of 32 bytes, they jump back round to the 2nd row of pixels on the screen. Because the screen itself is divided into thirds.

You can see this most clearly when early ZX Spectrum games are loading the title screen, because the baud rate is so slow you can watch it build up the screen as it loads the data contiguously into memory.

I don't confess to fully understand quite why the screen was done this way, other than to assume the reasons were probably cost related. Sinclair did after all not design this as a games machine, so efficiency of throwing sprites to a screen would have been far from their minds.

Since old computers always do these weird things for a reason, and that reason is always related to bits, there is a good way to convert X, Y coords into memory addresses, even with this strange system above.

High Byte:

  Bit        7      6      5      4      3      2      1      0
Value 32768 16384 8192 4096 2048 1024 512 256
0 1 0 T T L L L

You should be able to see straight away here that bits 5-7 will always be set such that the HL word references memory between 16384 and 24575, the latter address being higher than our screen memory area.

The letters T, L, R and C I'll explain in a moment.

Low Byte:

  Bit        7      6      5      4      3      2      1      0
Value 128 64 32 16 8 4 2 1
R R R C C C C C

Bits 0-4 of the low byte marked as C are easy to follow, they represent the X column of the bitmap area. Since there are 32 columns (8 * 32 = 256 pixels), working out any given horizontal offset for a pixel byte is as easy as dividing it by 8. The pixel at position 5 is part of byte 0, (since 5 / 8 is 0.625, rounding down to 0), and the pixel at position 70 is byte 8 (70 / 8 is 8.75).

Things get confusing when we get to the y axis. The first thing we need to know is what third of the screen our coordinate resides in, we can do this by dividing it by 64, since there are 192 lines, three sets of 64. We set bits 3-4 of the high byte to the correct third (0 for the first, 1 for the second and 2 for the third).

The next task is which of the 8 rows our pixel is in, this is what Bits 5-7 of the low byte represent, the R being for row. And finally, which of the 8 lines in that row, Bits 0-2 of the high byte, aka L, represent that.

This is all very messy and quite annoying on the real spectrum at times. Sure you can do some simple maths to work out the right memory address, but it still isn't in any way easier than if it was a contiguous mapping like other machines. You can quickly increase the high byte (effectively adding 256) to move down a line, but this only works until you pass an 8x8 block, at which point you have to reset the L bits and increase the R bits, or if you cross a third, just the R bits (because the L bits overflow into the T bits).

The Colour Attributes

As for colours, these are pulled from the last part of screen memory, 768 bytes which each represent an 8x8 block, containing the foreground colour, background colour, a brightness bit and a flashing bit.

Bits 0-2 represent on/off states for blue, red and green respectively for the foreground. If you examine a 48K Spectrum keyboard you'll see that it has colours along the number row, with blue being above 1, red being above 2, and green above 4. This is no coincidence, as each of the aforementioned bits evaluate to the same numbers.

Other colours are combinations of these bits, so on the keyboard magenta is above 3 (since it is red + blue), cyan above 5, and so on.

Bits 3-5 represent identical on/off states for the background colour. And Bit 6 is the brightness bit, which adds about 25% to the voltage of the RGB values bringing them up to their maximum. Bit 7 is the flashing bit, and simply means twice a second (don't quote me on this) it flips the foreground and background.

Completely unlike the bitmap portion of the display, the colour attributes section is stored sequentially as you would expect, running left to right, top to bottom.

Comments

Add Your Own Comment