This is DirtPile.m in view mode; [Download] [Up]
// This object tracks the dirty rectangle of the frame buffer.
// If two rects overlap, they are coalesced. If they don't
// overlap, they are kept separate. This way, when a redraw
// is done, we have two flushes that are small rather than one
// large flush. (The large flush would draw *lots* of unnecessary
// pixels!)
#import <gamekit/gamekit.h>
#import <appkit/appkit.h>
#import <dpsclient/dpsNeXT.h>
#import <stdio.h>
// function to coalesce two rectangles if they overlap.
// Returns NO if they don't, returns YES if they do and
// leaves the union rect in *r1. I suppose that I could
// have used NXIntersectsRect() and NXUnionRect(), but
// this is just as easy.
BOOL coalesce(NXRect *r1, NXRect *r2)
{
NXRect r3;
// see if the two rects intersect. If they don't, return NO.
if (((NX_X(r1) + NX_WIDTH(r1)) < NX_X(r2)) ||
((NX_X(r2) + NX_WIDTH(r2)) < NX_X(r1)) ||
((NX_Y(r1) + NX_HEIGHT(r1)) < NX_Y(r2)) ||
((NX_Y(r2) + NX_HEIGHT(r2)) < NX_Y(r1))) return NO;
// take the union of the rects; the new, larger rect is in r3
NX_X(&r3) = MIN(NX_X(r1), NX_X(r2));
NX_Y(&r3) = MIN(NX_Y(r1), NX_Y(r2));
NX_WIDTH(&r3) = MAX(NX_X(r1) + NX_WIDTH(r1),
NX_X(r2) + NX_WIDTH(r2)) - NX_X(&r3);
NX_HEIGHT(&r3) = MAX(NX_Y(r1) + NX_HEIGHT(r1),
NX_Y(r2) + NX_HEIGHT(r2)) - NX_Y(&r3);
*r1 = r3;
return YES; // tell them we coalesced it.
}
@implementation DirtPile
- init // initialize the instance
{
[super init];
// reset instance variables.
maxRects = MAX_RECTS;
numRects = 0;
return self;
}
- addRegion:(float)x :(float)y :(float)w :(float)h // add a dirty rect
{
register NXRect *r;
// make sure we have enough room. Complain if we don't. (Shouldn't
// ever get the printf(), though! )
if (numRects >= maxRects) {
fprintf(stderr, "Need more rects allocated in DirtPile!\n");
return self;
}
// copy coords into the rect list
r = &rectList[numRects];
NX_X(r) = x; NX_Y(r) = y;
NX_WIDTH(r) = w; NX_HEIGHT(r) = h;
// update number of rects in list
numRects++;
return self;
}
- addRegion:(NXRect *)rect // add a dirty rect
{
return [self addRegion:NX_X(rect) :NX_Y(rect)
:NX_WIDTH(rect) :NX_HEIGHT(rect)];
}
- fullRedraw:sender :buffer // assumed to be a view
{
NXRect bounds = {{0.0, 0.0}, {0.0, 0.0}};
[sender getBounds:&bounds];
[buffer composite:NX_COPY fromRect:&bounds
toPoint:&(bounds.origin)];
numRects = 0;
return self;
}
// Flush dirty parts of the buffer to the currently focused view.
// The view should be in a retained window for this to actually
// work as it is supposed to do.
- doRedraw:buffer
{
register NXRect *r1, *r2;
register int i, j;
BOOL changed;
// Leave if nothing to flush. This isn't really necessary, since if
// this object is properly used, there will be some dirt when this
// method gets called.
if (!numRects) return self;
r1 = &rectList[0]; // not necessary, but silences an irrelevant
// compiler warning. You could remove it, though, if it bothers you.
// first, coaselse all redraw regions.
do {
changed = NO;
for (i=0; i<(numRects-1); i++) {
r1 = &rectList[i];
for (j=i+1; j<numRects; j++) {
r2 = &rectList[j];
if (coalesce(r1, r2)) {
changed = YES;
numRects--;
for (; j<numRects; j++) {
*r2 = *(r2+1);
r2++;
}
}
}
}
} while (changed);
// flush dirty rects from buffer onto the screen
for (i=0; i<numRects; i++) {
[buffer composite:NX_COPY fromRect:&rectList[i]
toPoint:&rectList[i].origin];
// if using a buffered window instead of retained, you
// need to flush the window here.
}
// reset dirty list, since it's all clean now
numRects = 0;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.