[comp.sys.amiga.programmer] Implementing moving crosshair...

baker@wbc.enet.dec.com (03/22/91)

-Message-Text-Follows-

	Given an Intuition window, I want a pair of lines -- one running
	from the top to the bottom of the window, the other running from
	the left edge to the right edge.  The intersection point of the
	lines should track the mouse.

	I'm concerned about keeping up with all the MOUSEMOVE's, so I'm
	looking for the most efficient way to implement the cross-hair 
	lines themselves.  I can use either a Bob for each line, or I can
	Draw the lines in COMPLEMENT and move them myself.  Is the use of
	a Bob going to make any real difference ?

	Also, I'd be interested in any suggestions that would speed up
	tracking on rubber-band lines and stretchable bounding-boxes.

	Thanks much.
	 Art Baker

markv@kuhub.cc.ukans.edu (03/23/91)

In article <1991Mar22.151348.23800@decuac.dec.com>, baker@wbc.enet.dec.com writes:
> -Message-Text-Follows-
> 
> 	Given an Intuition window, I want a pair of lines -- one running
> 	from the top to the bottom of the window, the other running from
> 	the left edge to the right edge.  The intersection point of the
> 	lines should track the mouse.
> 
> 	I'm concerned about keeping up with all the MOUSEMOVE's, so I'm
> 	looking for the most efficient way to implement the cross-hair 
> 	lines themselves.  I can use either a Bob for each line, or I can
> 	Draw the lines in COMPLEMENT and move them myself.  Is the use of
> 	a Bob going to make any real difference ?

I think for this a BOB would be harder and slower.  I would draw the
lines in COMPLEMENT (using COMPLEMENT again to remove them of course),
and special case the code to only redraw the cross-hairs if they've
moved and only 3-5 times a sec (the user wont need any more often, but
MOUSEMOVE can spew a lot faster).  I do something similar for another
program.  I've also seem some machines have a fair bit of "jitter" in
the mouse values (it seems to be related to the physical values in the
mouse XY registers being a bit touchcy), so I also use a running
average of the last few (4) values.  Four was picked because I can
keep the running average with integer arithmatic:

	NewAvg = ((OldAvg * 3) + NewVal) >> 2;

or for the speed obsessed:

	NewAvg = ((OldAvg << 1) + OldAvg + NewVal) >> 2;

> 	Also, I'd be interested in any suggestions that would speed up
> 	tracking on rubber-band lines and stretchable bounding-boxes.

Same rules, keep down the number of draws.  Also, pick the color with
complement mode so that you only have to flip bits in one-bitplane.
(JAM1, Color 0 or 1 works well).
 
> 	Thanks much.
> 	 Art Baker
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mark Gooderum			Only...		\    Good Cheer !!!
Academic Computing Services	       ///	  \___________________________
University of Kansas		     ///  /|         __    _
Bix:	  mgooderum	      \\\  ///  /__| |\/| | | _   /_\  makes it
Bitnet:   MARKV@UKANVAX		\/\/  /    | |  | | |__| /   \ possible...
Internet: markv@kuhub.cc.ukans.edu
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

espie@egret.Stanford.EDU (Marc Espie) (03/23/91)

