Annotation of Examples/AppKit/Backspace/SpaceView.m, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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