First I would like to thank the author of Claudia; it is a magnificent piece of work! I never would have thought of doing this without analyzing his program first... and why should we let the French have all the fun... Ok, this document contains my analysis of this shades of grey thing. Contained here in these humble lines I have attempted to describe how to go about designing a shades of grey program (in MC of course). I have also provided the source (and a uuencoded version at the end) for a simple shades of grey display utility. The source code is fully commented and also describes the hardware display locations used and their significance. There are many variations on this theme which I describe later. The basic idea is to create a sequence of grobs which when displayed successively will give the illusion of shades of grey. If a pixel is on in all of the frames, it will give the darkest presentation. The only way to display frames quick enough is to mess around with the display address pointer. The HP has a pointer located in $120h which points to the first line of the display memory data. This 5 nib pointer is write only. The display hardware accepts the data you store there and remembers it when it is time to refresh the display. Refreshing the display happens 64 times each second. It is important to know that bit 0 of this pointer is ignored. This means that the display memory has to be byte alligned, that is to say that it must begin on an even address (remember HP memory is only 4 bit). HP has conveniently assigned both the PICT display memory and the STACK display memory to even address just for this reason. Now one requirement of rpl is that data and code objects *MUST* be relocatable. It must work equally well when an object begins at an even or an odd address. There is no way to guarantee that a grob you place on the rpl stack will begin at an even address. This fact makes it necessary to adjust other display parameters to fix the problem when the grob on the stack begins at an odd address. Suppose your grob data (line 1) begins at address $34567 and you want to display this 131x64 grob by altering the display pointer to point at this location. After storing the $34567 to the display pointer, the HP will think that the actual address is $34566 since bit 0 is ignored. The presentation on the display will be shifted to the right by 4 pixels with 4 pixel columns of garbage on the left side of the display. This can be corrected by shifting the display left 4 pixels. The HP hardware has such a feature. $100h is the display bit offset for scrolling. Storing a number here between 0 and 7 will shift the display left by that number of pixels. You must also take care to fix $125, the display line byte offset. This is the number of nibs skiped after each line. It is a 3 nib signed (2's compliment) number with bit 0 ignored as well. When shifting a display left by 4 pixels you must set this to a -2 nibs, or -1 bytes. In any case, store a $FFE here. This feature allows the HP to display any region of a grob that is larger than the display. This is accomplished by setting the display to point at the first nib of the desired line and by setting the display line byte offset to skip all the undesired nibs and by setting the display bit offset to shift the display up to 7 pixels. Wow, if that isn't complicated enough, there is one more thing to worry about... the vertical size of the display. There is a counter (read and write allowed) at $128 which holds the current line in the display that is being refreshed. This counter starts at 63 and decriments to 0 and then repeats. It cycles 64 times each second. If you store a 63d in this 2 nib address, it will instruct the hardware to display all 64 lines of the display. Storing a 55d here will allow the menu grob to be displayed on the bottom 8 lines of the display. Enough theory. The program which I have included below is a modification to the origional Claudia program. The author of Claudia was so very clever. He designed his 11 shades of grey to be *INTERLACED*. There was a total of 11 frames in the Claudia grob and the display utility only displayed every other one each pass. This decreased the amount of flicker. There are some obvious variations on this theme. In Claudia, each frame was given an equal ammount of display time (weight). You can easily design a grob sequence and display utility using a 1,2,4,8,etc, weighted scheme. In this way it would only take 3 frames to represent 8 shades of grey, thereby saving memory. Read over the first fiew lines of the display source for a description of how to design your own shades of grey pictures. I am presently working on a pc program which will take a .tif file and convert it to an HP shades of grey grob. There may be a problem which can surface when using the included display utility. On exit, it is assumed that the menu was displayed and that the display was scrolled to the upper left corner. It may become necessary to modify the dispay utility if your application has some other initial conditions. You can also replace the keyboard reading portion of the program with your own graphic animation thing, provided it does not consume more than 31250 clock cycles (SX). Your own animation routine must return control to the shades of grey utility before it is time for the next refresh or else flickering may result. The uuencoded zip1.9 file which is included at the end of this article is a HP directory object which contains the following... (1) 'CLAUD11' the origional Claudia grob (RFU packed) (2) 'TESTGROB' a small 4 color test grob which I made (also RFU packed) (3) 'GREYSCAL' the compiled version of the following display util source (4) 'RFU' my modified version of the RFU unpacker which works on the GX If anyone has any questions, comments, suggestions, flames, or money \:-) you wish to send to me, please feel free to contact me at randyd@csd4.csd.uwm.edu ~a politically incorrect hacker...~ Randy. --------------- cut, begin source code ------------------ * This is a *multiple* shades of grey display utility. * Compile this source file with the HP rplcomp/sasm tools. * It displays an encoded grob sequence to give the illusion of grey scale. * An on pixel in all the frames gives the darkest presentation. * --> Requires one grob on stack level 1 and it must be 131 x 64*n * where n is the number of frames. The display utility determines * the number of frames from the size of the grob. * --> If there are at least 7 frames, and the number of frames is odd, * then the display utility will interlace the frames. By interlacing * the frames (displaying every other one) the flicker is reduced. It * should help in these cases to design the frame order for a progression * from lightest to darkest. * --> Equal weight is given to each frame. * * Written by: Randy Ding * Date: October, 1993 * Email: randyd@csd4.csd.umw.edu * * Display controls used and their significance... * * $00120h [5 nibs] = Display address pointer (write only, bit 0 ignored) * $00125h [3 nibs] = Display line byte offset (write only, bit 0 ignored) * This 2's compliment signed number designates the number * of nibs to skip after each line before start of next. * $00100h [1 nibs] = R/W, Display bit offset for scrolling. Shifts display * left up to 7 pixels. MSB is 'DispOn' flag, must be 1. * $00128h [2 nibs] = R/W, Line counter. Begins at 3F, decr to 0 and repeats. * Store here the number of display lines -1. Normally 55d * if menu row is on, 63d if menu is off. Display refresh * is complete when this counter reaches zero. (64/second) * Mask off bits 6 and 7 when reading. ASSEMBLE NIBASC /HPHP48-E/ RPL :: CK1NOLASTWD CK&DISPATCH1 #C ( *grob* ) :: DUPGROBDIM ( *must be 131 x 64*n grob* ) BINT_131d #<> SWAP SIXTYFOUR ( *calculate number of frames* ) #/ ( *grobYsize / 64 -> remain, quotient* ) SWAP #0<> ( *if remainder <> 0 then bad* ) ROT OR ITE DROP ( *drop #frames and skip code if bad* ) CODE :ILACE EQU 0 interlace flag bit in ST reg GOSBVL =POP# pop number of frames from RPL stack R1=A.F A save number of frames GOSBVL =SAVPTR save registers INTOFF totally disable keyboard interrupts ST=0 15 " A=DAT1 A D1 -> grob object now on top of stack C=0 A LC(2) 20 skip 20 nib prolog A=A+C A R0=A.F A save pointer to data grob first line ?ABIT=0 0 even address? GOYES :EVEN skip if grob data is allready byte alligned LC(1) #C 1100b, [disp on: b3] & [offset: b2 b1 b0] D0=(5) #00100 display bit offset address DAT0=C 1 shift display left 4 pixels D0=(2) #25 line byte offset addr, nibs skipped per line LC(3) #FFE signed number with bit 0 ignored DAT0=C X make byte offset = -2 nibs (1 byte) :EVEN D0=(5) #128 display line counter addr D1=(5) #120 display start addr LC(2) 63 DAT0=C B make line counter 63 A=R1.F A recall number of frames ST=0 :ILACE make flag bit = 1 if interlacing required ?ABIT=0 0 don't interlace if even # of frames GOYES :NOLACE LC(2) 7 ?ARow1 get original display address AD0EX DAT1=A A reset display address ?ABIT=0 0 check for even address GOYES :EXITEVEN LA(1) #C 1100b, [disp on: b3] & [offset: b2 b1 b0] LC(3) #FFE signed number with bit 0 ignored GOTO :EXIT01 :EXITEVEN LA(1) #8 LC(3) #0 :EXIT01 D1=(2) #0 reset bit offset DAT1=A 1 D1=(2) #25 reset line byte offset DAT1=C X INTON enable keyboard interrupts ST=1 15 " GOVLNG =GETPTRLOOP recall registers then LOOP ENDCODE DROP ( *grob* ) ; ; ----------- cut, end of source ---------------