In article <1991Mar22.122651.29232@kuhub.cc.ukans.edu> markv@kuhub.cc.ukans.edu writes:
>In article <1991Mar22.151348.23800@decuac.dec.com>, baker@wbc.enet.dec.com writes:
>> -Message-Text-Follows-
>> 
>> 	Given an Intuition window, I want a pair of lines -- one running
>> 	from the top to the bottom of the window, the other running from
>> 	the left edge to the right edge.  The intersection point of the
>> 	lines should track the mouse.
>> 
>> 	I'm concerned about keeping up with all the MOUSEMOVE's, so I'm
>> 	looking for the most efficient way to implement the cross-hair 
>> 	lines themselves.  I can use either a Bob for each line, or I can
>> 	Draw the lines in COMPLEMENT and move them myself.  Is the use of
>> 	a Bob going to make any real difference ?
>
>I think for this a BOB would be harder and slower.  I would draw the
>lines in COMPLEMENT (using COMPLEMENT again to remove them of course),
>and special case the code to only redraw the cross-hairs if they've
>moved and only 3-5 times a sec (the user wont need any more often, but
>MOUSEMOVE can spew a lot faster).  
---------- this is the interesting point.
[some more interesting comments deleted]
> 
>> 	Thanks much.
>> 	 Art Baker
>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>Mark Gooderum			Only...		\    Good Cheer !!!
>Academic Computing Services	       ///	  \___________________________
>University of Kansas		     ///  /|         __    _
>Bix:	  mgooderum	      \\\  ///  /__| |\/| | | _   /_\  makes it
>Bitnet:   MARKV@UKANVAX		\/\/  /    | |  | | |__| /   \ possible...
>Internet: markv@kuhub.cc.ukans.edu
>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of using MOUSEMOVE, in many cases, you can just ask for
INTUITICKS. IntuiMessages have the current position of the mouse
stamped in MouseX/MouseY. For many applications (rubber band boxes for
instance), that is largely sufficient, and it does reduce the traffic
to less than ten messages par seconds. Also, an INTUITICKS message gets posted
only if you haven't used the previous one. This means that whatever
you do, you can always keep up with whatever Intuition sends you.
That's already less messages than MOUSEMOVE, and the MouseX/MouseY fields are
completely reliable. If you're using COMPLEMENT mode, 
you still have to trim down the number of messages (check the time signature)
or else the rubber-band frame will flicker. Personnally, I obtain best
results with a rate of 2 or 3 redraws per second for a rubber band. I
wouldn't know for a cross-hair.
You can also mask off some bitplanes in your drawing area. After all, you
only need one bitplane to be able to see the moving frame. 
This is a very effective optimization.
I haven't checked if the line drawing routines recognize horizontal/vertical
lines. If they don't DrawRectangle() might be faster :-)

You should have no problem drawing a nice crosshair using that.
I used the same technic to draw a SOLID rubber box.
--
    Marc (espie@flamingo.stanford.edu)
no .sig today.

Dickson@system-m.phx.bull.com (Paul Dickson) (03/23/91)

>         NewAvg = ((OldAvg * 3) + NewVal) >> 2;

Is it me, or does OldAvg really never converge to NewVal.  It appears
that it could be off by as much as three.

jsmoller@jsmami.UUCP (Jesper Steen Moller) (03/25/91)

In article <1991Mar22.122651.29232@kuhub.cc.ukans.edu>, markv@kuhub.cc.ukans.edu writes:

> In article <1991Mar22.151348.23800@decuac.dec.com>, baker@wbc.enet.dec.com writes:
> > -Message-Text-Follows-
> > 
> > 	Given an Intuition window, I want a pair of lines -- one running
> > 	from the top to the bottom of the window, the other running from
> > 	the left edge to the right edge.  The intersection point of the
> > 	lines should track the mouse.
> > 
> > 	I'm concerned about keeping up with all the MOUSEMOVE's, so I'm
> > 	looking for the most efficient way to implement the cross-hair 
> > 	lines themselves.  I can use either a Bob for each line, or I can
> > 	Draw the lines in COMPLEMENT and move them myself.  Is the use of
> > 	a Bob going to make any real difference ?
> 
> I think for this a BOB would be harder and slower.  I would draw the
> lines in COMPLEMENT (using COMPLEMENT again to remove them of course),
> and special case the code to only redraw the cross-hairs if they've
> moved and only 3-5 times a sec (the user wont need any more often, but
> MOUSEMOVE can spew a lot faster).

If you check for the values, this doesn't mean all that much.

