Make your own Chunky Two Planar

By Mikael Kalms (Scout / C-Lous)

The basic idea of Chunky-to-Planar conversion is to convert one chunky-pixel (one byte containing the complete color value of one pixel) to bitplane-data. This is achieved by writing one bit of the chunky-pixel to each bitplane. That way, one can have a putpixel-routine that does all the work. However, the conversion is extremely slow. It does, for instance, write the same byte eight (!) times when drawing horizontal lines (one write (or rather 'or.b') per bit to be set). Isn't there any other way?

Yes there is. If one would have a temporary buffer where one would draw the chunky-pixels (not converting them in any way), and a C2P-routine then would convert the whole buffer into bitplanes (writing data directly to the screen), there would be a tremendous speed-increase since the C2P-routine can deal with many pixels at once!

The simplest (and slowest) C2P-routine grabs 8 pixels at a time. The more complex ones handle 16 pixels (or 32, but they then need a temporary buffer). The C2P conversion is handled through a magic process.

Knowledge of a few special operations are required:

Rotation (90 degrees counterclockwise):

This has the following effect:

(Each letter represents a bit in the byte)
abcdefgh
ijklmnop

Rot 1x1

bjdlfnhp
aickemgo
The data is split up into 2x2 segments. Inside each segment, a 1x1 rotation is performed: a moves down, b moves left, i moves right, j moves up.

A 2x2 rotation means that the data is split up into 4x4 segments, and inside each segment 2x2 blocks (instead of single pixels) are moved. The order inside each 2x2 block shouldn't be changed.
It is done like this:

abcd
efgh
ijkl
mnop

Rot 2x2

cdkl
ghop
abij
efmn

A 1x1 swap is performed like this:

; d0 and d1 contains bit pattern
; Bit mask with every 2nd bit set
move.b #$55,d7
move.b d0,d2
; Mask out the bits changing byte
and.b d7,d0
; Mask out the other ones in d2
eor.b d0,d2
; Do the left-move
lsl.b #1,d0
move.b 1,d3
; Mask out the bits not changing byte
and.b d7,d3
; Mask out the other ones in d2
eor.b d3,d1
; Do the right-move
lsr.b #1,d0
; Do the up-move
or.b d3,d0
; Do the down-move
or.b d2,d1
Swap: This one is almost exactly like the rotation. It exchanges bits diagonally:
abcdefgh
ijklmnop

Swap 2x1

abijefmn
cdklghop

A 2x1 swap is done like this:

; d0 and d1 contains bit pattern
; Bit mask: 00110011
move.b #$33,d7
move.b d0,d2
; Mask out the bits not moved
and.b d7,d2
; Mask out the other ones
eor.b d2,d0
; Move the bits left
lsl.b #2,d2
move.b d1,d3
; Mask out the bits moved
and.b d7,d0
; Mask out the other ones
eor.b d0,d3
; Move the bits right
lsr.b #2,d3
; Insert the bits
or.b d3,d0
; Insert the bits
or.b d2,d1

Now, what if we grabbed 8 chunky-pixels and did a 4x4 rotation, a 2x2 rotation and finally a 1x1 rotation?

(Where a7 denotes byte 'a', bit 7 aso)
a7a6a5a4a3a2a1a0
b7b6b5b4b3b2b1b0
c7c6c5c4c3c2c1c0
d7d6d5d4d3d2d1d0
e7e6e5e4e3e2e1e0
f7f6f5f4f3f2f1f0
g7g6g5g4g3g2g1g0
h7h6h5h4h3h2h1h0

Rot 4x4

a3a2a1a0e3e2e1e0
b3b2b1b0f3f2f1f0
c3c2c1c0g3g2g1g0
d3d2d1d0h3h2h1h0
a7a6a5a4e7e6e5e4
b7b6b5b4f7f6f5f4
c7c6c5c4g7g6g5g4
d7d6d5d4h7h6h5h4

Hmm... Notice that bits 0-3 and bits 4-7 of all bytes now have been separated!

Rot 2x2

a1a0c1c0e1e0g1g0
b1b0d1d0f1f0h1h0
a3a2c3c2e3e2g3g2
b3b2d3d2f3f2h3h2
a5a4c5c4e5e4g5g4
b5b4d5d4f5f4h5h4
a7a6c7c6e7e6g7g6
b7b6d7d6f7f6h7h6

Now bits 0-1, bits 2-3, bits 4-5 and bits 6-7 are separated.

Rot 1x1

a0b0c0d0e0f0g0h0
a1b1c1d1e1f1g1h1
a2b2c2d2e2f2g2h2
a3b3c3d3e3f3g3h3
a4b4c4d4e4f4g4h4
a5b5c5d5e5f5g5h5
a6b6c6d6e6f6g6h6
a7b7c7d7e7f7g7h7
We now have eight bytes of bitplane-data!

However, the process can be made a bit better. Grab 16 pixels at a time, have them stored in d0-d3 and try to do all operations longword-wise! Remember to make the routine max 256 bytes long, too. (If it doesn't fit into the cache, the routine will become dramatically slower.)

The blitter can be used as well. Blitterscreen-routines are very clever: They have the pixels in scrambled order (a look-up-table required for horizontal drawing), and they don't do the 1x1 rotation! (It is instead handled via playfield-scrolling.) The black pixels on a blitterscreen are actually sprites (5 64-bit sprites) - every 2nd pixel is wrong, so the sprites hide those!

I have some C2P routines by now (most of them are homebrew). Some enlarge the pixels before writing them to the screen (2x width). If you're interested in sharing/getting ideas or sources, contact me.

Scout/C-Lous
kalms@vasa.gavle.se

(To edit an article like this including assemble code is the most boring thing you can do. Trust me! Don't try this at home! /Frame)