|
|
1.1 ! root 1: // SpaceView.m ! 2: // ! 3: // This class implements the flying starfield screen saver view. ! 4: // ! 5: // You may freely copy, distribute, and reuse the code in this example. ! 6: // NeXT disclaims any warranty of any kind, expressed or implied, as to its ! 7: // fitness for any particular use. ! 8: ! 9: ! 10: #import "SpaceView.h" ! 11: #import "Thinker.h" ! 12: #import "psfuncts.h" ! 13: ! 14: #import <dpsclient/wraps.h> ! 15: #import <appkit/NXImage.h> ! 16: #import <objc/zone.h> ! 17: #import <mach/mach.h> ! 18: #import <c.h> ! 19: #import <libc.h> ! 20: #import <math.h> ! 21: ! 22: #define PI (3.141592653589) ! 23: ! 24: @implementation SpaceView ! 25: ! 26: //takes theta and distance and stuffs it into x &y for *p ! 27: - convertToXY:(STAR *)p ! 28: { ! 29: p->draw->x = floor(bounds.size.width / 2 + (p->distance * cos(p-> theta))); ! 30: p->draw->y = floor(bounds.size.height / 2 + (p->distance * sin(p-> theta))); ! 31: return self; ! 32: } ! 33: ! 34: ! 35: - oneStep ! 36: { ! 37: int i, count, starsInArray = 0; ! 38: STAR *p; ! 39: NXPoint *t; ! 40: ! 41: if (nstars < NSTARS) [self addStar]; ! 42: ! 43: for (i=0; i<nstars; i++) ! 44: { ! 45: p = &stars[i]; ! 46: p->distance += p->delta; ! 47: p->delta *= p->ddelta; ! 48: ! 49: [self convertToXY:p]; ! 50: ! 51: // only draw the star if it moved > 1 pixel ! 52: if (p->draw->x != p->erase->x || ! 53: p->draw->y != p->erase->y) ! 54: { ! 55: BOOL mustErase = NO; ! 56: // add star to the erasure array ! 57: b[starsInArray] = *p->erase; ! 58: bc[starsInArray] = p->c; ! 59: ! 60: if (p->distance > p->changepoint[p->changemode]) ! 61: { ! 62: (p->c)++; // increment character for next star size ! 63: (p->changemode)++; ! 64: } ! 65: ! 66: // clipping is off, so we must not draw outside view. ! 67: // replace stars that go too far... ! 68: if (p->draw->x < 0 || ! 69: p->draw->y < 0 || ! 70: p->draw->x + 7 > bounds.size.width || ! 71: p->draw->y + 7 > bounds.size.height) ! 72: { ! 73: [self replaceStarAt:i]; ! 74: mustErase = YES; ! 75: } ! 76: ! 77: w[starsInArray] = *p->draw; ! 78: wc[starsInArray] = p->c; ! 79: ! 80: if (mustErase || [self allowStars:p]) starsInArray++; ! 81: ! 82: t = p->draw; p->draw = p->erase; p->erase = t; ! 83: } ! 84: } ! 85: ! 86: bc[starsInArray] = wc[starsInArray] = 0; //null terminate string ! 87: if (starsInArray) ! 88: { ! 89: for (i=0; i<(starsInArray-1); i++) ! 90: { ! 91: bOffsets[i].x = b[i+1].x - b[i].x; ! 92: bOffsets[i].y = b[i+1].y - b[i].y; ! 93: wOffsets[i].x = w[i+1].x - w[i].x; ! 94: wOffsets[i].y = w[i+1].y - w[i].y; ! 95: } ! 96: bOffsets[i].x = bOffsets[i].y = wOffsets[i].x = wOffsets[i].y = 0; ! 97: ! 98: count = 0; ! 99: while (count < starsInArray) ! 100: { char tc; ! 101: int j; ! 102: // You get the best performance if you put out all the stars ! 103: // at once. This causes noticable flicker, so I put out ! 104: // 100 of the stars per iteration. This gives reasonable speed ! 105: // and flicker is hardly noticable. Besides, stars ! 106: // _should_ flicker a little... ! 107: ! 108: int t = (starsInArray - count); ! 109: i = (t < STARSPERIT)?t:STARSPERIT; ! 110: j = i + count; ! 111: ! 112: PSsetgray(NX_BLACK); ! 113: tc = bc[j]; bc[j] = 0; ! 114: PSWXYShow(b[count].x, b[count].y, &bc[count], ! 115: (float *)(&bOffsets[count].x), i*2); ! 116: bc[j] = tc; ! 117: ! 118: PSsetgray(NX_WHITE); ! 119: tc = wc[j]; wc[j] = 0; ! 120: PSWXYShow(w[count].x, w[count].y, &wc[count], ! 121: (float *)(&wOffsets[count].x), i*2); ! 122: wc[j] = tc; ! 123: ! 124: count += STARSPERIT; ! 125: } ! 126: } ! 127: ! 128: return self; ! 129: } ! 130: ! 131: // returns yes if the star is outside the avoidance rectangle ! 132: // this is really fast and loose but it works acceptibly well ! 133: // ps I could just use NXIntersectsRect() but I want to avoid ! 134: // trap overhead. Call me paranoid... ! 135: - (BOOL) allowStars:(const STAR *)p ! 136: { ! 137: // just return if voidRect not set ! 138: if ((!voidRect.size.width) || ! 139: p->draw->x < voidRect.origin.x || ! 140: p->draw->y < voidRect.origin.y || ! 141: p->draw->x+7 > voidRect.origin.x+voidRect.size.width || ! 142: p->draw->y+7 > voidRect.origin.y+voidRect.size.height || ! 143: ! 144: p->erase->x < voidRect.origin. x || ! 145: p->erase->y < voidRect.origin. y || ! 146: p->erase->x+7 > voidRect.origin.x+voidRect.size.width || ! 147: p->erase->y+7 > voidRect.origin.y+voidRect.size.height) return YES; ! 148: ! 149: return NO; ! 150: } ! 151: ! 152: - initFrame:(const NXRect *)frameRect ! 153: { ! 154: [super initFrame:frameRect]; ! 155: [self allocateGState]; // For faster lock/unlockFocus ! 156: [self setClipping:NO]; // even faster... ! 157: [self setRadius]; ! 158: loadPSProcedures(); ! 159: PSWDefineFont("StarFont"); ! 160: ! 161: return self; ! 162: } ! 163: ! 164: - drawSelf:(const NXRect *)rects :(int)rectCount ! 165: { ! 166: // this drawself doesn't really draw the view at all. ! 167: // in fact it just promotes the window to screen depth... ! 168: ! 169: NXRect t = {0,0,1,1}; ! 170: ! 171: PSsetrgbcolor(1,0,0); ! 172: NXRectFill(&t); //yucky trick for window depth promotion! ! 173: PSsetgray(NX_BLACK); NXRectFill(&t); ! 174: ! 175: PSselectfont("StarFont", 1.0); ! 176: ! 177: return self; ! 178: } ! 179: ! 180: - sizeTo:(NXCoord)width :(NXCoord)height ! 181: { ! 182: [super sizeTo:width :height]; ! 183: ! 184: if (oldSize.width != bounds.size.width || ! 185: oldSize.height != bounds.size.height) ! 186: { ! 187: oldSize.width = bounds.size.width; ! 188: oldSize.height = bounds.size.height; ! 189: [self setRadius]; ! 190: nstars = 0; ! 191: [self display]; ! 192: } ! 193: ! 194: return self; ! 195: } ! 196: ! 197: // only call addStar if there is room in the stars array! ! 198: - addStar ! 199: { ! 200: [self replaceStarAt:nstars++]; ! 201: return self; ! 202: } ! 203: ! 204: - replaceStarAt:(int)index ! 205: { ! 206: float dist, t; ! 207: int tries = 0; ! 208: STAR *p = &stars[index]; ! 209: BOOL inBounds; ! 210: ! 211: p->draw = &p->r1; ! 212: p->erase = &p->r2; ! 213: ! 214: ! 215: do { ! 216: p->theta = randBetween(0,(2*PI)); ! 217: ! 218: if (tries++ < 3) p->distance = randBetween(1, radius); ! 219: else p->distance = randBetween(1, p->distance); ! 220: ! 221: inBounds = YES; ! 222: [self convertToXY:p]; ! 223: ! 224: if (p->draw->x < 0 || p->draw->y < 0 || ! 225: p->draw->x + 7 > bounds.size.width || ! 226: p->draw->y + 7 > bounds.size.height) ! 227: { ! 228: inBounds = NO; ! 229: } ! 230: } while (!inBounds); ! 231: ! 232: p->delta = (0.2); ! 233: ! 234: p->ddelta = randBetween(1.0, 1.1); ! 235: ! 236: ! 237: ! 238: t = randBetween(0, (0.42*radius)); ! 239: dist = MAX(20,t); ! 240: p->changepoint[0] = p->distance + 5; // to b ! 241: p->changepoint[1] = p->changepoint[0] - 5 + dist + dist; // to c ! 242: ! 243: ! 244: p->changepoint[2] = p->changepoint[1] + dist; // to d ! 245: p->changepoint[3] = p->changepoint[2] + dist; // to e ! 246: p->changepoint[4] = p->changepoint[3] + dist; // to f ! 247: p->changepoint[5] = 100000; // never change to g ! 248: ! 249: p->changemode = 0; ! 250: ! 251: if ((++toggle) & 1) p->c = 'a'; ! 252: else p->c = 'g'; ! 253: ! 254: p->r2 = p->r1; ! 255: ! 256: return self; ! 257: } ! 258: ! 259: - setRadius ! 260: { ! 261: float x = bounds.size.width; ! 262: float y = bounds.size.height; ! 263: radius = (sqrt(x*x + y*y))/2; ! 264: return self; ! 265: } ! 266: ! 267: - (const char *)windowTitle ! 268: { ! 269: return "The Final Frontier"; ! 270: } ! 271: ! 272: - setVoidRect:(const NXRect *)r ! 273: { ! 274: voidRect = *r; ! 275: return self; ! 276: } ! 277: ! 278: - didLockFocus ! 279: { ! 280: PSselectfont("StarFont", 1.0); ! 281: return self; ! 282: } ! 283: ! 284: - (BOOL)useBufferedWindow ! 285: { return NO; ! 286: } ! 287: ! 288: - inspector:sender ! 289: { ! 290: return [sender spaceInspector]; ! 291: } ! 292: ! 293: - (BOOL)ignoreMouseMovement ! 294: { return NO; ! 295: } ! 296: ! 297: - inspectorWillBeRemoved ! 298: { return self; // just a prototype ! 299: } ! 300: ! 301: - inspectorInstalled ! 302: { return self; // just a prototype ! 303: } ! 304: ! 305: @end ! 306: ! 307: ! 308: ! 309: // this class is only used in the inspector, it animates ! 310: // when it draws itself. ! 311: ! 312: @implementation StaticSpaceView ! 313: ! 314: - drawSelf:(const NXRect *)rects :(int)rectCount ! 315: { ! 316: int i; ! 317: ! 318: if (!rects || !rectCount) return self; ! 319: ! 320: PSselectfont("StarFont", 1.0); ! 321: ! 322: PSsetgray(NX_BLACK); ! 323: NXRectFill(rects); ! 324: ! 325: for (i=0; i<20; i++) ! 326: { ! 327: [self oneStep]; ! 328: [[self window] flushWindow]; ! 329: NXPing(); ! 330: } ! 331: ! 332: return self; ! 333: } ! 334: ! 335: - initFrame:(const NXRect *)frameRect ! 336: { ! 337: [super initFrame:frameRect]; ! 338: ! 339: while (nstars < NSTARS) [self addStar]; ! 340: return self; ! 341: } ! 342: ! 343: - sizeTo:(NXCoord)width :(NXCoord)height ! 344: { ! 345: [super sizeTo:width :height]; ! 346: ! 347: nstars = 0; ! 348: while (nstars < NSTARS) [self addStar]; ! 349: return self; ! 350: } ! 351: ! 352: @end ! 353: ! 354: ! 355: ! 356: ! 357: ! 358: @implementation View(nonretainedFillMethod) ! 359: ! 360: // I add this method as a category of View to be sure that all ! 361: // my views implement it. I really want to use nonretained windows ! 362: // but they are drawn via drawSelf at all kinds of goofy times. It ! 363: // seems like the kit kind of throws up its hands when it doesn't have ! 364: // a buffer to draw from, so you get a lot more drawSelfs than you need, ! 365: // and sometimes you don't get them when you really want them. I know ! 366: // when I need the background filled in black, so I factor that out of ! 367: // my drawSelf and then drawself only draws things that are already on ! 368: // screen so you don't see it happen. I will only call this method on ! 369: // a nonretained (and full screen) window. ! 370: ! 371: - fillBoundsWithBlack ! 372: { ! 373: if ([self canDraw]) ! 374: { ! 375: [self lockFocus]; ! 376: PSsetgray(NX_BLACK); ! 377: NXRectFill(&bounds); ! 378: [self unlockFocus]; ! 379: } ! 380: return self; ! 381: } ! 382: ! 383: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.