One day I was watching some demos that used linecrunch routines for whole-screen multicolor-graphics upscrollers. I already had my theories about how and why linecrunch worked, but because I had not used it anywhere, the details were a bit vague. In fact, I have many times accidentally created linecrunch effects when trying to do something else with $D011. Probably every demo coder has.
But you learn by doing. I had the idea of using linecrunch for FLI instead of a simple multicolor picture as it always seemed to be used. However, this has probably been done before and because I don't like to do things that have been done before, I decided to use linecrunch to show a two-screen-tall FLI picture.
Linecrunch works by setting $D011 equal the line before the current line and VIC-II will happily think that it is time to move on to the next character row - add 40 to the video matrix counter, 320 to the graphics memory counter and be ready to start a bad line. Or, maybe 'NOT to go back to the current row' would be a more suitable description. (Programming VIC-II is slowly becoming a science.)
The required timing also does not cause bad lines so that you can skip another line immediately on the successive line. In addition, lines can be skipped only after the first character row and half of the second character row have been displayed. This has something to do with the way VIC-II decides when there is a bad line.
Because linecrunch causes VIC-II to skip rows, it will run out of video matrix and color memory (and graphics memory) before reaching the end of the screen. However, VIC-II does not stop displaying the graphics nor does it reset the internal counters. The counters keep on running and wrap around instead.
Normally, when VIC-II is displaying the last character row, it is showing the memory from offsets $3c0 to $3e7. If VIC-II has skipped one character row, it is displaying from $3e8 to $40f instead. But, there are only 10 bits for the video matrix counter (0..1023), so it wraps around to zero after $3ff. This means that the beginning of the video matrix is displayed at the bottom of the screen. The character rows become shifted by 24 character positions to the right because there were originally 24 unused memory locations at the end of the memory (1000..1023). (To be honest, sprite image pointers are not unused memory, but they are not used with normal FLI.)
The same thing happens for color memory because it uses the same
counter for addressing the memory (in fact, color memory access and
character data access are performed simultaneosly, 12 bits at a
time). The graphics memory behaves the same way, except that the
counter has three bits more and it counts at eight times the speed,
so that it wraps at the exact same time as the other counter.
The first character row can't be used for linecrunch and the second
one is also lost in the process. The first usable line to display
is the third character row. However, those two lost rows can still
be used as an extension at the end of the first screen. You must
notice, however, that the alignment has been changed. After these
two rows have been displayed, the video bank is switched to get new
fresh data on the screen.
Figure 2 shows the principles. To make things simpler I have chosen
location 0 to mean that the top of the picture is visible, 1 means
that the picture is scrolled one line upwards and so on. We can see
that linecrunch is not used at all for the location 0. To make the
picture start at the same point whether linecrunch has crunched
lines or not we compensate the non-lost raster lines by delaying the
next bad line. When the location is n*8 (n=0,1,2..), the sum of the
linecrunched and delayed lines is constant - the graphics display
always starts at the same point.
Then how do we deal with the location values that are not evenly
dividable by eight ? Now, lets assume that the location is L, and
we have C, which is the location divided by eight (C = L/8), and R,
which is the remainder (R = L%8). To make the picture scroll to the
right position, we need to delay the bad line less than before - R
lines less for location L than for location C*8. E.g. for location
2 we delay the bad line two lines less than for location 0. This
also shows that we need 7 lines more than is needed for to
compensate for the linecrunch.
Determining the number of linecrunch lines is a recursive process,
because when you use more linecrunch lines, that decreases the
number of lines you have available for the display and you need
bigger range for the location value. The linecrunch can be started
after 12 lines, and we need at least 7 lines to use the soft
y-scroll. This makes 181 lines available for the display
originally.
Because we need to show 400 lines of graphics, we would need
(400-181)/8=28 linecrunch lines. However, this in turn reduces the
number of lines we have for graphics to 181-28=153 and we need
(400-153)/8=31 linecrunch lines. Again, 181-31 is 150. We get
(400-150)/8=32 and there it finally converges and we have 149 lines
for graphics, which makes location values 0..251 valid.
When both ECM and multicolor mode (MCM) are selected, VIC-II will
turn the display to black. This is because there is a conflicting
situation and it just can't decide which color scheme to use. The
video accesses will continue to happen just like before, the data is
just not displayed. When the ECM bit is cleared again, the normal
multicolor graphics is shown.
So, we set the ECM bit and start to display the first eight lines of
the FLI. Because the FLI routine already writes to $D011, we just
make sure the ECM bit is set in the first R number of writes to
$D011 and zero in all other.
The viewer is now 'complete'. You can take a look at the code below
or you can get C64Gfx1_4.lha and see it in action yourself and not
just rely on my word. The package includes converter programs for
BFLI, FLI and Koala (ANSI-C), couple of example pictures and viewers
for PAL and NTSC machines.
-Pasi 'Albert' OjalaBack to BFLI
Wrapped data is nothing difficult to work with. It is just the
matter of writing the right conversion program. Also, the normal
FLI routine can be used, we just have to make sure VIC always has
the right bank visible - simple LDA bank,x:sta $DD00 can accomplish
that. The more difficult aspect is to make the display freely
locatable. We have 32 kilobytes of graphics data, this is the main
reason we can't even think about using copying. Linecrunch combined
with the bad line delaying technique will do the job much more
nicely.Clipping added
Now we can scroll the picture to any location we want, but the top
of the picture is not clipped and it is very annoying to watch. We
need to enable the graphics at the same point regardless of the
y-scroll value. The answer is in the extended color mode (ECM).
albert@cs.tut.fi
BFLI viewer program for PAL machines
The BFLI file format: