Home | Contents | KwikPik |
OUT OF ALL PROPORTION
Normal Speccy printing is ugly, ugly, ugly and boring, boring, boring. Here's shaped crusader Tony 'Slim' Samuels with a pretty neat alternative! |
given here or one of your own design. If
you've got an assembler, you can go to
work on the assembly listing. Otherwise,
you'll have to type in and use the hex
loader provided. Once that's in, use the
hex loader to enter the proportional
character set itself. Done all that? Wow,
you're getting really quick! Okay, best
remember to save the whole shebang as
one lump with: SAVE "PROPSYS" CODE 64200,1150 Now, whenever you get the urge, you can set up the whole thing with: CLEAR 64199: LOAD "PROPSYS" CODE: RANDOMIZE USR 65000 LPRINT ; will go on working until you do a NEW. You can get it back afterwards with another RANDOMIZE USR 65000. The Speccy's got 96 printing characters from space (CHR$(32) to the copyright symbol CHR$(127)). Each of these is defined just like a UDG using 8 bytes. A proportional character set is done in a similar way except the first byte of each definition is used to tell the print program how wide the character is, so that it can start the next character just after it. To work out this byte, just set those bits that aren't used by the character to 1 and leave the rest at 0. If your character is four bits wide, the bits 8,7,6,5 and 4 should all be 0 (bit 4 is 0 so that there's a one pixel gap between this character and the next) and bits 0,1 and 2 should be 1. Simple really! And I've included a little font designer listing opposite so you can get started right away. There, who says I'm just a pretty face? | |
---|---|---|
No-one could say that the way the Speccy
PRINTs is the most beautiful in the
world. The problem is that the screen is
divided into 32 character columns and
every character always takes up the same
amount of space on the screen. Hardly
news and not the kind of thing that
bothers us hacks at all. But it's a bit of a
shock for all those poor misdirected
human beings out there in the real world. Now take a close look at these words in YS, You'll see that thin characters like I and 1 take up a lot less space than fat ones like M and W. This is our secret way of making sure you can read and re-read YS from cover to cover at no risk to your eyesight. Who says we don't look after you? So how's about a little bit of machine code to print properly using this sneaky proportional printing idea? Not only will any program you write using it look really nice and be very pleasant to use but you get the added benefit of printing at any pixel position on the screen and so stuff far more than 32 characters on every line. Choose thin words and you'll get more than 100 characters per line! Proportional printing is therefore ideal for any |
program with lots of text in it -
databases, word processors and so on. GOTO LPRINTTo make life even easier, the print program here becomes part of Speccy Basic by taking over the LPRINT command. The syntax is the same except you can now use the AT command if you like. The program doesn't like INK and PAPER control codes but it will print in whatever permanent colours you've set with INK and PAPER. Once you've got the routine loaded, the command, LPRINT AT 0,0; "Your Spectrum" will print "Your Spectrum" proportionally spaced in the top left of your screen. All proportional printing is done as if OVER 1 was set so you've got to be careful only to print on blank bits of screen or else the result will be more of a mess than the usual PRINT command!GET LOADEDTo get your own printing going, you're going to have to type in the proportional print program and either the character set |
SHAPIN' UP ... You'll find here all the code you need to get proportional printing up and running on your Speccy. Tony's also provided a designer program, so if you're not happy with his creative characters then you can knock up your own. If you're going for the minimum typing job, then you'll only need to enter three parts. The Hex Loader (which enters the code), the Proper Print machine code listing (using either our Hex Loader or your own assembler package) and finally the Character Set code using the Hex Loader program. | A HEX FOR YOU |
In case you're wondering, this is a hex loader - a program to provide hours and hours of endless entering fun for all the family. To use it, type it in and SAVE it and then enter the print program by typing in each line of hex in the second column of the main listing (one byte at a time) starting from address 65000. When you've finished type xx. The checksum should come to 45760 if you've got it right. Next, use the loader to enter the proportional character set. It starts at 64200 and the checksum should come to 64743. Don't forget to save it all with SAVE "PROPSYS" CODE 64200,1150 . | |
10 CLEAR 62199 20 INPUT "START LOCATION >"; sl 40 LET a=10: LET b=11: LET c=12: LET d=13: LET e=14: LET f=15 50 LET cq=0 60 LET t=0 100 INPUT h$ 105 IF LEN h$<>2 THEN GO TO 100 107 IF h$="XX" OR h$="xx" THEN GO TO 200 110 LET h=0 120 LET h=h+16*VAL h$(1) 130 LET h=h+VAL h$(2) 140 POKE sl,h: LET sl=sl+1 145 LET cq=cq+h 150 PRINT TAB (t);h$;: LET t=t+3: IF t=33 THEN LET t=0: PRINT 160 GO TO 100 200 INPUT "CHECKSUM >";cs 210 IF cs<>cq THEN PRINT: PRINT "DATA ENTRY ERROR": STOP 220 PRINT: PRINT "DATA OKAY" |
PROPER PRINT | ||
This is it - the machine code program that, coupled with a character set at 64200, prints like magic on your Speccy. If you've got an assembler or monitor, you can start straight away. Otherwise nip ahead and type in the hex loader and come back when it's running. | ||
FDE8 0010 ORG 65000 5C8D 0020 ATTRP EQU 23693 22AA 0030 PIXAD EQU 22AAH 5C7B 0040 UDG EQU 23675 | ||
Start the routine at 65000 and declare some labels. | ||
FDE8 26A8 0050 INITI LD H,168 FDEA 2E00 0060 LD L,0 FDEC 22DBFE 0070 LD (XPOS),HL | ||
Reset the printing position to the top left of the screen. | ||
FDEF 2A4F5C 0080 ENABL LD HL,(23631) FDF2 010F00 0090 LD BC,15 FDF5 09 0100 ADD HL,BC FDF6 01FDFD 0110 LD BC,DO-IT FDF9 71 0120 LD (HL),C FDFA 23 0130 INC HL FDFB 70 0140 LD (HL),B FDFC C9 0150 RET | ||
Change the pointer to the LPRINT routine in the CHANS table to point to the proportional printing routine. | ||
FDFD E5 0160 DO-IT PUSH HL FDFE C5 0170 PUSH BC FDFF D5 0180 PUSH DE FE00 F5 0190 PUSH AF FE01 CD09FE 0200 CALL DOIT1 FE04 F1 0210 POP AF FE05 D1 0220 POP DE FE06 C1 0230 POP BC FE07 E1 0240 POP HL FE08 C9 0250 RET | ||
Save all the registers, call the printing routine, put back all the registers again and leap back to the operating system. | ||
FE09 F5 0260 DOIT1 PUSH AF FE0A 3AE2FE 0270 LD A,(ATFLG) FE0D FE00 0280 CP 0 FE0F 200B 0290 JR NZ,GETXP FE11 F1 0300 POP AF | ||
Look to see if last character was a control code 22 - the code for AT. | ||
FE12 FE16 0310 ATCHQ CP 22 FE14 2021 0320 JR NZ,CRCHQ FE16 3EFF 0330 LD A,255 FE18 32E2FE 0340 LD (ATFLG),A FE1B C9 0350 RET | ||
If the current character is an AT control code, set the ATFLG to indicate that the next two codes dealt with will be the X and Y positions for the print. | ||
FE1C FEFE 0360 GETXP CP 254 FE1E 2809 0370 JR Z,GETYP FE20 F1 0380 POP AF FE21 32DBFE 0390 LD (XPOS),A FE24 21E2FE 0400 LD HL,ATFLG FE27 35 0410 DEC (HL) FE28 C9 0420 RET FE29 F1 0430 GETYP POP AF FE2A 47 0440 LD B,A FE2B 3EA8 0450 LD A,168 FE2D 90 0460 SUB B FE2E 32DCFE 0470 LD (YPOS),A FE31 3E00 0480 LD A,0 FE33 32E2FE 0490 LD (ATFLG),A FE36 C9 0500 RET | ||
If the last character was an AT then fetch the X and Y co-ordinates and move to the new printing position. | ||
FE37 FE0D 0510 CRCHQ CP 13 FE39 2009 0520 JR NZ,VCHRQ FE3B CD1CFF 0530 CALL DWNCR FE3E 3E02 0531 LD A,2 FE40 CD0116 0532 CALL 1601H FE43 C9 0540 SKIPC RET | ||
If the current character is a Return control code, move down 8 pixels and open channel 2 to deal with nasty INK and PAPER control codes. | ||
FE44 FE20 0550 VCHRQ CP 32 FE46 3804 0560 JR C,PRNT? FE48 FE80 0570 CP 128 FE4A 3804 0580 JR C,FCHR FE4C 3E3F 0590 PRNT? LD A,63 | ||
Burp! If the character is not between 32 and 127 then print a question mark instead. | ||
FE4E 1800 0600 JR FCHR FE50 210000 0610 FCHR LD HL,0 FE53 6F 0620 LD L,A FE54 29 0630 ADD HL,HL FE55 29 0640 ADD HL,HL FE56 29 0650 ADD HL,HL FE57 EB 0660 EX DE,HL FE58 2AE6FE 0670 LD HL,(CRADR) FE5B 19 0680 ADD HL,DE FE5C 7E 0690 LD A,(HL) | ||
Figure out where the character's definition is stored in memory. | ||
FE5D 32E3FE 0700 LD (CRMSK),A FE60 3600 0710 LD (HL),0 | ||
Store the first byte of the character (the width indicator) and stick a zero byte in its place. | ||
FE62 22E4FE 0720 LD (CRAD1),HL FE65 010700 0730 PRNIT LD BC,7 | ||
We're getting there! Load CRADD with the address of the seventh byte of the character, check the character will fit on the screen and calculate the address in the display file where the character will be printed. | ||
FE68 09 0740 ADD HL,BC FE69 22E0FE 0750 LD (CHRAD),HL FE6C 3ADCFE 0760 LD A,(YPOS) FE6F FEA9 0770 CP 169 FE71 D2FCFE 0780 JP NC,ERR5 FE74 CD05FF 0790 CALL FITCQ FE77 ED4BDBFE 0800 LD BC,(XPOS) FE7B CDAA22 0810 CALL PIXAD FE7E 32DFFE 0820 LD (PIXPQ),A FE81 22DDFE 0830 LD (DFADD),HL FE84 0608 0840 LD B,8 FE86 C5 0850 PRNLP PUSH BC FE87 2AE0FE 0860 LD HL,(CHRAD) FE8A 7E 0870 LD A,(HL) FE8B 2B 0880 DEC HL FE8C 22E0FE 0890 LD (CHRAD),HL FE8F 6F 0900 LD L,A FE90 3ADFFE 0910 LD A,(PIXPO) FE93 FE00 0920 CP 0 FE95 CAA2FE 0930 JP Z,PUTIT FE98 47 0940 LD B,A FE99 2600 0950 LD H,0 FE9B CB3D 0960 ROTLP SRL L FE9D CB1C 0970 RR H FE9F A7 0980 AND A FEA0 10F9 0990 DJNZ ROTLP FEA2 ED5BDDFE 1000 PUTIT LD DE,(DFADD) FEA6 1A 1010 LD A,(DE) FEA7 AD 1020 XOR L FEA8 12 1030 LD (DE),A FEA9 CD2AFF 1040 CALL COLAD FEAC 3ADFFE 1050 LD A,(PIXPO) FEAF FE00 1060 CP 0 FEB1 CABCFE 1070 JP Z,PST FEB4 13 1080 INC DE FEB5 1A 1090 LD A,(DE) FEB6 AC 1100 XOR H FEB7 12 1110 LD (DE),A FEB8 CD2AFF 1120 CALL COLAD FEBB 1B 1130 DEC DE FEBC 2ADDFE 1140 PST LD HL,(DFADD) FEBF CDE9FE 1150 CALL ULINE FEC2 22DDFE 1160 LD (DFADD),HL FEC5 C1 1170 POP BC FEC6 10BE 1180 DJNZ PRNLP | ||
Rotate the character definition into the correct pixel position, place it on the screen one byte at a time and make sure each byte is in the right colour. | ||
FEC8 3AE3FE 1190 LD A,(CRMSK) FECB 2AE4FE 1200 LD HL,(CRAD1) FECE 77 1210 LD (HL),A FECF 3ADBFE 1220 LD A,(XPOS) FED2 47 1230 LD B,A FED3 3AE8FE 1240 LD A,(WIDTH) FED6 80 1250 ADD A,B FED7 32DBFE 1260 LD (XPOS),A FEDA C9 1270 RET | ||
Get the width indicator byte and put it back at the start of the character definition. Then move right the correct number of pixels for the character just printed. | ||
FEDB 00 1280 XPOS DEFB 0 FEDC A8 1290 YPOS DEFB 168 FEDD 0000 1300 DFADD DEFW 0 FEDF 00 1310 PIXPO DEFB 0 FEE0 0000 1320 CHRAD DEFW 0 FEE2 00 1330 ATFLG DEFB 0 FEE3 00 1340 CRMSK DEFB 0 FEE4 0000 1350 CRAD1 DEFW 0 FEE6 C8F9 1360 CRADR DEFW 64200-256 FEE8 00 1370 WIDTH DEFB 0 | ||
Reserve a bit of space for some variables. | ||
FEE9 F5 1380 ULINE PUSH AF FEEA 7C 1390 LD A,H FEEB 25 1400 DEC H FEEC E607 1410 AND 7 FEEE 200A 1420 JR NZ,END FEF0 7D 1430 LD A,L FEF1 D620 1440 SUB 32 FEF3 6F 1450 LD L,A FEF4 3804 1460 JR C,END FEF6 7C 1470 LD A,H FEF7 C608 1480 ADD A,8 FEF9 67 1490 LD H,A FEFA F1 1500 END POP AF FEFB C9 1510 RET | ||
Here's a handy routine that sets HL to point to the next pixel line up in the display file. | ||
FEFC 3AE3FE 1520 ERR5 LD A,(CRMSK) FEFF 2AE4FE 1525 LD HL,(CRAD1) FF02 77 1530 LD (HL),A FF03 CF 1540 RST 8 FF04 04 1550 DEFB 4 | ||
Restore the width indicator byte to the first byte of the character definition and generate an Out of Screen error. | ||
FF05 0608 1560 FITCQ LD B,8 FF07 3AE3FE 1570 LD A,(CRMSK) FF0A 4F 1580 LD C,A FF0B A7 1590 CNTLP AND A FF0C CB39 1600 SRL C FF0E 3003 1610 JR NC,OUT FF10 05 1620 DEC B FF11 18F8 1630 JR CNTLP FF13 78 1640 OUT LD A,B FF14 32E8FE 1650 LD (WIDTH),A FF17 3ADBFE 1660 LD A,(XPOS) FF1A 80 1670 ADD A,B FF1B D0 1680 RET NC FF1C 3E00 1690 DWNCR LD A,0 FF1E 32DBFE 1700 LD (XPOS),A FF21 3ADCFE 1710 LD A,(YPOS) FF24 D608 1720 SUB 8 FF26 32DCFE 1730 LD (YPOS),A FF29 C9 1740 RET | ||
Check if the character to be printed will fit on this line - if it doesn't, move down 8 pixels and back to the left hand side of the screen. | ||
FF2A E5 1750 COLAD PUSH HL FF2B F5 1760 PUSH AF FF2C 7A 1770 LD A,D FF2D CB0F 1780 RRC A FF2F CB0F 1790 RRC A FF31 CB0F 1800 RRC A FF33 E603 1810 AND 3 FF35 F658 1820 OR 58H FF37 67 1830 LD H,A FF38 6B 1840 LD L,E FF39 3A8D5C 1850 LD A,(ATTRP) FF3C 77 1860 LD (HL),A FF3D F1 1870 POP AF FF3E E1 1880 POP HL FF3F C9 1890 RET | ||
And another useful routine - it calculates the relevant address in the attributes file from a given display file address and stores the value of ATTRP (the permanent PAPER and INK colours) in it. | ||
1900 FINIS END | ||
That's all folks! | ||
CHARACTER SET | ||
Here's the info for proportionally spaces characters - all 96 of them! Grab the hex loader and get going ... | ||
| ||
FONT DESIGNER | ||
You can use this either for the proportional printing program or for the Speccy's normal characters. Q, A, O and P move the cursor around - give Troubleshootin' Pete a ring if you can't work out which does which direction! To set a pixel use M and to turn one off use N. F stores the design on the grid in memory as any particular character you want, D displays any character, U shows the whole character set and S and J save and load the whole lot for you. Once you've saved a new set, you can load it into the proportional print program with LOAD "name" CODE 64200. Away you go ... | ||
10 CLEAR 39999 20 LET ba=40000 100 PRINT AT 2,3;"??????????" 110 FOR f=3 TO 10: PRINT AT f,3;"?00000000?": NEXT f 120 PRINT AT 11,3;"??????????" 130 LET a=0: LET b=0 200 OVER 1: PRINT AT a+3,b+4;"?": PAUSE 2: PRINT AT a+3,b+4;"?": PAUSE 2: OVER 0 210 LET a=a+(INKEY$="a" AND a<7)-(INKEY$="q" AND a>0) 220 LET b=b+(INKEY$="p" AND b<7)-(INKEY$="o" AND b>0) 230 IF INKEY$="m" THEN PRINT AT a+3,b+4; INVERSE 1;"X": PLOT b+160,(8-a)+151 240 IF INKEY$="n" THEN PRINT AT a+3,b+4;"O": PLOT INVERSE 1;b+160,(8-a)+151 250 IF INKEY$="f" THEN GO TO 300 260 IF INKEY$="d" THEN GO TO 400 270 IF INKEY$="u" THEN GO TO 500 275 IF INKEY$="s" THEN GO TO 1000 280 IF INKEY$="j" THEN GO TO 1020 290 GO TO 200 300 INPUT "WHICH CHARACTER ";c$ 310 IF LEN c$<>1 THEN GO TO 300 320 IF CODE c$<32 OR CODE c$>127 THEN GO TO 300 330 LET c=CODE c$ 340 FOR f=0 TO 7 350 POKE (c-32)*8+f+ba,PEEK (16468+(f*256)): NEXT f: RUN 400 INPUT "WHICH CHARACTER ";c$ 410 IF LEN c$<>1 THEN GO TO 400 420 IF CODE c$<32 OR CODE c$>127 THEN GO TO 400 430 POKE 23606,64: POKE 23607,155: PRINT AT 2,20;c$: POKE 23606,0: POKE 23607,60 440 FOR a=0 TO 7: FOR b=0 TO 7 450 IF POINT (b+160,(8-a)+151)=1 THEN PRINT AT a+3,b+4; INVERSE 1;"X": GO TO 470 460 PRINT AT a+3,b+4;"O" 470 NEXT b: NEXT a 480 LET a=0: LET b=0: GO TO 200 500 PRINT AT 15,0;: FOR f=32 TO 127: PRINT BRIGHT 1;CHR$ f;" ";: NEXT f 501 PRINT AT 15,0;" ";: OVER 1: FOR f=32 TO 127: POKE 23606,64: POKE 23607,155: PRINT BRIGHT 1;CHR$ f;: POKE 23606,0: POKE 23607,60: PRINT " ";: NEXT f: OVER 0: POKE 23606,0: POKE 23607,60 510 BEEP .1,1: PAUSE 0: PAUSE 0: RUN 1000 INPUT "file name ";f$: SAVE f$ CODE 40000,768: RUN 1020 INPUT "file name ";f$: LOAD f$ CODE 40000,768: RUN 9999 STOP: ERASE "m";1;"YSGD": SAVE *"m";1;"YSGD": STOP | ||
DEMO LISTING JOB | ||
If you're still confused about life, death and the meaning of proportional printing, try out this major new adventure program once you've got PROPSYS working. Cor, it's even harder than Castle Rathbone! Just so you can see how awful Speccy printing is, the magic word xyzzy will flip you between the two types of printing. | ||
1 REM *Proportional Printing* 2 REM * Tony Samuels 1985 * 9 REM --Initialise routine-- 10 LET i=USR 65000 11 PAPER 0: BORDER 0: CLS 12 FOR f=1 TO 7 15 INK f 20 LPRINT AT f*2+50,(f-1)*8;"Proportional Printing" 30 NEXT f 40 FOR f=7 TO 1 STEP -1 50 INK f 60 LPRINT AT f*2+50,(6+(8-f))*8;"Proportional Printing" 70 NEXT f 80 FOR f=0 TO 10 85 INK RND*6+1 90 LPRINT AT 165-f*2,80+f*8;"In High Resolution" 120 NEXT f 125 PAUSE 400 130 INK 0: PAPER 0: BORDER 0: CLS 132 LET i=USR 65000 135 INK 5 136 LET c=3 140 LPRINT AT 70,0;"The YS Silly Adventure" 145 DATA "You are in a room","You are in a cave","You find yourself in a dank dungeon","You are in an extremely messy office (Yeah ed.) !","You are having a nightmare (or are you)" 146 DATA "A shaft of light beams down from the roof","It is dark","There is a bucket nailed to the floor which you can't pick up","There are strange etchings on the wall","A wind is blowing" 150 LPRINT: LPRINT: LPRINT 160 INK RND*4+3 170 RESTORE 145: FOR f=1 TO INT (RND*5)+1: READ f$: NEXT f 180 RESTORE 146: FOR f=1 TO INT (RND*5)+1: READ s$: NEXT f 185 IF PEEK 65244<30 THEN LET l=USR 65000: CLS 190 PRINT #c;f$;", ";s$: PRINT #c 200 INPUT INK 5;"COMMAND >";c$ 210 IF c$="xyzzy" THEN IF c=2 THEN LET c=3: RANDOMIZE USR 65000: CLS: GO TO 221 220 IF c$="xyzzy" THEN IF c=3 THEN LET c=2: CLS 230 IF c$="n" OR c$="s" OR c$="w" OR c$="e" OR c$="xyzzy" THEN GO TO 250 235 IF PEEK 65244<30 THEN LET l=USR 65000: CLS 240 INK 5: PRINT #c: PRINT #c;"I'm sorry I don't understand!": BEEP .5,1: GO TO 200 250 PRINT #c: PRINT #c;"OKAY sir" 300 GO TO 160 |
![]() |
---|
Before ... and after. The difference, as you can see, is quite dramatic. Not only is the proportional text more pleasing to look at - it's also easier to read! |
Home | Contents | KwikPik |