From ervin@pinbot.enet.dec.com Fri May 10 15:35:00 1991 Flags: 000000000001 Received: from enet-gw.pa.dec.com by hpuxa.acs.ohio-state.edu with SMTP (15.11/15.6) id AA08264; Fri, 10 May 91 13:34:42 edt Return-Path: Received: by enet-gw.pa.dec.com; id AA14061; Fri, 10 May 91 10:34:10 -0700 Message-Id: <9105101734.AA14061@enet-gw.pa.dec.com> Received: from pinbot.enet; by decwrl.enet; Fri, 10 May 91 10:34:21 PDT Date: Fri, 10 May 91 10:34:21 PDT From: 10-May-1991 1331 To: ryee@hpuxa.acs.ohio-state.edu Subject: Re: HP48: Waynes mail server Hi Roger, Here's another file that would be good for Wayne's mail server. This is the source code to my screen dissolver. The executable is currently in the graphics directory, so that's probably where this file should go as well. How about a file description like "Source code for Joe Ervin's dissolver.". Thanks again! >>>Joe **************************************************************************** ; DISSOLVE VERSION 0.2 ; Joe Ervin - 4-MAR-1991 ; ; The following program is written for the HP-48SX. This program is intended ; to be assembled using the Star assembler, version 1.04.2 or later. ; The purpose of this program is to provide a function which can be used to do ; screen dissolves. In other words, this program will take a GROB from the ; stack and dissolve it into PICT, updating PICT with the pixels of the new ; GROB one pixel at a time, in a visually random sequence so that the visual ; effect is that the image contained in the GROB dissolves into the display, ; replacing the existing image in PICT in an asthetically pleasing manner. ; THEORY: ; ; The basic technique used to dissolve the screen will be to number the nibbles ; which make up the GROB sequentially, such that the nibbles which make up the ; first row of pixels start from the left with 1, 2, 3, and so on. the rest ; of the lines are numbered similarly. In this way, all the nibbles that make ; up the GROB (and PICT) are numbered from 1 to n, where n is the last nibble ; on the right end of the last row of pixels. ; ; The method used to generate the pixel addresses will be to use a simple ; psuedo-random number generator formula. There are many such formulae which ; will generate all integers between 0 and 2^n exactly once (which is what ; we want here. The formula I have chosen is a particularly simple one, and ; is given as : ; ; next(r) = (r * 5) + 3. ; ; In our case, we will mask these random numbers to 14-bits. We will use the ; bottom 2 bits of this random number to indicate which of the four pixels ; within each nibble we should transfer. This allows us ; to randomly generate relative addresses for all the pixels in PICT (assuming ; that PICT is 131x64, as is usually the case). ; Using this, we can successfully generate the address of every pixel in ; PICT exactly once. Of course, we will unavoidably generate addresses which ; are outside the bounds of PICT (since the size of PICT is not an even power ; of 2). Such addresses will simply be discarded. ; NOTES: D0 is the RPL instruction pointer. ; D1 is the stack pointer. Grows towards lower addresses. ; B is the FRAME pointer. Grows towards higher addresses. ; D is the amount of nibbles between stack and heap. ; Each of the above registers may have a secondary use within the program. ; R0 holds the pointer to the dest GROB (PICT) data field. ; R1 holds the GROB size. ; R2 holds a pointer to the source GROB data field. ; R3 holds the 12 bit version of the random number. ; R4 holds the 14/12 bit version of the random number. ; D holds the 14-bit mask. ; B holds the bit mask corresponding to the bit within the ; nibble which is to be transfered. header ; puts the kermit header at the top. ; Below is the internal RPL structure which will do error checking and which ; encapsulates the machine language routine. ; ; The RPL code expects the following parameters on the stack from the user. ; ; 2: A real number. Zero indicates that a bit-wise dissolve should be ; performed. A 1 indicates that tiling should be done. ; 1: Source GROB. ; The purpose of this RPL code is to do the argument ; type checking and build the proper parameters on the stack for the machine ; language code which does the actual screen dissolve. badgrob = `Invalid GROB Data' badgrobs = $((2 * sz^badgrob) + 5) badpict = `Invalid PICT Size' badpicts = $((2 * sz^badpict) + 5) radix ^x10 ; Set the radix to hex. rpl ; Start of RPL body. 2d9d ; Start of program 1884d ; Set last token to <0h>. 18a8d ; Check that there are at least 2 arguments on the stk. 18fb2 ; Check that the args are the right type. 4107 ; <1Ch> 2: real, 1: GROB. 2d9d ; Start of program 3188 ; Internal DUP. ; Now we need to check the size of the GROB to make sure it has the standard ; size. 1ca62 ; Internal SIZE (graphic). 5a03 ; binary --> short 3223 ; Internal SWAP. 5a03 ; binary --> short 3223 ; Internal SWAP. ; Now both dimensions of the grob are short binaries. 2911 ; System Binary 40 ; 64 decimal. 63d3a ; If TOS-1 = TOS (Syst Bin), then skip next, else ; do next and return. 2d9d ; Start of program 3244 ; Internal DROP. Get rid of row dimension. 2A2C ; String _data.a badgrobs ; length of the string. _ascii badgrob 1a339 ; DOERR. 312b ; end marker 2911 ; System Binary 83 ; 131 decimal. 63d3a ; If TOS-1 = TOS (Syst Bin), then skip next, else ; do next and return. 2d9d ; Start of program 3244 ; Internal DROP. Get rid of row dimension. 2A2C ; String _data.a badgrobs ; length of the string. _ascii badgrob 1a339 ; DOERR. 312b ; end marker ; Now we need to check the size of PICT to make sure it has the standard size. 5187f ; Get pict dimensions. 3223 ; Internal SWAP --> 2: columns, 1: rows. 2911 ; System Binary 40 ; 64 decimal. 63d3a ; If TOS-1 = TOS (Syst Bin), then skip next, else ; do next and return. 2d9d ; Start of program 3244 ; Internal DROP. Get rid of row dimension. 2A2C ; String _data.a badpicts ; length of the string. _ascii badpict 1a339 ; DOERR. 312b ; end marker 2911 ; System Binary 83 ; 131 decimal. 63d3a ; If TOS-1 = TOS (Syst Bin), then skip next, else ; do next and return. 2d9d ; Start of program 3244 ; Internal DROP. Get rid of row dimension. 2A2C ; String _data.a badpicts ; length of the string. _ascii badpict 1a339 ; DOERR. 312b ; end marker 3223 ; Internal SWAP. Put the "real" at level 1. 18cea ; Convert real to system binary. 2911 ; System Binary; the size-1 of PICT in nibbles. ^d2175 ; 2175 decimal. 3223 ; Internal SWAP. endrpl ;************************************************************************* ; The machine language portion of DISS starts here. radix ^d10 ; set default radix to decimal code ; START OF MACHINE LANGUAGE ROUTINE. ; Addresses of ROM routines. save_registers = ^x679B ; Saves system registers. restore_registers = ^x67d2 ; Restores system register. rplcont = ^x71BE ; Jumps to the next RPL instruction. rr_rplcont = ^x5143 ; Restores the system registers and ; then does rplcont. get_short = ^x6641 ; Pops the short of TOS and returns it ; into A.A ; General address definitions bos = ^x7057E ; Pointer to beginning of the stack. pict_pointer = ^x70565 ; Pointer to PICT grob. START: ; The first thing we need to do is to get the input parameters off the stack. ; The parameters that this routine expects on the stack are: ; 3: Source GROB (the one which will be on display at end of routine.) ; 2: System binary integer (short) indicating the number of nibbles to move. ; 1: System binary integer (short) indicating #0 for bit-wise dissolve, or ; #(nonzero) for tiling. CALL.A get_short ; Put the tile/dissolve indicator in A.A ; If this integer is a zero, then we ; do bit-wise dissolve. If non-zero, we do nibble ; tiling. CLR.W D ; Clear every bit in D. BRZ.A A, DISSOLVE ; If zero, then leave D.S clear for (dissolve). ; Otherwise, set D.S = 1 (for tiling). TILING: INC.S D ; Set D.S to 1 (nonzero is all that matters). ; This field will be tested later. DISSOLVE: CALL.A get_short ; Get the level 2 system binary off the stack into A.A. ; This is the GROB size-1. CLR.W C ; SWAP.A A, C ; MOVE.W C, R1 ; Save it in R1. ; Then we get the pointer to the source GROB data and load it into R2. MOVE.A @D1, A ; Gets the address of the level 3 object. ADD.A 10, A ; Skip over the prolog and size fields. ADD.A 10, A ; Skip over the row and column fields of the GROB. MOVE.A A, R2 ; Save pointer to GROB data in R2. ADD.A 5, D1 ; to pop the level 3 object off the stack... INC.A D ; and increment the free size counter. CALL.A save_registers ; Save the system registers. ; At this point, we have saved all the information we need to start the loop ; which calculates all the screen addresses randomly. ; The following psuedocode represents essentially what this code does: ; BEGIN ; R = 0 ; TRANSFER_PIXEL(R[BITMASK]); ; DO ; R = RANDOM(R) ; IF R <= GROB_SIZE THEN TRANSFER_PIXEL(R[BITMASK]) ; UNTIL R = 0 ; END; ; We need to fetch the address of the beginning of the data field of PICT. MOVE.A pict_pointer, D1 ; Address which contains pointer to ; display. MOVE.A @D1, C ; get the address of PICT GROB. ADD.A 10, C ; Skip over the prolog and size fields. ADD.A 10, C ; Skip over the row and column size fields. MOVE.A C, R0 ; Copy pointer to PICT data field in R0 for later use. ; We need to initialize the mask held in D to ^x3FFF if doing a bit-wise ; dissolve or to ^xFFF if tiling. CLR.W C ; MOVE.P5 ^x3FFF, C ; Puts 14 ones in the lower bit positions of C, BRZ.S D, DISSOLVE2 ; Tiling or bit-wise dissolve? MOVE.P5 ^xFFF, C ; Change the mask to 12 bits for tiling. DISSOLVE2: MOVE.A C, D ; and transfer it to D. CLR.W A ; MOVE.W A, R3 ; Initialize the random value to 0. MOVE.W A, R4 ; Note: because of the really cool properties of the ; algorithm used here, the value 0 will not repeat ; until every other integer has been created. ; Note that if doing tiling we use a 12-bit integer, ; and if dissolving, we use a 14-bit integer. CLR.W C MOVE.P2 ^x11, C ; Indicates the first bit for dissolve. BRZ.S D, DISSOLVE3 ; Tiling or bit-wise dissolve? MOVE.P2 ^x0F, C ; Change the bit pattern to ^xF if tiling. DISSOLVE3: MOVE.B C, B ; The bottom nibble of B holds the bit mask which indicates which ; bit(s) in the nibble we are transfering. If we are dissolving, then only ; 1 bit of this nibble is set. If tiling, then this nibble contains ^xF to ; indicate that all four bits within the nibble should be transfered at once. ; Now we must transfer a pixel of data at the ; Rth nibble of the stack GROB to the PICT GROB. The bit within the nibble ; that will be transfered is indicated by the BITMASK variable. MOVE.A R3, A ; Get the random number. CALL TRANSFER_GROB ; Transfer the GROB data pointed to by A.A. DO: ; Begin the loop. MOVE.W R4, C ; Get the 14/12-bit version of the random number R. ADD.A C, C ; ADD.A C, C ; MOVE.W R4, A ; ADD.A A, C ; Multiply R by 5,... ADD.A 3, C ; ....and add 3. AND.A D, C ; Mask off everything but the lower 14/12-bits. MOVE.A C, R4 ; Temporary storage for 14/12-bit version. This ; 14/12 bit number is compared to 0 to see if the ; random number generator has finished its cycle. MOVE.A C, R3 ; This is for the case of tiling. If dissolving, this ; will be overwritten below. BRNZ.S D, P_TRANS ; Tiling or dissolving? If tiling, then we can ; leave B containing ^xF. SRB.A C SRB.A C ; Shift the bottom two bits out, yielding a 12-bit #. MOVE.A C, R3 ; Save the 12-bit random number in R3. This copy of ; the random number R is always 12-bits, and is used ; by the code which transfers the GROB data to index ; into the GROB. SRB.B B ; Shift the mask one bit to the right to point to the ; next bit to be tranfered. This works because the ; the random number generator used here cycles the ; botom 2 bits through 3, 2, 1, 0, 3, 2, 1, 0, etc. ; Therefore, we just drop them and rotate the bit mask. MOVE.B B, A ; Get copy of bit mask. BRBC 3, A, P_TRANS ; If bit mask is OK, skip to P_TRANS. SETB 7, A ; Else, insert a 1 in bit 7 to keep the rotating bit ; mask working properly. MOVE.B A, B ; Restore new bit mask. P_TRANS: MOVE.A R1, A ; Get the GROB size. MOVE.A R3, C ; Get the 12-bit version of the random number. This ; will be used below as an index into the source GROB. BRGT.A C, A, SKIP ; IF R is greater than the GROB size, then ; skip it. SWAP.A A, C ; Put the GROB offset in A.A. Required by the procedure ; TRANSFER_GROB. CALL TRANSFER_GROB ; Transfer a pixel or nibble of data from the ; source GROB to PICT. SKIP: ; We came here because the generated random number was outside the ; range of addresses in the GROB. MOVE.A R4, A ; Get the value of R most recently generated. BRNZ.A A, DO ; If the last value of R is zero, then we have finished ; generating all the addresses, and have finished this ; pass. Otherwise, we must branch up and keep ; generating more random values. ; Now to restore things to a sane state before returning control to the calling ; RPL program. DONE: JUMP rr_rplcont ; Restore the system registers... ; and continue on with the RPL thread. TRANSFER_GROB: ; Routine that transfers GROB data from the source ; GROB to PICT. MOVE.A R2, C ; Get the pointer to the GROB data. ADD.A A, C ; Add the offset (R) MOVE.A C, D1 ; Point to nibble in stack GROB to be read. CLR.W A ; Zero out A. MOVE.B @D1, A ; Get the nibble from the GROB into A. ; Now what I need to do is GROB*MASK+PICT*MASK_BAR ---> PICT. AND.B B, A ; Perform bit-AND of BITMASK and nibble from GROB. ; This value will be ORd with the same nibble from ; PICT and written back into PICT, thus moving the bit ; from the stack GROB to PICT. MOVE.W R3, C ; Get the pointer into the GROB. ; At this point, the modified nibble from stack GROB is in A. ; the offset into PICT is in C. SWAP.A A, D1 ; Save the nibble in A into D1 for a moment. MOVE.A R0, A ; Get the address of PICT. ADD.A A, C ; Now C contains the address of the nibble in PICT. SWAP.A A, D1 ; Restore the nibble from the source GROB into A. MOVE.A C, D1 ; Point into PICT. MOVE.B @D1, C ; Get the nibble from PICT. NOT.B B ; Invert the mask for a moment. AND.B B, C ; Mask off the bits to be modified. OR.B A, C ; Modify the BITMASKth bit in the nibble,.... NOT.B B ; restore the mask to its original state. MOVE.1 C, @D1 ; and write it back into PICT. RET endcode radix ^x10 ; Go back to hex. RPL 312b ; end marker. 312b ; End program object ENDRPL end