|
|
1.1 ! root 1: /* ! 2: The animation guts from a freely distributable X program: ! 3: xsperm.c ! 4: Drew Olbrich, Febrary 1991 ! 5: Note -- This code originally served as a demonstration ! 6: of how to do animation under X. The "guts" of the program ! 7: which draws the sperm are consequently located in one huge ! 8: chunk in the update_display() routine, and can be easily ! 9: cut out. ! 10: ! 11: The animation function wrapped in a NeXTstep View subclass by Ali Ozer, May 91 ! 12: Very minor changes so this thing works as a screen saver module by sam streeper, ! 13: August 91 ! 14: The "oneStep" method computes new locations. ! 15: */ ! 16: ! 17: #import "SpermView.h" ! 18: #import "Thinker.h" ! 19: #import <appkit/appkit.h> ! 20: ! 21: #define VEC_DOT(x, y) (x[0]*y[0] + x[1]*y[1]) ! 22: #define VEC_LEN(x) (sqrt(x[0]*x[0] + x[1]*x[1])) ! 23: ! 24: #define VEC_SET(x, a, b) x[0] = a, x[1] = b ! 25: #define VEC_COPY(y, x) y[0] = x[0], y[1] = x[1] ! 26: #define VEC_NEG(x) x[0] = -x[0], x[1] = -x[1] ! 27: #define VEC_ADD(z, x, y) z[0] = x[0] + y[0], z[1] = x[1] + y[1] ! 28: #define VEC_SUB(z, x, y) z[0] = x[0] - y[0], z[1] = x[1] - y[1] ! 29: #define VEC_MULT(x, a) x[0] *= a, x[1] *= a ! 30: #define VEC_DIV(x, a) x[0] /= a, x[1] /= a ! 31: #define VEC_ADDS(z, x, a, y) z[0] = x[0] + (a)*y[0], z[1] = x[1] + (a)*y[1] ! 32: #define VEC_NORM(x) { double l = VEC_LEN(x); VEC_DIV(x, l); } ! 33: ! 34: #define MINRAD 0.1 ! 35: #define RADSTEP 2.0 ! 36: #define MAXRAD (MINRAD * RADSTEP * RADSTEP * RADSTEP * RADSTEP * RADSTEP * RADSTEP) ! 37: #define INITRAD (MINRAD * RADSTEP * RADSTEP * RADSTEP) ! 38: ! 39: // RANDINT(n) returns an integer 0..n-1 ! 40: // RANDFLOAT(f) returns a float [0..f] (inclusive on both ends) ! 41: ! 42: #define RANDINT(n) (random() % (n)) ! 43: #define RANDFLOAT(f) (((f) * (float)(random() & 0x0ffff)) / (float)0x0ffff) ! 44: ! 45: @implementation SpermView ! 46: ! 47: - initFrame:(const NXRect *)rect ! 48: { ! 49: [super initFrame:rect]; ! 50: ! 51: [self allocateGState]; // For faster lock/unlockFocus ! 52: ! 53: dir = 1.0; ! 54: rad = INITRAD; ! 55: [self getSpermCount]; ! 56: [self getLineWidth]; ! 57: [self getUseColor]; ! 58: [inspectorPanel display]; ! 59: ! 60: color = NX_COLORWHITE; ! 61: alreadyInitialized = NO; ! 62: randCount1 = 100; ! 63: randCount2 = 200; ! 64: ! 65: uPath = newUserPath(); ! 66: ! 67: return self; ! 68: } ! 69: ! 70: - (void)initializeLine:(int)i ! 71: { ! 72: double angle = RANDFLOAT(10.0) + 5.0; ! 73: prevX[i][0] = x[i][0] = (double) (RANDINT((int)NX_WIDTH(&bounds))); ! 74: prevX[i][1] = x[i][1] = (double) (RANDINT((int)NX_HEIGHT(&bounds))); ! 75: v[i][0] = RANDFLOAT(2.0) - 1.0; ! 76: v[i][1] = RANDFLOAT(2.0) - 1.0; ! 77: sine[i] = sin(angle*M_PI/180.0); ! 78: cosine[i] = cos(angle*M_PI/180.0); ! 79: vel[i] = RANDFLOAT(4.0) + 4.0; ! 80: VEC_NORM(v[i]); ! 81: } ! 82: ! 83: - (void)getFocusFromEvent:(NXEvent *)event ! 84: { ! 85: NXPoint loc = event->location; ! 86: [self convertPoint:&loc fromView:nil]; ! 87: mouse[0] = loc.x; ! 88: mouse[1] = loc.y; ! 89: } ! 90: ! 91: - (BOOL)acceptsFirstMouse ! 92: { return YES; ! 93: } ! 94: ! 95: - mouseDown:(NXEvent *)event ! 96: { ! 97: [self getFocusFromEvent:event]; ! 98: return self; ! 99: } ! 100: ! 101: - effectOne ! 102: { ! 103: VECTOR y; ! 104: int i; ! 105: ! 106: dir *= -1.0; ! 107: for (i = 0; i < MAXCOUNT; i++) { ! 108: VEC_COPY(y, v[i]); ! 109: if (dir == -1.0) { ! 110: v[i][0] = y[1]; ! 111: v[i][1] = -y[0]; ! 112: } else { ! 113: v[i][0] = -y[1]; ! 114: v[i][1] = y[0]; ! 115: } ! 116: } ! 117: return self; ! 118: } ! 119: ! 120: - effectTwo ! 121: { ! 122: int i; ! 123: for (i = 0; i < MAXCOUNT; i++) { ! 124: v[i][0] = -v[i][0]; ! 125: } ! 126: return self; ! 127: } ! 128: ! 129: - effectThree ! 130: { ! 131: int i; ! 132: for (i = 0; i < MAXCOUNT; i++) { ! 133: v[i][1] = -v[i][1]; ! 134: } ! 135: return self; ! 136: } ! 137: ! 138: - effectFour ! 139: { ! 140: [self effectTwo]; ! 141: [self effectThree]; ! 142: return self; ! 143: } ! 144: ! 145: - effectFive ! 146: { ! 147: [self effectOne]; ! 148: [self effectFour]; ! 149: return self; ! 150: } ! 151: ! 152: - effectSix ! 153: { ! 154: rad = MIN(rad * RADSTEP, MAXRAD); ! 155: return self; ! 156: } ! 157: ! 158: - effectSeven ! 159: { ! 160: rad = MAX(rad / RADSTEP, MINRAD); ! 161: return self; ! 162: } ! 163: ! 164: - doEffectNumber:(int)val ! 165: { ! 166: switch (val) { ! 167: case 0: [self effectOne]; break; ! 168: case 1: [self effectTwo]; break; ! 169: case 2: [self effectThree]; break; ! 170: case 3: [self effectFour]; break; ! 171: case 4: [self effectFive]; break; ! 172: case 5: [self effectSix]; break; ! 173: case 6: [self effectSeven]; break; ! 174: default: break; ! 175: } ! 176: return self; ! 177: } ! 178: ! 179: - oneStep ! 180: { ! 181: int i, cnt; ! 182: POINT lLeft, uRight; ! 183: NXRect eraseRect; ! 184: ! 185: uRight[0] = lLeft[0] = x[0][0]; ! 186: uRight[1] = lLeft[1] = x[0][1]; ! 187: ! 188: for (i = 0; i < count; i++) { ! 189: VECTOR w, y; ! 190: POINT p; ! 191: double r; ! 192: ! 193: for (cnt = 0; cnt < 2; cnt++) { ! 194: if (prevX[i][cnt] < lLeft[cnt]) lLeft[cnt] = prevX[i][cnt]; ! 195: else if (prevX[i][cnt] > uRight[cnt]) uRight[cnt] = prevX[i][cnt]; ! 196: if (x[i][cnt] < lLeft[cnt]) lLeft[cnt] = x[i][cnt]; ! 197: else if (x[i][cnt] > uRight[cnt]) uRight[cnt] = x[i][cnt]; ! 198: } ! 199: ! 200: prevX[i][0] = x[i][0]; /* old location */ ! 201: prevX[i][1] = x[i][1]; ! 202: ! 203: VEC_SUB(w, x[i], mouse); ! 204: VEC_NORM(w); ! 205: VEC_COPY(y, w); ! 206: w[0] = y[0]*cosine[i] - dir*y[1]*sine[i]; ! 207: w[1] = y[1]*cosine[i] + dir*y[0]*sine[i]; ! 208: VEC_ADDS(p, mouse, rad*(160.0 - vel[i]*20.0), w); ! 209: ! 210: VEC_SUB(w, p, x[i]); ! 211: r = VEC_LEN(w); ! 212: VEC_DIV(w, r); ! 213: ! 214: VEC_ADDS(v[i], v[i], 1.0, w); ! 215: ! 216: VEC_NORM(v[i]); ! 217: VEC_MULT(v[i], vel[i]); ! 218: ! 219: VEC_ADD(x[i], x[i], v[i]); ! 220: ! 221: } ! 222: ! 223: NXSetRect (&eraseRect, lLeft[0], lLeft[1], uRight[0]-lLeft[0], uRight[1]-lLeft[1]); ! 224: NXInsetRect (&eraseRect, -1.0-lineWidth, -1.0-lineWidth); ! 225: PSsetgray(0); ! 226: NXRectFill(&eraseRect); ! 227: ! 228: [self drawPath]; ! 229: ! 230: if (--randCount1 < 0) ! 231: { ! 232: randCount1 = RANDINT(700); ! 233: mouse[0] = randBetween(0,bounds.size.width); ! 234: mouse[1] = randBetween(0,bounds.size.height); ! 235: } ! 236: if (--randCount2 < 0) ! 237: { ! 238: randCount2 = RANDINT(600); ! 239: [self doEffectNumber:(randCount2 % 7)]; ! 240: } ! 241: return self; ! 242: } ! 243: ! 244: // Modify "orig" by upto plus or minus "by" keeping it in the specified range... ! 245: ! 246: static float randMod(float orig, float by, float min, float max) ! 247: { ! 248: orig = orig + RANDFLOAT(by * 2.0) - by; ! 249: return (orig < min) ? min : ((orig > max) ? max : orig); ! 250: } ! 251: ! 252: - drawPath ! 253: { ! 254: int cnt; ! 255: ! 256: PSsetlinewidth (lineWidth); ! 257: if (useColors) { ! 258: color = NXConvertRGBToColor(randMod(NXRedComponent(color), 0.05, 0.0, 1.0), ! 259: randMod(NXGreenComponent(color), 0.05, 0.0, 1.0), ! 260: randMod(NXBlueComponent(color), 0.05, 0.0, 1.0)); ! 261: } ! 262: else color = NX_COLORWHITE; ! 263: ! 264: NXSetColor (color); ! 265: ! 266: beginUserPath(uPath, NO); ! 267: for (cnt = 0; cnt < count; cnt++) { ! 268: UPmoveto(uPath, (float)prevX[cnt][0], (float)prevX[cnt][1]); ! 269: UPlineto(uPath, (float)x[cnt][0], (float)x[cnt][1]); ! 270: } ! 271: closePath(uPath); ! 272: endUserPath(uPath, dps_ustroke); ! 273: sendUserPath(uPath); ! 274: ! 275: return self; ! 276: } ! 277: ! 278: - drawSelf:(const NXRect *)rects :(int)rectCount ! 279: { ! 280: if (!rects || !rectCount) return self; ! 281: ! 282: PSsetgray(NX_BLACK); ! 283: NXRectFill(rects); ! 284: [self drawPath]; ! 285: return self; ! 286: } ! 287: ! 288: - newWindow ! 289: { ! 290: mouse[0] = randBetween(0,bounds.size.width); ! 291: mouse[1] = randBetween(0,bounds.size.height); ! 292: ! 293: return self; ! 294: } ! 295: ! 296: - free ! 297: { ! 298: freeUserPath(uPath); ! 299: return [super free]; ! 300: } ! 301: ! 302: - setNumLines:sender ! 303: { ! 304: int i; ! 305: int oldCount = count; ! 306: char str[100]; ! 307: ! 308: // set the number of lines ! 309: count = MIN(MAXCOUNT, MAX([sender intValue], 1)); ! 310: ! 311: // initialize velocities & such ! 312: for (i = oldCount; i < count; i++) { ! 313: [self initializeLine:i]; ! 314: } ! 315: ! 316: [self display]; ! 317: ! 318: sprintf(str,"%d", count); ! 319: NXWriteDefault([NXApp appName], "SpermViewCount", str); ! 320: ! 321: return self; ! 322: } ! 323: ! 324: - getSpermCount ! 325: { ! 326: const char *ptr; ! 327: int val; ! 328: ! 329: [spermCountSlider setMinValue: 10]; ! 330: [spermCountSlider setMaxValue: MAXCOUNT]; ! 331: ! 332: ptr = NXGetDefaultValue([NXApp appName], "SpermViewCount"); ! 333: if (ptr) ! 334: { ! 335: sscanf(ptr,"%d",&val); ! 336: if (val >= 10 && val <= MAXCOUNT) count = val; ! 337: else count = MAXCOUNT; ! 338: } ! 339: else count = MAXCOUNT; ! 340: ! 341: return self; ! 342: } ! 343: ! 344: - setUseColor:sender ! 345: { ! 346: useColors = [sender state]; ! 347: ! 348: if (useColors) ! 349: NXWriteDefault([NXApp appName], "SpermViewColor", "Yes"); ! 350: else ! 351: NXRemoveDefault([NXApp appName], "SpermViewColor"); ! 352: ! 353: return self; ! 354: } ! 355: ! 356: - getUseColor ! 357: { ! 358: const char *ptr; ! 359: ! 360: ptr = NXGetDefaultValue([NXApp appName], "SpermViewColor"); ! 361: ! 362: if (!ptr || !strcmp(ptr,"No")) useColors = NO; ! 363: else useColors = YES; ! 364: ! 365: return self; ! 366: } ! 367: ! 368: - setLineWidth:sender ! 369: { ! 370: char str[50]; ! 371: ! 372: lineWidth = MAX([sender floatValue], 0.0); ! 373: sprintf(str,"%5.1f", lineWidth); ! 374: NXWriteDefault([NXApp appName], "SpermViewWidth", str); ! 375: ! 376: return self; ! 377: } ! 378: ! 379: - getLineWidth ! 380: { ! 381: const char *ptr; ! 382: float val; ! 383: ! 384: [spermWidthSlider setMinValue: 0]; ! 385: [spermWidthSlider setMaxValue: 8]; ! 386: ! 387: ptr = NXGetDefaultValue([NXApp appName], "SpermViewWidth"); ! 388: if (ptr) ! 389: { ! 390: sscanf(ptr,"%f",&val); ! 391: if (val >= 0 && val <= 8) lineWidth = val; ! 392: else lineWidth = 0; ! 393: } ! 394: else lineWidth = 0; ! 395: ! 396: return self; ! 397: } ! 398: ! 399: - sizeTo:(NXCoord)width :(NXCoord)height ! 400: { ! 401: [super sizeTo:width :height]; ! 402: ! 403: if (!alreadyInitialized) ! 404: { int i; ! 405: mouse[0] = NX_MIDX(&bounds); ! 406: mouse[1] = NX_MIDY(&bounds); ! 407: ! 408: for (i = 0; i < MAXCOUNT; i++) { ! 409: [self initializeLine:i]; ! 410: } ! 411: alreadyInitialized = YES; ! 412: } ! 413: ! 414: [self newWindow]; ! 415: return self; ! 416: } ! 417: ! 418: - (const char *)windowTitle ! 419: { return "Sperm"; ! 420: } ! 421: ! 422: - (BOOL) useBufferedWindow; ! 423: { return YES; ! 424: } ! 425: ! 426: ! 427: - inspector:sender ! 428: { ! 429: char buf[MAXPATHLEN]; ! 430: ! 431: if (!inspectorPanel) ! 432: { ! 433: [NXBundle getPath:buf forResource:"sperm" ofType:"nib" inDirectory:[sender moduleDirectory:"Sperm"] withVersion:0]; ! 434: [NXApp loadNibFile:buf owner:self withNames:NO]; ! 435: ! 436: [spermCountSlider setIntValue:count]; ! 437: [spermWidthSlider setFloatValue:lineWidth]; ! 438: [colorButton setState: (useColors ? 1:0)]; ! 439: } ! 440: return inspectorPanel; ! 441: } ! 442: ! 443: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.