Annotation of Examples/AppKit/BackspaceViews/Sperm/SpermView.m, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.