home *** CD-ROM | disk | FTP | other *** search
Text File | 1985-06-01 | 12.2 KB | 282 lines | [TEXT/MACA] |
- ;
- ; procedure dissBytes (srcBits, dstBits: bitMap); external;
- ;
- ; mike morton
- ; release: 14 february 1985 (happy birthday, chuck!)
- ;
- ; version one. somewhat tested, but not in a wide variety of programs.
- ;
- ; ******************************************************************************
- ; * *
- ; * copyright 1985 by michael s. morton *
- ; * please see details below on using, copying and changing this source. *
- ; * *
- ; ******************************************************************************
- ;
- ;
- ; about dissBytes:
- ; ---------------
- ;
- ; dissBytes copies one whole bitMap to another, moving bytes in a pseudo-random order. its function is a
- ; SUBSET of dissBits', with these restrictions:
- ; - you must copy an entire bitmap to another of equal size.
- ; - the bitmap.bounds rectangle must be the full width of the bitmap. this probably means your
- ; destination bitmap is the whole screen.
- ; - the bitmap must not contain more than 64k bytes (this should be no problem; the screen is only 21kb).
- ; the full screen will dissolve in about 0.3 seconds. it would be nice to have the effect run a little bit
- ; slower, but that shows up the fact that the data are moved a byte at a time, giving an effect like a short
- ; burst of bad TV reception.
- ;
-
- ; sample calling code:
- ; -------------------
- ;
- ; this code is loosely taken from the cursor editor. it uses three bitmaps, which take up a lot of
- ; memory. one is the real screen; the second saves the original screen while we play; the third has new
- ; stuff drawn into it, and is dissolved onto the real screen. to restore the original stuff, we dissolve
- ; from the second to the first. a real program would more likely generate update events for the affected
- ; area. note that we dissolve the WHOLE screen, and thus we have to copy everything to the third bitmap
- ; before we start drawing the things we want to dissolve in.
- ; (caveat: this code has been edited a lot from the actual application; it's never really run.)
- ;
- ; var
- ; anEvent: eventRecord; { used to wait for a mousedown }
- ; oldPbits: bitmap; { original screen bitmap }
- ; newBits: bitmap; { bitmap to draw in between setUpFade and doFade }
- ; savBits: bitmap; { bitmap to save the screen in }
- ; dissrect: rect; { dissolve rectangle }
- ;
- ; dissrect := theport^.portbits.bounds; { steal the screen bounds }
- ; newBits := thePort^.portbits.bounds; { and, in fact, the whole bitmap }
- ; newBits.baseAddr := qdptr(newptr( { except the base address points to this new storage }
- ; newBits.rowbytes*(dissrect.bottom-dissrect.top))); { width times height }
- ; savBits := newBits; { temp for old screen looks just the same... }
- ; savBits.baseAddr := qdptr(newptr(
- ; savBits.rowbytes*(dissrect.bottom-dissrect.top))); { ...but has yet another bitmap }
- ; oldPbits := thePort^.portBits; { remember where the screen is }
- ; setPortBits (newBits); { but for now, we draw in here }
- ;
- ; copyBits (oldPbits, newBits, dissrect, dissrect, srcCopy, nil); { copy the original screen here }
- ; copyBits (oldPbits, savBits, dissrect, dissrect, srcCopy, nil); { and save a copy which we won't trash }
- ;
- ; (*** do all the drawing you want here; it'll go to the offscreen bitmap "newBits". ***)
- ;
- ; dissBytes (newBits, oldPbits) { put new stuff on screen, slowly }
- ; flushEvents (mDownMask+keyDownMask, 0); { ignore mousedowns from during the dissolve }
- ; repeat until getnextevent(mDownMask+keyDownMask,anevent); { wait for them to click or type }
- ; dissBytes (savBits, oldPBits) { restore the screen, also slowly }
- ;
- ; disposPtr (ptr(newBits.baseAddr)); { toss stuff we drew }
- ; disposPtr (ptr(savBits.baseAddr)); { and space we used to save the original screen }
- ; setPortBits (oldPbits); { go back to drawing on the real screen }
- ;
-
- ;
- ; duplication and use of this routine:
- ; -----------------------------------
- ;
- ; this is freeware. you're welcome to copy it and use it in programs. you're welcome to modify it, as long
- ; as you leave everything up until this section unchanged. you're welcome to port it to other machines;
- ; i'd appreciate hearing about efforts to do this.
- ;
- ; if you use it for profit, i ask that you pay for my work. why?
- ;
- ; o if you have problems using it, i'll try to help you debug it.
- ; o i'll send you improved, debugged, faster versions.
- ; o i'll tell you about future products.
- ;
- ; how much should you pay? my suggestion is:
- ; (cost of one copy of the program) * (log10 of number of copies sold)
- ; if the subroutine is an integral part of your program, double the amount.
- ; if it's a frill (e.g., you dissolve in your "About MacWhatever"), halve it.
- ;
- ; i find it hard to believe that any damages to you or anyone else could come from
- ; bugs in this routine. but, alas, whether or not you pay me, alas, i can't be
- ; liable in any way for any problems in it.
- ;
- ; send comments, contributions, criticisms, or whatever to:
- ; mike morton
- ; 6 blackwood street, #102
- ; boston, mass. 02115
- ; if you'd like to hear about what else i've produced (as of this writing, it's not a whole lot), send a
- ; self-addressed, stamped envelope to the address above.
- ;
-
- ;
- ; -- end of introduction; real stuff starts here --
- ;
-
- ;
- ; include files:
- ; tlasm/graftypes -- definitions of "bitMap" and "rect"
- ; tlasm/quickmacs -- macros for quickdraw calls (e.g., _hidecursor)
- ;
-
- .nolist
- .include tlasm/graftypes
- .include tlasm/quickmacs
- .list
-
- ;
- ; copy one bitmap to another. the bitmap must be contiguous (i.e., the bounds rect
- ; must be as wide as "rowbytes"), the bitmaps must be the same size, and the number of bytes in the
- ; bitmap must be under 64k. if any of these conditions aren't met, the routine returns WITHOUT
- ; DOING ANYTHING.
- ;
-
- .proc dissBytes
- link A6,#0 ; set up an empty stack frame (no local storage)
- movem.l D3/A2,-(A7) ; save registers for our caller
-
- move.l 8(A6),A1 ; point to destination bitmap with A1
- move.l 12(A6),A0 ; and to the source bitmap with A0
-
- ;
- ; check that the bitmaps match in size:
- ;
-
- move.w bounds+bottom(A0),D0 ; pick up source.bounds.bottom
- sub.w bounds+top(A0),D0 ; find (source.bounds.bottom-source.bounds.top)
- swap D0 ; cache that in the top half of D0
- move.w bounds+right(A0),D0 ; and find (source.bounds.right...
- sub.w bounds+left(A0),D0 ; ...-source.bounds.left)
-
- move.w bounds+bottom(A1),D1 ; pick up dest.bounds.bottom
- sub.w bounds+top(A1),D1 ; find (dest.bounds.bottom-dest.bounds.top)
- swap D1 ; cache that in the top half of D1
- move.w bounds+right(A1),D1 ; and find (dest.bounds.right...
- sub.w bounds+left(A1),D1 ; ...-dest.bounds.left)
-
- cmp.l D0,D1 ; do height and width of rectangles match?
- bne.s noBytes ; nope -- can't handle this
-
- move.w rowbytes(A0),D2 ; pick up bytes-per-row in D2
- cmp.w rowbytes(A1),D2 ; do they match?
- bne.s noBytes ; nope -- they must for us to copy
-
- move.w D2,D3 ; set byte count aside in D3
- lsl.w #3, D2 ; turn byte count into bit (pixel) count
- cmp.w D2,D0 ; compare against width of both bounds rects
- bne.s noBytes ; bounds rect must span the whole bitmap!
-
- swap D1 ; bring rect height to D1.w
- mulu D1,D3 ; multiply width in bytes times height to find bytes in the rectangle
- move.l D3,D0 ; copy that to D0 so we can...
- bsr log2 ; convert byte count per rect to ceil(log2(byte count)) in D0.w
- swap D3 ; now make sure that the number of bits fits in a word...
- tst.w D3 ; like so
- bne.s noBytes ; sorry, too large; i want to use word ops in the main loop
- swap D3 ; now put D3 back
-
- lsl.w #2,D0 ; make the table stride right [sic?] (longwords)
- lea TABLE,A2 ; point to the table of XOR masks
- move.l 0(A2,D0.w),D1 ; grab the correct magic mask in D1
-
- move.l D1,D2 ; 1st sequence element is the mask itself
-
- move.l baseAddr(A0),A0 ; pick up a pointer to the actual source stuff
- move.l baseAddr (A1),A1 ; and to the target (most likely the screen)
- _hideCurs ; don't let the cursor get in our way
- bra.s BYTELP ; jump into the loop
-
- ; register usage for the loop:
- ; D1 is the magic XOR mask to generate the sequence
- ; D2 is the current sequence element
- ; D3 is the number of bytes in the bitmap (1 more than the highest byte offset)
- ; A0 points to the source bitmap's data
- ; A1 points to the destination bitmap's data
-
- BYTESEQ
- eor.w D1,D2 ; go to the next sequence element
- BYTELP
- cmp.w D2,D3 ; is D2 within the range (1..D3-1)?
- ble.s BYTENEXT ; nope: don't copy this byte
- BYTECOPY
- move.b 0(A0,D2.w),0(A1,D2.w) ; copy D2'th byte from A0's data to A1's data
- BYTENEXT
- lsr.w #1,D2 ; slide one bit to the right
- bhi.s BYTECOPY ; if no carry out, but not zero, loop
- bne.s BYTESEQ ; if carry out, but not zero, loop earlier
-
- move.b (A0),(A1) ; copy the zero'th element, which the sequence doesn't hit
- _showCurs ; bring back the cursor (or at least undo one level of hiding)
-
- NOBYTES ; here when we can't copy
- movem.l (A7)+,D3/A2 ; pop needed registers
- unlk A6 ; delete our empty stack frame
- move.l (A7)+,A0 ; pop our return
- add.l #8,A7 ; deallocate parameters
- jmp (A0) ; and return
-
-
- ;
- ; -----------------------------------------------------------------------------------
- ;
- ; table of (longword) masks to XOR in strange Knuthian algorithm. the first table
- ; entry is for a bit-width of two, so the table actually starts two longwords before
- ; that. hardware jocks among you may recognize this scheme as the software analog
- ; of a "maximum-length sequence generator".
- ;
-
- table .equ *-8 ; first element is #2; stride is four bytes
- .long 3o ; 2
- .long 6o ; 3
- .long 14o ; 4
- .long 24o ; 5
- .long 60o ; 6
- .long 140o ; 7
- .long 270o ; 8
- .long 420o ; 9
- .long 1100o ; 10
- .long 2400o ; 11
- .long 6240o ; 12
- .long 15400o ; 13
- .long 32400o ; 14
- .long 60000o ; 15
- .long 132000o ; 16
- .long 220000o ; 17
- .long 402000o ; 18
- .long 1620000o ; 19
- .long 2200000o ; 20
- .long 5000000o ; 21
- .long 14000000o ; 22
- .long 20400000o ; 23
- .long 66000000o ; 24
- .long 110000000o ; 25
- .long 342000000o ; 26
- .long 710000000o ; 27
- .long 1100000000o ; 28
- .long 2400000000o ; 29
- .long 6240000000o ; 30
- .long 11000000000o ; 31
- .long 24300000000o ; 32
-
- ;
- ; -----------------------------------------------------------------------------------
- ;
- ; log2 -- find the ceiling of the log, base 2, of a number.
- ;
- ; calling sequence:
- ; move.l N,D0 ; store the number in D0
- ; bsr LOG2 ; call us
- ; move.w D0,... ; D0 contains the word result
- ;
- ; registers used: D2, (D0)
- ;
-
- LOG2
- tst.l D0 ; did they pass us a zero?
- beq.s LOGDONE ; call log2(0) zero -- what the heck...
- sub.l #1,D0 ; so 2**n works right (sigh)
- beq.s LOGDONE ; if D0 was one, answer is zero
- move.w #32,D2 ; initialize count
- LOG2LP
- lsl.l #1,D0 ; slide bits to the left by one
- dbcs D2,LOG2LP ; decrement and loop until a bit falls off
-
- move.w D2,D0 ; else save our value where we promised it
- LOGDONE ; here with final value in D0
- rts ; and return
-
- .end ; procedure dissBytes
-