[comp.sys.next] How do you draw lines into the current view for Rubberbanding

leivian@axon.sps.mot.com (Bob Leivian) (05/17/91)

first of all thanks to all who helped with by previous requests,
 I now have a pretty compilcated application ported to NeXTStep
and know alot more about NeXT and OBJ C but... (he's back...)

I would like to draw lines into the current view in XOR mode to do 
rubberbanding,  I can't find anything on this except composite, which
has an XOR mode but do I need to have two full window rectangles and 
clear one and draw into it and then composite them?  
I would like to do something like this

mouseMoved: e
{
   ...

   PSmoveto(old.x, old.y);
   PS..setXORmode... ();  /* where is this */
   PSlineto(anchor.x, anchor.y);
   PSlineto(e->location.x, e->location.y);
   old = e->location;
   ...

}


also bonus question for extra brownie points...

In IB I created a .nib that has a controlPanel (subclass of panel)
that has the buttons and sliders set up  to control an instance of
an object that is dynamically created by the program. However when I
'new' the panel (with a loadNibSection in the +new method) I still
just get an empty panel, no buttons or sliders, even though the loadNib
comes back without an error -- any hints of where to look

thanks for any help -- Bob
-- 
Bob Leivian				leivian@email.pcrl.sps.mot.com
Neural Network Development Group	(602) 897-5117
2100 E. Elliot MD508			Tempe, AZ 85284

Peter_King@NeXT.COM (Peter King) (05/18/91)

In article <1004@nddsun1.sps.mot.com> leivian@axon.sps.mot.com (Bob Leivian)  
writes:
>
> ...
>
> I would like to draw lines into the current view in XOR mode to do 
> rubberbanding,  I can't find anything on this except composite, which
> has an XOR mode but do I need to have two full window rectangles and 
> clear one and draw into it and then composite them?  
> I would like to do something like this
> 

Check out instance drawing.  Here's a little snippet of code that does  
temporary line drawing in response to a mouse-down method.

-mouseDown:(NXEvent *)theEvent
{
	int	looping;		/* Flag for while in modal loop */
	int	oldMask;		/* Old event mask */
	NXPoint	startPoint;		/* Location of mouseDown */
	NXPoint	currentPoint;		/* Location of mouseDragged/mouseUp */

	/* Allow mouseDragged events */
	oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];

	/* Get the location of the mouseDown in view coordinates */
	startPoint = theEvent->location;
	[self convertPoint:&startPoint fromView:nil];

	/* Initialize the drawing context */
	[self lockFocus];
	PSsetgray(0.0);

	/* Turn on instance drawing */
	PSsetinstance (YES);

	/* Run modal loop until mouse up */
	looping = YES;
	while (looping) {

		/* Get the next mouseDragged/mouseUp event */
		theEvent=[NXApp
			  getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];


		/* Convert location to view coordinates */
		currentPoint = theEvent->location;
		[self convertPoint:&currentPoint fromView:nil];

		/* Erase all previous instance drawing */
		PSnewinstance();
		
		/* Handle the event */
		if (theEvent->type==NX_MOUSEDRAGGED) {
			/*
			 * On mouseDragged, instance draw a line
			 * from starting point to current point.
			 */
			PSmoveto(startPoint.x, startPoint.y);
			PSlineto(currentPoint.x, currentPoint.y);
			PSstroke();
		}
		else {
			/*
			 * On mouse up, we stop the modal loop and draw
			 * a real line from starting point to current
			 * point.
			 */
			looping = NO;
			PSsetinstance(NO);	/* Turn off instance drawing */
			PSmoveto(startPoint.x, startPoint.y);
			PSlineto(currentPoint.x, currentPoint.y);
			PSstroke();
			
			/*
			 * Since we're not called from display, flush the
			 * window buffer.
			 */
			[window flushWindow];
		}
	}

	/* Release the drawing context and restore the event mask */
	[self unlockFocus];
	[window setEventMask:oldMask];
	
	return self;
}

This causes a little bit of flicker (acceptable when rubber-banding).  If you  
want to avoid the flicker, then you'd need to do double-buffering with  
off-screen windows and compositing.  I'll leave this as an exercise for the  
reader.

> In IB I created a .nib that has a controlPanel (subclass of panel)
> that has the buttons and sliders set up  to control an instance of
> an object that is dynamically created by the program. However when I
> 'new' the panel (with a loadNibSection in the +new method) I still
> just get an empty panel, no buttons or sliders, even though the loadNib
> comes back without an error -- any hints of where to look
> 

You never need to "new" the panel;  loadNibSection:owner: will instantiate it  
for you.

