scott@scam.Berkeley.EDU (Scott Silvey) (10/31/90)
I have just written and debugged my very first Macintosh application! It is a simple program which allows you to draw a lot of squiggly lines wherever you drag the mouse. My problem is that when the user is drawing, the lines come out a bit too squiggly. The mouse skips about erratically like it does when the wait cursor shows as the Mac is doing intensive disk I/O. When the mouse accelleration is high, this problem is the most pronounced, while it is reduced when I set the accelleration to 'graphics tablet' mode. Since I may someday wish to make a serious application which tracks the mouse smoothly, I find this behaviour rather annoying. MacPaint and other similar programs don't seem to have this trouble, so I can only assume I am going about the problem in a manner that is perhaps too brutish. My speculation is that Mac is going off on some interrupt every few seconds or so, resulting in the cursor movement being interpolated over the period of time in which the interrupt is being serviced. Now, I don't even know if the Mac even DOES such things ... I'm only guessing. Does anyone out there perhaps have an idea of what the problem is? Does anyone have code that work as it smoothly tracks the mouse? I have a Mac SE, I'm using LSC 3.0, and I am NOT using MultiFinder. Here is the code I use to do the drawing: do_line(theEvent) EventRecord *theEvent; { Point p; p = theEvent->where; GlobalToLocal(&p); MoveTo(p.h, p.v); do { LineTo(p.h, p.v); GetMouse(&p); } while (StillDown()); save_image(); } I would appreciate any help you could give me. Thanks, Scott
gurgle@well.sf.ca.us (Pete Gontier) (11/02/90)
In article <1990Oct31.100603.1989@agate.berkeley.edu> scott@xcf.berkeley.edu writes: >I have just written and debugged my very first Macintosh application! Alert the media! Another hacker conquers the learning cliff! :-) >Does anyone out there perhaps have an idea of what the problem is? Doesn't look like there is any *problem* with your routine. You've done it all by the book, which is good. > Does anyone have code that work as it smoothly tracks the mouse? Now the ugly answer. Sometimes you can't do everything by the book. :-) The following suggestions apply only to short stretches of code and only to situations in which you are fairly certain you won't be interrupted by any other code that does anything similar to what you are doing. (In this case, it sounds pretty safe.) The Trap Dispatcher is a pig. It saves registers, calculates offsets, all sorts of horrible things that take up time. Accordingly, you need to minimize your trap calls. 1) write your loops using the minimum amount of trap calls 2) think about what those traps actually do -- you might be able to do the same thing -- convenience traps like SetPt come to mind 3) cut the Trap Dispatcher out of the picture a) before entering your loop, find out the address of the code that will execute when you call your traps -- learn the use of CallPascal, which is a compiler trick, not a trap call b) make judgement calls about how to fake traps -- exercise what's called 'Toolbox Karma' Now, here's the code you wrote that I would change: > do { > LineTo(p.h, p.v); > GetMouse(&p); > } while (StillDown()); The problem here, really, is that you are calling traps which call other traps. StillDown calls Button, GetMouse calls GlobalToLocal. I might write something like this (and I emphasize the _might_ -- I know this compiles, but that's it): #define kLineToTrapWord 0xA891 #define kGlobalToLocalTrapWord 0xA871 extern Boolean CrsrBusy : 0x08CD; extern Point Mouse : 0x0830; extern Boolean MouseButtonState : 0x0172; Point mousePt; long LineToTrapAddr, GlobalToLocalTrapAddr; LineToTrapAddr = NGetTrapAddress ( kLineToTrapWord, ToolTrap ); GlobalToLocalTrapAddr = NGetTrapAddress ( kGlobalToLocalTrapWord, ToolTrap ); if ( StillDown ( ) ) while ( MouseButtonState ) { while ( CrsrBusy ) ; /* just wait */ mousePt = Mouse; CallPascal ( & mousePt, GlobalToLocalTrapAddr ); CallPascal ( Mouse.h, Mouse.v, LineToTrapAddr ); } Voila, no trap calls in the loop. If you really want it to honk, do it in assembly, and all kinds of overhead goes away. You can keep things lying around in registers and you don't have to let the compiler do fourteen things when it only needs to do one. Is this DTS-approved technique? Nope. Not a chance. Does it work? Yep. (The next question is "Does it break anybody else?" Nope. At least not until System 8.) BTW, note that the "if ( StillDown ( ) ) while" strategy needs to be employed whether you use my way or your way. You can't draw a line and then test for StillDown at the bottom of the loop, because then you might as well just call Button -- the user may already have made the mistake. Pete Gontier, gurgle@well.sf.ca.us Software Imagineer, Kiwi Software, Inc.
oster@well.sf.ca.us (David Phillip Oster) (11/02/90)
The overhead to call a few traps in a
while(StillDown()){
MoveTo();
LineTo();
}
loop is totally lost in the time it takes to actually do the drawing.
The trap dispatcher overhead simply can't matter. You get responsiveness
in a situation like this by:
draw only that part that changes.
use XOR mode drawing, so a second draw can erase it,
or, use an offscreen buffer that you CopyBits to the screen.
Even though the offscreen buffer is actually slower, its smoothness is
percieved by users as being faster. (To get flicker free, stamp your
offscreen bitmap with the image of the cursor.)
--
-- David Phillip Oster - Note new signature. Old one has gone Bye Bye.
-- oster@well.sf.ca.us = {backbone}!well!oster
smoke@well.sf.ca.us (Nicholas Jackiw) (11/03/90)
In article <21464@well.sf.ca.us> oster@well.sf.ca.us (David Phillip Oster) writes: [blah blah blah] >(To get flicker free, stamp your >offscreen bitmap with the image of the cursor.) >-- David Phillip Oster - Note new signature. Old one has gone Bye Bye. What an excellent and obvious idea! Makes me feel like a dolt, the amount of satisfaction I get out of my offscreen routines despite the fact that the cursor's quivering like a biker mad on booze and speed. Here's some cheap code to accomplish it. THINK Pascal 3.0. Note that you'll not want to call it for the final frame of an animation, or else the stamped cursor will linger permanently in that frame. procedure StampCursor; {By Nick Jackiw 11/2/90 - idea from David Phillip Oster.} {Use wantonly and rewrite as necessary. Color cursor} {support should be a trivial addition.} {StampCursor, assuming that thePort is currently set to an} {offscreen bitmap which is going to be copied to the screen,} {draws the current cursor at the current mouse location in that port.} {This helps minimize the flicker that occurs when a cursorless} {offscreen image is copied over the current screen cursor.} {This implementation assumes the presence of a few global variables:} { - GlobalCurs is the cursor most recently set with SetCursor.} { - OffWorld and OnWorld are two bitmaps describing the offscreen} { and onscreen drawing environments.} { - OffCWorld and OnCWorld are similar, but are pixmaps} { - hasCQD indicates whether to use pixmaps or bitmaps} var cursBits, maskBits: BitMap; aPt: point; begin GetMouse(aPt);{Let Quickdraw localize the mouseLoc to our offscreen port} with aPt do {then adjust it by the difference between offscreen and onscreen} if hasCQD then with OffCWorld^^.bounds do begin h := h + OnCWorld^^.bounds.left - left; v := v + OnCWorld^^.bounds.top - top end else with OffWorld.bounds do begin h := h + OnWorld.bounds.left - left; v := v + OnWorld.bounds.top - top end; with cursBits do {Generate bitmaps describing the cursor and its mask} begin {in positions relative to the localized mouse point} with bounds do with GlobalCurs.HotSpot do with thePort^ do begin top := aPt.v - (v); left := aPt.h - (h); right := left + 16; bottom := top + 16 end; rowBytes := 2; baseAddr := @GlobalCurs.data end; maskBits := cursBits; maskBits.baseAddr := @GlobalCurs.mask; with cursBits do {image and clip it appropriately to the present port} CopyMask(cursBits, maskBits, thePort^.portBits, bounds, bounds, bounds) end; -- --- * --- Nicholas Jackiw Smoke@well.sf.ca.us | Jackiw@cs.swarthmore.edu Key Curriculum Press, Inc. Applelink: D3970 | (415) 548-2304 --- * ---