Font Effects ============ Jonathan Harston, 15 Norris Road, Sheffield, S6 3TR. This program allows you to apply various effects to text displayed on the screen. It came from a desire to be able to write a program to preview word processed text documents to see how they would appear when printed, so it implements most of the font effects available on many printers. The listing generates the FONTFX command file. Type it in and check it with Get it Right! When run it generates the code and saves it as FONTFX. The font effects are enabled by entering: *FONTFX or */FONTFX Once enabled, GCOL 140,n and GCOL 141,n can be used to select various font styles. The value n is a bitmap of the font styles that can be selected, so multiple styles can be selected by adding up each bit value. GCOL 140,0 or GCOL 141,0 and MODE resets the font effect to Plain. The font style bitmap with the effects it selects is shown in this table: Bit Value Effect ----------------------- - 0 plain 0 1 underline 1 2 bold 2 4 italics 3 8 thin 4 16 superscript 5 32 subscript 6 64 inverse 7 128 wide You can select font styles in the following way: GCOL 141,1:PRINT "1=Underlined" GCOL 141,2:PRINT "2=Bold" GCOL 141,3:PRINT "3=Bold and Underlined" GCOL 141,0:PRINT "0=Plain" GCOL 141 selects an absolute font style. GCOL 140 on the other hand adds to the existing font style by OR'ing it with the selected style. GCOL 140,1:PRINT "1=Underlined" GCOL 140,2:PRINT "1+2=Bold and Underlined" GCOL 140,0:PRINT "0=Plain" Being able to select the font styles with GCOL means that the VDU sequence can be embedded in a string and printed. For example: setbold$=CHR$18+CHR$141+CHR$2 setundr$=CHR$18+CHR$141+CHR$1 setnorm$=CHR$18+CHR$141+CHR$0 PRINT setbold$;"Bold text ";setundr$;"underlined";norm$;" plain" addbold$=CHR$18+CHR$140+CHR$2 addundr$=CHR$18+CHR$140+CHR$1 addnorm$=CHR$18+CHR$140+CHR$0 PRINT addbold$;"Bold text ";addundr$;"bold+underlined";addnorm$;" plain" The program FONTDEMO demonstrates the effects by cycling through all the font styles. All eight font styles can be combined, but by the nature of the BBC screen display some of the combinations will not be ideal. For instance, selecting subscript+thin+italic+underline can be rather hard to read, and setting both thin and bold can result in some strange effects. Also, selecting both superscript and subscript will result in just subscript being selected. How it works ------------ As each character is sent to OSWRCH the VDU queue is checked. If the queue is empty, it must be either a printable character or the first character of a VDU sequence. If it is a printable character and the font flag is non-zero then each bit of the font flag is checked to create a new bitmap to print. The OSWRCH intercept also checks for a VDU 18 GCOL sequence. If it recognises the VDU 18,140,n or VDU 18,141,n GCOL sequence then it claims it by clearing the VDU queue and sets the font flag. If it recognises a VDU 22,n MODE sequence, it clears the font flag and passes the MODE command on. The new bitmap is created by reading the character's definition with OSWORD 10, then going through each bit of the font flag and building a new bitmap. This is then used to define character 255, and then CHR$255 is printed. Underline is simple, all the pixels of the bottom pixel line are set. +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | ---> | | |##|##|##|##| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | | |##|##|##|##|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | ---> |**|**|**|**|**|**|**|**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Bold characters are formed by doubling pixels by moving each pixel line left and superimposing it back with the original value. The extra pixel is added at the left side as wide characters such as M and W have their rightmost pixel set, and adding the leftmost pixels keeps the characters symetrical. +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | ---> | |**|##|##|##|##| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**|##|##| |**|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**|##|##| |**|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | |**|##|##|##|##|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**|##|##| |**|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**|##|##| |**|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**|##|##| |**|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | ---> | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Thin characters are formed by reducing all double pixels to single pixels. This is done my moving each pixel line left and using AND with the original value. This only leaves pixels where the original line was at least two pixels wide. The rightmost pixel is removed instead of the leftmost pixel as wide characters such as M and W have their rightmost pixel set, and removing the rightmost pixels keeps the characters symetrical. +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | ---> | | |##|##|##|--| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|--| | |##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|--| | |##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | | |##|##|##|##|##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|--| | |##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|--| | |##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|--| | |##|--| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | ---> | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Italic characters are formed by moving the top three pixel lines to the right and the bottom three pixel lines to the left: +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | ---> | | | |##|##|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|##| | |##|##| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|##| | |##|##| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | | |##|##|##|##|##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |##|##| | |##|##| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |##|##| | |##|##| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | ---> | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Superscript and subscript characters are formed by picking five pixel lines to form the character. A bit of adjustment is done to pick the best lines to use, most lower case characters use a slightly different set of pixel lines. Superscript characters put these five lines at the top of the bitmap, and subscript characters put them at the bottom. +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | -------> | | |##|##|##|##| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | /--> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ / +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | --/ /--> | |##|##|##|##|##|##| | +--+--+--+--+--+--+--+--+ / +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | --/ /--> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ / +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | --/ /-> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ / +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | / | | | | | | | | | +--+--+--+--+--+--+--+--+ / +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | -/ | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | -\ | | | | | | | | | +--+--+--+--+--+--+--+--+ \ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | \ | | | | | | | | | +--+--+--+--+--+--+--+--+ \ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | -\ \ | | | | | | | | | +--+--+--+--+--+--+--+--+ \ \ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | -\ \ \->| | |##|##|##|##| | | +--+--+--+--+--+--+--+--+ \ \ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | -\ \ \-> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ \ \ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | \ \-> | |##|##|##|##|##|##| | +--+--+--+--+--+--+--+--+ \ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | --\ \-> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ \ +--+--+--+--+--+--+--+--+ | | | | | | | | | \--> | |##|##| | |##|##| | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Inverted characters simply invert all the pixels: +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | ---> |**|**| | | | |**|**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**| | |**|**| | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**| | |**|**| | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | |**| | | | | | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**| | |**|**| | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**| | |**|**| | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | |**| | |**|**| | |**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | ---> |**|**|**|**|**|**|**|**| +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Double-width characters are created by building two bitmaps, one for the lefthand side and one for the righthand side, with each pixel rotated out of the source line and rotated twice into the destination line. +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | |##|##|##|##| | | --> | | | | |##|**|##|**| |##|**|##|**| | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|**|##|**| | | | | |##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|**|##|**| | | | | |##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##|##|##|##|##| | | | |##|**|##|**|##|**| |##|**|##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|**|##|**| | | | | |##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|**|##|**| | | | | |##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | |##|##| | |##|##| | | | |##|**|##|**| | | | | |##|**|##|**| | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ | | | | | | | | | --> | | | | | | | | | | | | | | | | | | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ Intercepting VDU commands ------------------------- To select the font style I needed some call to make to set the font style variable. There are various ways of doing this. For instance, I could have used a spare OSBYTE variable, but I wanted a method that used a VDU sequence so that the selection could be sent along with any other characters sent to OSWRCH, for instance: PRINT bold$;"bold";norm$ Two unused VDU sequences are passed to UKVDUV, the Unknown VDU vector: unknown PLOT codes, and unknown VDU 23 codes. With a full graphics system almost all the PLOT codes are used, and PLOT sends five bytes to OSWRCH which seems wasteful when selecting a font style only needs one byte. There are plenty of unused VDU 23 commands, but there is no BASIC command to send a VDU 23 command, so everything would need a long VDU 23,a,b,c,d,e,f,g,h,i command. However, GCOL is a nice short VDU sequence, has a BASIC command, and has lots of spare command codes. On all Acorn machines, GCOL 0 to 7 are used for the standard GCOL actions. Extended graphics with the GXR ROM or on the Master uses the rest of the GCOL codes up to &5F. Testing on the Archimedes shows GCOL codes up to &7F are used. This quite neatly leaves GCOL codes &80-&FF free. Looking at the way other OS calls are laid out, in my code I have tentatively followed the following scheme: &Ax : reserved ('A' for Acorn) &Ex : for applications (similar to OSWORD &Ex) &Fx : for applications (similar to OSWORD &Fx and PLOT &Fx) From these I picked &8C and &8D because if you negate them you get ASCII letters, which is a useful mnemonic: GCOL -ASC"s" set the font 's'tyle GCOL -ASC"t" add 't'o the font style This is similar to other code I have written that uses GCOL -ASC"w" to select a window. Intercepting a VDU sequence also means that only one vector needs to be intercepted, the WRCHV vector. WRCHV already needs to be intercepted to apply the effects to displayed characters, so checking for GCOL can be done at the same time. It makes it a little fiddlier as the code has to ensure characters are still passed to the printer, serial, and SPOOL outputs if they are selected, but it means not having to intercept both WRCHV and UKVDUV or some other vector. Note to editor ============== It is Jonathan. Not Jon, not John, not Johnathan, not Jonathon. Jonathan.