Update: All needed files for this tutorial can be found in the GitHub repo linked in the bottom of this page.
In the previous tutorial, we learned how to create and render a bitmap, and how to enter bitmap-mode.
In this tutorial, we are going to use almost the same concepts, but instead of rendering bitmaps, we are rendering text. We are also going to use a custom charset instead of the pretty boring charset that’s default.
The default charset look like this:
First of all, I’m not good at creating fonts so I won’t teach you how to do this. Instead we are going to download a charset that is named Scrap Writer III 17. Don’t know who created it but if anyone knows, please let me know so I can add proper credits.
The Scrap Writer III 17 charset look like this:
Donwload the charset here:
Download other charsets from this page: http://kofler.dot.at/c64/ but remember, some of them might be copyrighted.
Rendering text
Rendering text is quite simple. All you need is to either use the default charset or a custom charset. Also, you will need the text you want to render.
Let’s write our program.
First, we want to clear the screen. You could use the method we created earlier, but to keep this example to the point, I’m going to use a function that is included on the Commodore 64 and located at $e544. This routine clears the screen.
Also, we want to set the screen color and the border color to something greenish.
processor 6502
org $1000
jsr $e544
lda #$0d
sta $d020
lda #$05
sta $d021
Then we load the custom charset, using the same method as in the previous tutorial about rendering bitmaps. Our screen memory is at $0400 and charset at $2000.
lda #$18
sta $d018
Now it’s time for the meat of this tutorial. The loop that writes the text! First, we set the x-register to zero. Then we load the x’th character of msg (declared in the bottom) into the accumulator.
ldx #$00
write: lda msg,x
Once it’s loaded, we jump to a subroutine that writes text to the screen. This routine is located at $ffd2. All it does is to write the value in the accumulator to the screen.
jsr $ffd2
The text we want to render is 54 character long. We loop through each of the characters and write it to the screen.
inx
cpx #54
bne write
Next we are setting the color of our characters. This could be done in the loop above, but just to split the different functionality, I decided to create another loop that does this. The color is stored at $d800 and so on. We do this for each of the 54 characters.
ldx #$00
setcolor: lda #$07
sta $d800,x
inx
cpx #$54
bne setcolor
In the end, we create an infinite loop so we can see what we rendered.
loop: jmp loop
Then we need to load our data. We create msg that contain the text we want to render
msg .byte “C64 programming tutorial by digitalerr0r of Dark Codex”
And then we include our custom charset
org $1ffe
INCBIN “scrap_writer_iii_17.64c”
And that’s it for rendering text. If you run this example, you will see the same result as below.
Listing 8.1 – Rendering text
processor 6502
org $1000
jsr $e544
lda #$0d
sta $d020
lda #$05
sta $d021
lda #$18
sta $d018
ldx #$00
write: lda msg,x
jsr $ffd2
inx
cpx #54
bne write
ldx #$00
setcolor: lda #$07
sta $d800,x
inx
cpx #$54
bne setcolor
loop: jmp loop
msg .byte “C64 programming tutorial by digitalerr0r of Dark Codex”
org $1ffe
INCBIN “scrap_writer_iii_17.64c”
Downloads
Download the source from GitHub:
https://github.com/petriw/Commodore64Programming/tree/master/8-TextCharsets
Pingback: Windows Client Developer Roundup 067 for 5/1/2011 - Pete Brown's 10rem.net
I noticed that I get garbage when I am using lowercase mode, since there ARE no lowercase letters in the charset (like the 2nd image for the default set) — and it would seem logical that if you copied this image (scrappy) to the memory area for that — the characters would be REVERSED… right ??? Capitals (aka uppercase for context here) would be lowercase and lowercase would be uppercase.
Is there a trick to FLIP this during the loading process of the charset?
I love this font for my Sci-Fi RPG game, but I use LOWERCASE in the program — so this is teasing me.
– Dave Hartman
Great again.
For people who started with acme syntax, c64studio
replace .byte
by !text
exemple (with cpx #5)
msg !text “hello”
The source code link is broken 😦
Make sure there’s a colon after msg-
msg: .byte “C64 programming tutorial by digitalerr0r of Dark Codex”
Why the #$18 that’s stored in $d018? It must be related to $2000 (where the data for the new char set starts), but I don’t get how.
Bits 1-3 are used to calculate the value in this way: $200 * lower nibble value + $400 offset, which in our case equals ($200 * $8) + $400 == $2000
More info here:
https://codebase64.org/doku.php?id=base:vicii_memory_organizing
@Mark: But $200 * $8 + $400 = $1400. Actually, it’s different. We have $2000 = $400 * $8. So, the lower nibble has to be set to $8. The higher nibble points to screen memory. If it’s $x, then the screen memory is at $400 * $x. In the usual case, $x = $1. Hence the $18.
@WebFritzi: Sorry, hurried incorrect answer based on what I’d read on another site – this page came up while I was finding out about this myself, and I foolishly answered before checking what I’d read. You are of course right. (Wish I could delete the comment…!)
@Mark: Not a problem. Your obviously wrong calculation made me think and so I finally looked up the documentation. When I posted the question above, I didn’t know where to find this information and if I had known, I wouldn’t have understood it. However, in my opinion, it should have been explained in the tutorial.