What you want to do is add an outlet to your "custom object that is  
instantiated programmatically" which points to the control panel.  In the nib  
file, set the File's Owner object to be the same class as your custom object,  
and drag a connection from the outlet you just created to your panel.

When instantiating -->your custom object<--, call loadNibSection:owner: and  
pass in the id of the new custom object as the argument to owner:.  When  
loadNibSection:owner: returns, the outlet in the custom object will have been  
initialized to point to the new panel (with buttons and all).

Peter


----------Disclaimers?  No such thing.  Everything's the truth----------
Peter F. King	Developer Trainer	NeXT Computer, Inc.
USPS:		900 Chesapeake Dr.	Redwood City, CA  94063
Internet:	Peter_King@NeXT.COM

glenn@heaven.woodside.ca.us (Glenn Reid) (05/19/91)

Peter King writes

> Check out instance drawing.  Here's a little snippet of code that does  
> temporary line drawing in response to a mouse-down method.

[ code omitted ]

> This causes a little bit of flicker (acceptable when rubber-banding).  If you  
> want to avoid the flicker, then you'd need to do double-buffering with  
> off-screen windows and compositing.  I'll leave this as an exercise for the  
> reader.

I'm curious; why isn't instance drawing implemented to avoid flickering in
the manner you suggest?  It seems that this would be a better
implementation, and just as easy, unless I'm missing something.

--
 Glenn Reid				RightBrain Software
 glenn@heaven.woodside.ca.us		NeXT/PostScript developers
 ..{adobe,next}!heaven!glenn		415-326-2974 (NeXTfax 326-2977)

duggie@pengyou (Doug Felt) (05/20/91)

In article <507@heaven.woodside.ca.us> glenn@heaven.woodside.ca.us (Glenn Reid)  
writes:
> Peter King writes
> 
> > Check out instance drawing.  Here's a little snippet of code that does  
> > temporary line drawing in response to a mouse-down method.
> 
> [ code omitted ]
> 
> > This causes a little bit of flicker (acceptable when rubber-banding).  If  
you  
> > want to avoid the flicker, then you'd need to do double-buffering with  
> > off-screen windows and compositing.  I'll leave this as an exercise for the  
> > reader.
> 
> I'm curious; why isn't instance drawing implemented to avoid flickering in
> the manner you suggest?  It seems that this would be a better
> implementation, and just as easy, unless I'm missing something.
> 
> --
>  Glenn Reid				RightBrain Software
>  glenn@heaven.woodside.ca.us		NeXT/PostScript developers
>  ..{adobe,next}!heaven!glenn		415-326-2974 (NeXTfax 326-2977)

I'm curious too, but the answer is probably buried in the depths of history.   
One day at an 'informal developer camp' back the summer before the NeXT was  
announced I remember talking to someone from Adobe about this, and he said that  
was how the specs were defined, and implied that the people from NeXT had  
something to do with it.  I never followed up.

In my opinion flicker is never acceptable, not even for rubberbanding, if you  
want a professional-looking product.  Offscreen buffering is the way to go,  
although unfortunately this is high overhead when you are selecting large areas  
of the screen.

Doug Felt

jmartin@trouble2 (Jeff Martin) (05/23/91)

In article <507@heaven.woodside.ca.us> glenn@heaven.woodside.ca.us (Glenn Reid)  
writes:
> Peter King writes
> 
> > Check out instance drawing.  Here's a little snippet of code that does  
> > temporary line drawing in response to a mouse-down method.
> 
> [ code omitted ]
> 
> > This causes a little bit of flicker (acceptable when rubber-banding).  If  
you  
> > want to avoid the flicker, then you'd need to do double-buffering with  
> > off-screen windows and compositing.  I'll leave this as an exercise for the  
> > reader.
> 
> I'm curious; why isn't instance drawing implemented to avoid flickering in
> the manner you suggest?  It seems that this would be a better
> implementation, and just as easy, unless I'm missing something.

     The answer is memory consumption and compositing overhead. Every window  
would have to have two buffers, one that holds the real image (secondary) and  
one that holds that image with some type of overlay (primary) (imagine how much  
more memory the system would need!). Then at each step you would have to update  
the primary buffer from the secondary buffer, draw the overlaying graphics,  
then flush the primary buffer to the screen.

     Flickering is the trade-off for saving memory and time. Instance drawing  
should be used sparingly - and just for wireframes and such in response to user  
actions with the mouse.

     Memory is the highest commodity on the NeXT. Instance drawing is a good  
solution for many apps.

Peter_King@NeXT.COM (Peter King) (05/29/91)

