x×x××x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x× How to code a 'non-blitter' screen typer An ACC tutorial by Mike Cross. x×x××x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x× First off, let me explain the aim of this tutorial. I am sure you have all seen demo's which at some point feature a routine to display a screenful of text. Quite impressive some of them. Also quite easy to code. In fact, a screen typer is so easy to code I won't even use the blitter! That is the 'aim' of this tutorial. To teach you how to write a fast and flexible screen typer. 1. Fonts I am sure we all know what a font is. I use Powerfonts16 or Powerfonts8 to create all of my fonts now - for the following reasons :- a) The raw data files are tiny! b) The format of the characters are easy to incorporate into code. c) Powerfonts have all punctuation and lower case letters. Powerfonts is Public Domain so you should not have much difficulty in obtaining it. Those of you who read the 17bit software Newsflash disks will find Powerfonts on disk 17a. I have included three fonts with the accompanying source code; for you to experiment with. 1.1. The font format. Now we know which fonts are being used I shall take a moment to discuss how the characters are stored. It is important that you understand the format of the raw files - else you may have difficulties following later on. Powerfonts stores the following Ascii characters :- (note. first char is a space!) !"#$%&'()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~ These letters corespond to Ascii codes 32 through to 126. The letters are stored in the raw file 'above' each other, which would look something like this :- *************... <-+ **************.. | ***************. | *****....******. | *****.....*****. | *****.....*****. | ***************. | ***************. +-- A. This is 16 words long. ***************. | *****.....*****. | *****.....*****. | *****.....*****. | *****.....*****. | *****.....*****. | *****.....*****. | ................ <-+ *************... <-+ **************.. | ***************. | *****....******. | *****.....*****. | *****.....*****. | **************.. | *************... +-- B. Directly below the A. **************.. | *****.....*****. | *****.....*****. | *****....******. | ***************. | **************.. | *************... | ................ <-+ . . . And so on. So, from this, we can see that each character is only 16 words, or, 32 bytes long; and is stored in a linear fashion. The actual characters are 16 pixels wide by 16 pixels deep (oh! what a perfick size to work with!) 2. Text structure (arghhhh!) Yup - A structure for you. I know what you are all thinking - this is a hardware tutorial with hardware code - so why use structures? The simple answer is; structures make everything a damned sight easier. The actual text structure is fairly simple. TextStruct1 dc.l TextStruct2 dc.w 0 dc.w 20 dc.w 'L' dc.l Font1 dc.l Text1 Simple eh? The first entry; in true structure fashion, points to the next entry in the linked list, or, if there are no more entries - it is zero. Next comes the X and Y co-ordinates. The co-ordinates are set relative to the top left corner of the screen. Here X is zero and Y is set to 20. This text will appear near the top left of the screen. The 'L' controls the desired text justification. Possible options are L for left, R for right and C for centre. If anything other than 'L' is used the previously set X position will no longer apply. Note; in the version of screen typer supplied with this tutorial, the justify option has not been implemented - BUT MUST BE INCLUDED! Next comes a pointer to the font for the text. Font1 is incbin'ed in the usual manor :- Font1 incbin Dh0:Fonts16/Powerfont1.fnt04 You can use several Powerfonts in your productions, as each font only use 3072 bytes (or 3K) of memory. Finally comes a pointer to the text itself. The structure only controls a single line of text at a time. The text can be entered as follows :- Text1 dc.b '- On every street. -',0 The text should be no longer than 20 characters. If it is the text will flow over to the next screen raster line and look messy. This has been rectified in version 3.0 by truncating the offending letters. Upper and lower case letters are allowed along with all standard punctuation. So, to recap - a complete text structure looks like :- TS1 dc.l TS2 * Next dc.w 0 * X dc.w 0 * Y dc.w 'L' * Justify dc.l Font1 * Use this font dc.l Text1 * And this text TS2 dc.l 0 dc.w 0 dc.w 60 dc.w 'R' dc.l Font2 dc.l Text2 Text1 dc.b 'ACC - No competition',0 Text2 dc.b 'CSM - What a crock! ',0 Font1 incbin Dh0:Fonts16/Powerfont1.fnt04 Font2 incbin Dh0:Fonts16/Turd.fnt 2. Reading the structure. Now the structure has been defined, we need some code to read it, and to act upon the information supplied there in. The ReadStruct routine needs 1 paramater passing to it, which is the linked text list. This must be in A1 as such :- lea TextStruct1,a1 bsr ReadStruct At the start of the stucture read code, we initialise two screen pointers :- ReadStruct move.l PlaneAddresses(a6),a0 move.l a0,a3 * 2 Bitplanes add.l #PlaneSize+40,a3 The screen typer code works on two bitplanes only. This at first seems illogical, as PowerFonts saves the data for 1 plane only; but with a bit of careful coding - we can use plane 2 as a 'drop shadow' effect. A0 will point at the first bitplane throughout the code, and A3 will point at the second plane. By adding 40 (1 raster line) to A3 and by setting bplcon1 (the screen scroll register) to $10 we create the shadow effect. You may be wondering why I use A0 and A3 for the screens and not A0 and A1. The simple reason is that I only added the second plane AFTER I had coded everything else - so A1 was well and truley tied up. Next, I store the address of the 'next' Structure in the list onto the stack, as this is not needed until later :- move.l (a1)+,-(sp) The X position is read and added to the address of both bitplanes :- move.w (a1)+,d0 add.w d0,a0 add.w d0,a3 The same applies to the Y position, except it is multiplied by the width of the screen (usually 40) and then added to the screen addresses :- move.w (a1)+,d0 mulu #ScreenWidth,d0 add.w d0,a0 add.w d0,a3 The justify option is not yet active, but the A1 counter must still be bumped. The value is read into D7 and is not used again :- move.w (a1)+,d7 The long word addresses for the font and the text come next. They are placed into A4 and A2 respectivly :- move.l (a1)+,a4 move.l (a1),a2 Initialisation is now complete. The text can now be written to the screen by calling the 'TypeString' sub-routine :- bsr TypeString I will detail this routine later. After the 20 characters in the string have been displayed to the screen the address of the next structure is pulled off the stack, and a check is made to see if it is zero or not. If it is zero the routine will exit. If it is 'not zero' It must contain the address of the next structure in the text list so the whole process will be repeated :- move.l (sp)+,a1 cmpa.l #0,a1 bne ReadStruct rts That is basically everything required to read a 'structure' You could easily modify the code to include other options or adapt it for your own needs. Again, a recap of the whole routine :- Read move.l PlaneAddresses(a6),a0 move.l a0,a3 * 2 Bitplanes add.l #PlaneSize+40,a3 move.l (a1)+,-(sp) * Push next onto stack moveq.l #0,d0 move.w (a1)+,d0 * X Pos add.w d0,a0 add.w d0,a3 * And plane 2 moveq.l #0,d0 move.w (a1)+,d0 * Y Pos mulu #ScreenWidth,d0 add.w d0,a0 add.w d0,a3 * Plane 2 move.w (a1)+,d7 * Ignore justify (for now) move.l (a1)+,a4 * Font move.l (a1),a2 bsr Type move.l (sp)+,a1 * Next struct' or null cmpa.l #0,a1 bne Read rts 3. Typing the string. Finally comes the all important routine to place the text on the screen. This is quite complex as a good speed must be matained at all times. I will take this routine an instruction or two at a time :- Type moveq.l #20-1,d0 AllChrs move.l a4,a1 * Font off stack There are twenty characters in the string so this is placed in d0. The font address is loaded into a1 (from A4) moveq.l #0,d0 move.b (a2)+,d1 subi.w #32,d1 rol.w #5,d1 * x32 add.l d1,a1 D0 is cleared as the character is going to be read into it. Remeber, A2 points to the text. The ascii code is read with the move.b (a2)+,d1 Unfortunatly Ascii is not particularly useful when coding. The Ascii value of the character needs to become an offset from the base address of the font. Suppose the character was an 'A' This has an Ascii code of 65 and is the thirty third character into the font. If we subtract 32 from the Ascii code we are left with the desired 33. 32 must be subtracted as the first code we are using is space with an Ascii code OF 32. Now we know the character number (33) we can simply multiply it by the size of each letter. Remeber each letter is 16 words, or, 32 bytes long. So by multiplying the 33 by 32 we arrive with 528 which just happens to be how far into the font the A is. The figure can now be added to the font base address for later. Now comes the actual copy (blit!) routine:- moveq.l #16-1,d2 moveq.l #0,d3 D2 holds the height of the letter which is 16. D3 will be used as the destination modulo. Now for the copy :- TypeIt move.w (a1),(a0,d3.w) move.w (a1)+,(a3,d3.w) add.w #ScreenWidth,d3 dbf d2,TypeIt A1 points to the start of the current letter data. A0 points to the current screen position. The move.w (a1),(a0,d3.w) moves the first line of the letter into the plane. This instruction is repeated for both bitplanes. The 'ScreenWidth' can now be added to D3 (the modulo). A dbf loop is then used to copy the rest of the font. Don't forget, each loop; 40 will be added to D3 so each time a move.w (a1),(a0,d3.w) is called; the data will be drawn to the next raster line down the screen. Finally, we can add two to the plane pointers (in A0 and A3) and repeat this process for all 20 characters :- addq.l #2,a0 addq.l #2,a3 dbf d0,AllChars rts And that is it. To re-cap, here is the whole 'TypeString' code again :- Type moveq.l #20-1,d0 AllChrs move.l a4,a1 * Font moveq.l #0,d1 * Char byte move.b (a2)+,d1 subi.w #32,d1 rol.w #5,d1 * x32 add.l d1,a1 moveq.l #16-1,d2 * Char height moveq.l #0,d3 * Modulo index TypeIt move.w (a1),(a0,d3.w) move.w (a1)+,(a3,d3.w) add.w #ScreenWidth,d3 dbf d2,TypeIt addq.l #2,a0 addq.l #2,a3 dbf d0,AllChrs rts 4. And finally . . A simple and I think pretty fast routine. I could have easily used the blitter to perform this task, but why? when there really is no need. I know the Atari ST takes a fair amount of arse kicking from the Amiga and its owners - but remeber this: there is no blitter on the ST; so ALL ST scrollers/demos/bobs/games will be coded in a manor similar to this. I must admit I have never used an ST (or even seen a working one) so I cannot vouch for the quality of their demos - but I bet they look as though a blitter has been used. ST coders deserve a medal. If you find this program useful - good. It can be easily modified to accept 8x8 fonts from Powerfonts8. If anybody wants an '8 version and can't do it for themselves - let me know and I will make all of the necessary alterations. Before I go, a quick note to Dave Edwards. I loved the area fill and fractal docs on disk 14. I very much look forward to seeing the outcome of the 'elite' style graphics and reading future docs written by you. Keep up the excellant work! Die in a beautiful way, code fast and work hard. Mike Cross, September 14th 1991 x×x××x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×x×