This is Space2View.m in view mode; [Download] [Up]
// SpaceView.m
//
// This class implements the flying starfield screen saver view.
//
// Another variation on the space theme, slightly faster and different.
#import "Space2View.h"
#import <dpsclient/wraps.h>
#import <appkit/NXImage.h>
#import <objc/zone.h>
#import <mach/mach.h>
#import <c.h>
#import <libc.h>
#import <math.h>
#define PI (3.141592653589)
NXSize sizeArray[] = {{1,1},{2,1},{2,2},{3,2},{3,3},{4,3},{4,4}};
@implementation Space2View
extern float randBetween(float a, float b);
//takes theta and distance and stuffs it into x &y for *p
- convertToXY:(STAR *)p
{
p->draw.origin.x = floor(bounds.size.width / 2 + (p->distance * cos(p-> theta)));
p->draw.origin.y = floor(bounds.size.height / 2 + (p->distance * sin(p-> theta)));
return self;
}
- oneStep
{
int i, count, starsInArray = 0;
STAR *p;
if (nstars < NSTARS) [self addStar];
for (i=0; i<nstars; i++)
{
p = &stars[i];
p->distance += p->delta;
p->delta *= p->ddelta;
p->theta += 0.012;
if (p->theta > (2*PI)) p->theta -= (2*PI);
[self convertToXY:p];
// only draw the star if it moved > 1 pixel
if (p->draw.origin.x != p->erase.origin.x ||
p->draw.origin.y != p->erase.origin.y)
{
// add star to the erasure array
b[starsInArray] = p->erase;
if (p->distance > p->changepoint[p->changemode])
{
(p->changemode)++;
p->draw.size = sizeArray[p->changemode];
}
// clipping is off, so we must not draw outside view.
// replace stars that go too far...
if (p->draw.origin.x < 0 ||
p->draw.origin.y < 0 ||
p->draw.origin.x + 4 > bounds.size.width ||
p->draw.origin.y + 4 > bounds.size.height)
{
[self replaceStarAt:i];
}
w[starsInArray++] = p->draw;
p->erase = p->draw;
}
}
if (starsInArray)
{
count = 0;
while (count < starsInArray)
{
// You get the best performance if you put out all the stars
// at once. This causes noticable flicker, so I put out
// 100 of the stars per iteration. This gives reasonable speed
// and flicker is hardly noticable. Besides, stars
// _should_ flicker a little...
int t = (starsInArray - count);
i = (t < STARSPERIT)?t:STARSPERIT;
PSsetgray(NX_BLACK);
NXRectFillList(&b[count],i);
PSsetgray(NX_WHITE);
NXRectFillList(&w[count],i);
count += STARSPERIT;
}
}
return self;
}
- initFrame:(const NXRect *)frameRect
{
[super initFrame:frameRect];
[self allocateGState]; // For faster lock/unlockFocus
[self setClipping:NO]; // even faster...
[self setRadius];
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
// this drawself doesn't really draw the view at all.
// in fact it just promotes the window to screen depth...
NXRect t = {0,0,1,1};
PSsetrgbcolor(1,0,0);
NXRectFill(&t); //yucky trick for window depth promotion!
PSsetgray(NX_BLACK); NXRectFill(&t);
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
if (bounds.size.width == width && bounds.size.height == height) return self;
[super sizeTo:width :height];
[self setRadius];
nstars = 0;
return self;
}
// only call addStar if there is room in the stars array!
- addStar
{
[self replaceStarAt:nstars++];
return self;
}
- replaceStarAt:(int)index
{
float dist, t;
int tries = 0;
STAR *p = &stars[index];
BOOL inBounds;
do {
p->theta = randBetween(0,(2*PI));
if (tries++ < 3) p->distance = randBetween(1, radius);
else p->distance = randBetween(1, p->distance);
inBounds = YES;
[self convertToXY:p];
if (p->draw.origin.x < 0 || p->draw.origin.y < 0 ||
p->draw.origin.x + 4 > bounds.size.width ||
p->draw.origin.y + 4 > bounds.size.height)
{
inBounds = NO;
}
} while (!inBounds);
p->draw.size = sizeArray[0];
p->delta = (0.3);
// p->ddelta = randBetween(1.0, 1.1);
p->ddelta = randBetween(1.0, 1.15);
t = randBetween(0, (0.42*radius));
dist = MAX(20,t);
p->changepoint[0] = p->distance + 5; // 2nd
p->changepoint[1] = p->changepoint[0] - 5 + dist + dist; // 3rd
p->changepoint[2] = p->changepoint[1] + dist; // 4th
p->changepoint[3] = p->changepoint[2] + dist; // 5th
p->changepoint[4] = p->changepoint[3] + dist; // 6th
p->changepoint[5] = 100000; // never change to 7th
p->changemode = 0;
p->erase = p->draw;
return self;
}
- setRadius
{
float x = bounds.size.width;
float y = bounds.size.height;
radius = (sqrt(x*x + y*y))/2;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.