In article <507@heaven.woodside.ca.us> glenn@heaven.woodside.ca.us (Glenn Reid)  
writes:
> 
> I'm curious; why isn't instance drawing implemented to avoid flickering in
> the manner you suggest?  It seems that this would be a better
> implementation, and just as easy, unless I'm missing something.
> 

I wasn't there when the instance drawing mechanism was designed, but I suppose  
it is a classic "aesthetics vs. performance" tradeoff.  An example of this kind  
of tradeoff is the different styles of window buffering available  
(Buffered/Retained/NonRetained).  You can get a cleaner, snappier look if you  
are willing to pay in virtual memory for the buffered window.  In a  
demand-paged system such as NeXT's, using more virtual memory effects the  
performance of the overall system.

When you do double-buffered compositing for dynamic drawing, you need to  
allocate an off-screen window to hold the on-screen window's current state.   
Let's look at a worst-case scenario: we are writing a Draw like program that  
works in color on the NeXTdimension.  An 8.5 by 11 page will take 

        612 pixels * 792 pixels * 4 bytes per pixel = 1938816 bytes

Almost 2MB for the off-screen window.  This will undoubtably cause paging to  
happen.  If you have limited physical memory, this may not perform as fast as  
needed.

Instance drawing gives you the option of using the window's backing store to  
erase from so you can avoid burning memory for the off-screen window.  The  
tradeoff is that you get flicker.

As with a lot of performance critical areas in NeXTstep application design,  
NeXT has provided the developer with a set of alternatives.  Only the developer  
knows which alternative is appropriate for his or her application.  If the  
flicker is unacceptable, use double-buffering.

Peter


----------Disclaimers?  Always.  Everything's Subjective----------
Peter F. King	Developer Trainer	NeXT Computer, Inc.
USPS:		900 Chesapeake Dr.	Redwood City, CA  94063
Internet:	Peter_King@NeXT.COM

dmg@ssc-vax (David M Geary) (05/31/91)

Peter King writes:
] In article <507@heaven.woodside.ca.us> glenn@heaven.woodside.ca.us (Glenn Reid)  
] writes:
]]  
]]  I'm curious; why isn't instance drawing implemented to avoid flickering in
]]  the manner you suggest?  It seems that this would be a better
]]  implementation, and just as easy, unless I'm missing something.
]]  

] You can get a cleaner, snappier look if you  
] are willing to pay in virtual memory for the buffered window.  In a  
] demand-paged system such as NeXT's, using more virtual memory effects the  
] performance of the overall system.

] When you do double-buffered compositing for dynamic drawing, you need to  
] allocate an off-screen window to hold the on-screen window's current state.   
] Let's look at a worst-case scenario: we are writing a Draw like program that  
] works in color on the NeXTdimension.  An 8.5 by 11 page will take 

]         612 pixels * 792 pixels * 4 bytes per pixel = 1938816 bytes

] Almost 2MB for the off-screen window.  This will undoubtably cause paging to  
] happen.  If you have limited physical memory, this may not perform as fast as ] needed.   ...

  Excuse me for jumping in on this thread because I do not own or even work on 
a NeXT, but having designed my own GUI from the ground up at work, and having
implemented rubber banding ...

  If all you want to do is rubber-banding without the flicker, why allocate an
off-screen buffer for the *entire* window?  Instead, why not allocate 4 buffers,each of which is one pixel wide by screen width (or height) long:

1 pixel * 792 pixels * 4 bytes per pixel = 3168 bytes

3168 bytes * 4 (one for each line in rubber band rectangle) = 12672

  This results in only 12K of ram vs. 2M.  This seems quite reasonable to me.
After all, it is not necessary to continually save and restore what the rubber
banding rectangle *encloses*, just the portion of the screen that the rubber
banding rectangle's lines are going to be drawn over.  I have used
this exact technique on a slow dinasour of a workstation (a Sun
3/60) and I have no flicker at all.

  Sorry if I'm way off base (see above disclaimer)...



-- 
|-----------------------------------------------------------------
|           David Geary, Boeing Aerospace, Seattle, WA.          |
|                                                                |
| Seattle - America's most attractive city... to the *jetstream* |

blanford@spf.trw.com (Ronald P. Blanford) (05/31/91)

In article <4043@ssc-bee.ssc-vax.UUCP> dmg@ssc-vax (David M Geary) writes:
>   If all you want to do is rubber-banding without the flicker, 
> why allocate an off-screen buffer for the *entire* window?  
> Instead, why not allocate 4 buffers,each of which is one pixel 
> wide by screen width (or height) long:

I didn't want to jump in earlier since I didn't do the work and am not
familiar with the code, but one of our applications implements a Rubberband
class using just this technique.  Besides reducing flicker, it improved
performance by an order of magnitude.

Peter_King@NeXT.COM (Peter King) (06/01/91)

