Well I thought I'd find the guide I wrote in my sentbox but apparently it doesn't save to many messages. So heres a quick run down of interlacing
Lets say this is the image you want.
It would be composed of 2 layers commonly referred to as a dark layer and a light layer. The dark layer is generally stored before the light layer. So that image would look like this.
Dark:
Light:
For 4 level gray scale, the dark layer is displayed 2 times longer than the light. So if the light layer flashed once than the dark is twice.
This method is generally faster, the biggest reason is because you don't have to perform fastcopy again when the dark layer was shown prior. So in other words you can skip 1 lcd update. That save a tremendous amount of time. This method of updating the entire screen with a layer is also simpler to code and generally lighter.
However, if timing is inaccurate, the screen will look flickery and be quite unpleasant. If timing is accurate but not tuned properly, you'll end up seeing a line moving across the screen. Which is horribly noticeable.
Rigview came along with accurate controllable timing and a new method of displaying the screen. This was done by interlacing bytes from both layers.
![Image](http://jim.revsoft.org/g/interlacing.gif)
Unlike the last screen you can actually tell even at this low frame rate whats suppose to be dark and whats suppose to be light. Even if the timing is slightly off the noise produced by that is spread out more evenly. So the effect is less painful. This however gets more bloated because you have to carry pointers to both layers and have a method to decide which layer gets used on what byte. Thats either by unrolling code or giving up some more registers.
I think it was Duck who decided to take it to the bit level, not sure on that. But there was a good deal of benefit from it. No matter how bad timing was dithering the bits together allowed for a very even image. The screen, no matter how noisy, was not unpleasant.
Of course with every advantage there is a disadvantage, the code is MUCH more complicated. Duck's code actually used shadow registers, so you can imagine the nightmare of having to work with that code. Big issue with it is that you have the annoyance of having to work with masks. So lets count the registers.
A 16bit pointer for the dark layer.
How bout HL?
An 8bit mask for the dark layer.
Ummm C?
A 8bit temporary storage place for the masked dark layer.
B!
A 16bit pointer for the light layer.
DE then
An 8bit mask for the light layer.
....uh
A 16bit value to add the offset to the next byte.
oh SP!!!?
An 8bit loop counter.
crap.
So in other words, this code would be register starved. You want each write to the lcd port to occur within ~70 tstates of the last write. Self Modifying Code works to an extent but is still not very fast.
Then some bright boy(I forget his name, had letters in it I swear) came up with a method that relied on reversible operations. What this did was get rid of the need of temporary storage and the need to hold both masks. (Kinda plays back into your xor swapping thing).
So this would look like:
Dark_layer ^ Light_layer & Dark_mask ^ Light_layer = result
As opposed to:
(Dark_layer & Dark_mask) | ( Light_layer & Light_mask ) = result
Just comparing the code is noticeable improvement.
Code: Select all
;Old broken code
ld a,(ix)
and d
ld c,a
ld a,(hl)
and e
or c
;New hotness
ld a,(de)
xor (hl)
and c
xor (hl)
This can really save you from requiring use of slower registers or shadow registers. Typically you can get WAY below the required lcd delay. So its extremely helpful.
So this is what I ended up using for RGP. It runs at fastcopy speed so I decided thats enough optimization. It requires that layers be stored next to each other, but that isn't to much of an issue.
Code: Select all
;-------------------------------------------------
;4 level Grey interlace routine
;by James Montelongo
lcd: ;52744
in a,($20)
push af
ld a,0
out ($20),a
ld (stacksave),sp
ld a,$80
out ($10),a
ld a,(gsmasknum)
inc a
cp 3
jr c,skipmaskswap
xor a
skipmaskswap:
ld (gsmasknum),a
ld e,a
ld d,0
ld hl,gsmasks
add hl,de
ld d,(hl)
inc hl ;accidentally deleted.
ld a,(hl)
cpl
ld e,a
ld hl,gsActivebuf1-12
ld sp,12
ld a,$20
ld c,a
colloop:
out ($10),a
ld b,32
rowloop:
add hl,sp
ld a,(hl)
inc h
inc h
inc h
xor (hl)
and d
xor (hl)
out ($11),a
add hl,sp
nop ;I actually need to delay.
ld a,(hl)
dec h
dec h
dec h
xor (hl)
and e
xor (hl)
out ($11),a
djnz rowloop
inc c
dec h
dec h
dec h
inc hl
ld a,c
cp $2c
jr nz,colloop
ld sp,(stacksave)
pop af
out ($20),a
ret
gsmasks:
.db %11011011
.db %10110110
.db %01101101
.db %11011011
For the masks, The dark layer should mask out 1/3 of its bits, the light layer should mask out 2/3 of its bits.