> I do something similar for another program.  I've also seem some machines
> have a fair bit of "jitter" in the mouse values (it seems to be related
> to the physical values in the mouse XY registers being a bit touchcy),
> so I also use a running average of the last few (4) values.  Four was
> picked because I can keep the running average with integer arithmatic:

Why? Isn't it better to tell the user to clean his/her mouse instead.
Intuitions mouse position _is_ the correct one, and I never use
anything else. I have used the cross-hairs many times, and if you check
for changes in coordinates for every MOUSEMOVE, your're ok. Do check
for changes in x and y independently, though. If you inverse the cross-
hairs, you can easily move one of the lines and leave the other one alone.

> 	NewAvg = ((OldAvg * 3) + NewVal) >> 2;
> 
> or for the speed obsessed:
> 
> 	NewAvg = ((OldAvg << 1) + OldAvg + NewVal) >> 2;

I did some research on that when I wrote some 3D routines in assembler
back in 1988. If only doubling, add is better than lsl (or asl for
signed numbers), at least it was on word-sized ints (shorts). So the
optimum would be:

NewAvg = (OldAvg + OldAvg + OldAvg + NewVal) >> 2;

> > 	Also, I'd be interested in any suggestions that would speed up
> > 	tracking on rubber-band lines and stretchable bounding-boxes.

Hmm, experiment with using RectFill for horizontal lines, and Draw for
vertical. If my assumptions are correct, it should be a bit quicker
than using Draw always.
 
> Same rules, keep down the number of draws.  Also, pick the color with
> complement mode so that you only have to flip bits in one-bitplane.
> (JAM1, Color 0 or 1 works well).
  ^^^^^^ What?
COMPLEMENT is the one to use (as you say yourself).

BTW, due to a bug in graphics, FillRect with COMPLEMENT actually inverts
ALL bitplanes (not just the ones in APen). Watch out if you use FillRect().
A workaround (a little dirty...) is to tamper with the rastport's
rp_Mask field. Set this to 1<<DesiredBitPlane, and FillRect, then restore
it to the old value (might need a pair of Forbid()/Permit()). I used that
in my program, and I'm pretty confident that it won't break any Kickstart.


Another optimization:

If you program is using a lot of DMA bandwidth (e.g. 16 colour HIRES),
you gain a lot if you check for any newer MOUSEMOVEs before you draw.

In other words: Each time you get MOUSEMOVEs, update some internal variables.
Just before you reach your Wait (or WaitPort), update these.
As any messages you read in the

while(!0) {

    (void)WaitPort(window->UserPort);

    while(msg=GetMsg(window->UserPort) {

        /* any messages handled here are queued from Intuition */

        if(msg->Class==MOUSEMOVE) UpdateInternalCoords();

        }

    /* Here, Intuition has no more messages for you, so you're not busy! */

    UpdateCrossHairs();
    }

I have used this with luck. The only problem that comes to mind is that
some mouse coordinates are "lost". This doesn't mean a thing if you
want to move a window or to pick a coordinate or mark a brush. But if
you draw lines or pixels, it's rather annoying. Check out DPaint, for
instance. Choose heavy DMA, and choose "Draw" (upper right-hand icon),
and watch! That's why PhotonPaint has a "FollowMouse" switch.
"FollowMouse" corresponds to redrawing once each MOUSEMOVE, the opposite
to the method shown above.

I'm sorry this got so long, but implementing cross-hairs obviously isn't
a piece of cake. Nothing is these days.

> > 	Thanks much.
> > 	 Art Baker

> Mark Gooderum

Thanks, I hope my advice is worth that.

Jesper Steen Moeller, Denmark

--                     __
Jesper Steen Moller   ///  VOICE: +45 31 62 46 45
Maglemosevej 52  __  ///  USENET: cbmehq!cbmdeo!jsmoller
DK-2920 Charl    \\\///  FIDONET: 2:231/84.45
Denmark           \XX/