In article <4043@ssc-bee.ssc-vax.UUCP> dmg@ssc-vax (David M Geary) writes:
> 
>   If all you want to do is rubber-banding without the flicker, why allocate  
an
> off-screen buffer for the *entire* window?  Instead, why not allocate 4  
buffers,each of which is one pixel wide by screen width (or height) long:
> 

This is really an extension of the double-buffered compositing I was talking  
about earlier, but you're being much smarter about choosing which background  
pixels to retain.  Would you call this quadruple buffering??? :-)

The mechanism I suggested (buffering the whole window) works well when the  
dynamic drawing you're doing isn't a simple rubber-band.  For example, you  
might be doing a draw program and you want to drag out a filled rectangle.   
This could potentially cover the whole window.

But, as you say, if you are doing a simple rubber-band, four one-pixel-wide  
buffers work really well.

Peter


--
----------Disclaimers?  Always.  Everything's Subjective----------
Peter F. King	Developer Trainer	NeXT Computer, Inc.
USPS:		900 Chesapeake Dr.	Redwood City, CA  94063
Internet:	Peter_King@NeXT.COM

scott@mcs-server.gac.edu (Scott Hess) (06/04/91)

In article <4043@ssc-bee.ssc-vax.UUCP> dmg@ssc-vax (David M Geary) writes:
   ] When you do double-buffered compositing for dynamic drawing, you need to  
   ] allocate an off-screen window to hold the on-screen window's current
   ] state.  Let's look at a worst-case scenario: we are writing a Draw
   ] like program that works in color on the NeXTdimension.  An 8.5 by 11
   ] page will take
   ]	612 pixels * 792 pixels * 4 bytes per pixel = 1938816 bytes
   ] Almost 2MB for the off-screen window.  This will undoubtably
   ] cause paging to happen.  If you have limited physical memory,
   ] this may not perform as fast as needed.   ...

     Excuse me for jumping in on this thread because I do not own or even
   work on a NeXT, but having designed my own GUI from the ground up at
   work, and having implemented rubber banding ...

     If all you want to do is rubber-banding without the flicker, why
   allocate an off-screen buffer for the *entire* window?  Instead,
   why not allocate 4 buffers,each of which is one pixel wide by
   screen width (or height) long:

   1 pixel * 792 pixels * 4 bytes per pixel = 3168 bytes

   3168 bytes * 4 (one for each line in rubber band rectangle) = 12672

     This results in only 12K of ram vs. 2M.  This seems quite reasonable
   to me.  After all, it is not necessary to continually save and restore
   what the rubber banding rectangle *encloses*, just the portion of the
   screen that the rubber banding rectangle's lines are going to be drawn
   over.  I have used this exact technique on a slow dinasour of a
   workstation (a Sun 3/60) and I have no flicker at all.

The best way to implement the above on a NeXT is to use 4 actual
_windows_ that overlay the selection.  This is what's used in
the AppKit for the Window resizing rubber-banding, and a similar
technique is used in InterfaceBuilder to draw the connections that
go between windows.

Basically, you have 4 narrow windows, 2 horizontal, 2 vertical.  Then,
you move them around as needed.  This is relatively flicker-free
(well, you can't get much less, as anything you do will, in the
end, depend on Display Postscript, and this should be about as good
as it gets for rubber-banding.)  To get an inkling of the method
to use, look in /usr/lib/NextStep/windowPackage.ps - therein
resides code that's loaded into the server that can be used to
check out system-wide windows for such a use.  If you can wait,
I've been working on a modified Window class which uses this for
its resizing, so hopefully there will be a real example out there
at some time in the future.

Note that this is probably not a NeXT-supported method of rubber-
banding (ie, using the code in the windowPackage).  But, the
technique should work fine, regardless.

Lastly, a point for Mr King - the instance drawing he is speaking
of is generalized - it's not limited to rubber-banding.  You can
draw arbitrary postscript as the instance drawing, and then have
it go away when you tell it to.  That's nice for some things -
unfortunately, you do lose either WRT the look of the drawing
(flicker), or memory.  Fortunately, many rubber-band effects are
rectilinear, so that can be worked around in some special cases . . .

Later,
--
scott hess                      scott@gac.edu
Independent NeXT Developer	Graduated GAC Undergrad!
<I still speak for nobody>
Note:  I have moved home for a time.  My email address will still be
valid.  Any SnailMail should be redirected, along with phone calls.
At the least, my parents can tell you how to get hold of me, or
forward any mail . . .
Old:	PO 829, GAC, St. Peter, MN  56082	(507) 933-8466
New:	RR#4 Box 227 Pipestone, MN  56164	(507) 825-2788