Annotation of Examples/AppKit/Backspace/BoinkViewPart.m, revision 1.1

1.1     ! root        1: //  BoinkViewPart.m
        !             2: //
        !             3: //  implements a bouncing ball 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 "BoinkViewPart.h"
        !            11: #import "SpaceView.h"
        !            12: #import "Thinker.h"
        !            13: #import "BoinkWraps.h"
        !            14: #import <appkit/NXImage.h>
        !            15: #import <math.h>
        !            16: #import <libc.h>
        !            17: #import <dpsclient/wraps.h>
        !            18: 
        !            19: @implementation BoinkView
        !            20: 
        !            21: // assumed interval in milliseconds
        !            22: #define ASSUMED_INTERVAL 35
        !            23: 
        !            24: #define WIDTH 100
        !            25: #define HEIGHT 100
        !            26: #define GAP 4
        !            27: #define COUNT 10
        !            28: #define ACCEL (-2)
        !            29: #define REBOUND (-1.3)
        !            30: 
        !            31: // This screen height value is not critical, though it will be used
        !            32: // to determine how high the ball can go
        !            33: #define SCREEN_HEIGHT 832
        !            34: #define LAUNCH_SPEED (sqrt(fabs(2*ACCEL*(SCREEN_HEIGHT - HEIGHT))))
        !            35: #define REAL_LAUNCH_SPEEd (sqrt(fabs(2*accel*(viewHeight - HEIGHT))))
        !            36: 
        !            37: #define MIN_X_SPEED (3)
        !            38: #define MAX_X_SPEED (6)
        !            39: #define ABS_MAX_X_SPEED (6)
        !            40: #define MAX_Y_SPEED (LAUNCH_SPEED + 20)
        !            41: 
        !            42: #define BUFFER_WIDTH (WIDTH + ABS_MAX_X_SPEED + 1)
        !            43: #define BUFFER_HEIGHT (HEIGHT + MAX_Y_SPEED + 1)
        !            44: 
        !            45: 
        !            46: 
        !            47: /* move the ball to its new bounce position */
        !            48: - oneStep
        !            49: {
        !            50:        NXRect black = {0,0,0,0};
        !            51:        NXRect ballRect;
        !            52:        BRECT new;
        !            53:        float scaledTime, calcYpos;
        !            54:        
        !            55:        then = now;
        !            56:        now = currentTimeInMs();
        !            57: 
        !            58:        /* calculate new ball x position */
        !            59:        xpos += [self timeCorrectedXSpeed];
        !            60: 
        !            61:        if (xpos < 0)                           /* ball hit left edge */
        !            62:        {       xspeed = -xspeed;
        !            63:                if (viewWidth > WIDTH)
        !            64:                {       spinDir = -spinDir;
        !            65:                }
        !            66:                xpos = 0;
        !            67:        }
        !            68:        else if (xpos > (viewWidth - WIDTH))            /* ball hit right edge */
        !            69:        {       if (viewWidth > WIDTH)
        !            70:                {
        !            71:                        xspeed = -[self getRandomXspeed];
        !            72:                        [self checkXspeed:&xspeed];
        !            73:                        xpos = (viewWidth - WIDTH);
        !            74:                }
        !            75:                else
        !            76:                {       xspeed = xpos = 0;
        !            77:                }
        !            78:        }
        !            79: 
        !            80: 
        !            81:        scaledTime = ((float)(now - then) / ASSUMED_INTERVAL);
        !            82:        if (scaledTime > 1) scaledTime = 1;
        !            83:        
        !            84:        // calculate new ball vertical position
        !            85:        calcYpos = ypos + (scaledTime*yspeed) + ((accel * scaledTime * scaledTime)/2);
        !            86: 
        !            87:        // change vertical ball speed to simulate gravity
        !            88:        yspeed += (accel * scaledTime);
        !            89:        
        !            90:        if (calcYpos < (ypos - MAX_Y_SPEED)) calcYpos = ypos - MAX_Y_SPEED;
        !            91:        else if (calcYpos > (ypos + MAX_Y_SPEED)) calcYpos = ypos + MAX_Y_SPEED;
        !            92:        
        !            93:        ypos = calcYpos;
        !            94:        
        !            95:        if (yspeed < -MAX_Y_SPEED) yspeed = -MAX_Y_SPEED;
        !            96:        
        !            97: 
        !            98:        if (ypos <= 0)                          /* ball hit bottom of window */
        !            99:        {
        !           100:                ypos = 0;
        !           101:                
        !           102:                if (viewHeight > HEIGHT)
        !           103:                {
        !           104:                        if (reboundMode == DECREASING)
        !           105:                        {
        !           106:                                yspeed = lastLaunchSpeed = lastLaunchSpeed + rebound;
        !           107:                        }
        !           108:                        else
        !           109:                        {
        !           110:                                yspeed = lastLaunchSpeed = lastLaunchSpeed - (2*rebound);
        !           111:                        }
        !           112: 
        !           113:                        if (yspeed <= 0)
        !           114:                        {
        !           115:                                yspeed = 0;
        !           116:                                reboundMode = INCREASING;       /* bounce height increases every bounce */
        !           117:                        }
        !           118:                        else if (yspeed > MAX_Y_SPEED) yspeed = MAX_Y_SPEED - (3*accel);
        !           119:                }
        !           120:                else yspeed = 0;
        !           121:        
        !           122:        }
        !           123:        else if (ypos >= (viewHeight - HEIGHT)) /* ball hit top of window */
        !           124:        {       if (viewHeight > HEIGHT)
        !           125:                {
        !           126:                        yspeed = accel;
        !           127:                        ypos = (viewHeight - HEIGHT);
        !           128:                        reboundMode = DECREASING;       /* bounce height decreases every bounce */
        !           129:                        spinDir = -spinDir;
        !           130:                }
        !           131:                else
        !           132:                {       yspeed = ypos = 0;
        !           133:                }
        !           134:        }
        !           135: 
        !           136: 
        !           137:        /* rotate the ball by selecting a new ball image to blit */
        !           138:        /* we have an image of the ball in 10 different stages of rotation */
        !           139: 
        !           140:        [self incrementBallNumber];
        !           141:        
        !           142:        new.l = floor(xpos);
        !           143:        new.b = floor(ypos);
        !           144:        new.r = new.l + WIDTH;
        !           145:        new.t = new.b + HEIGHT;
        !           146:        
        !           147:        ballRect.origin.x = (WIDTH+GAP) * ballNum;
        !           148:        ballRect.origin.y = 0;
        !           149:        ballRect.size.width = WIDTH;
        !           150:        ballRect.size.height = HEIGHT;
        !           151:        
        !           152:        redrawTo.x = MIN(new.l, old.l);
        !           153:        redrawTo.y = MIN(new.b, old.b);
        !           154: 
        !           155:        redraw.origin.x = 0;
        !           156:        redraw.origin.y = 0;
        !           157:        redraw.size.width = (MAX(new.r, old.r)) - redrawTo.x + 1;
        !           158:        redraw.size.height = (MAX(new.t, old.t)) - redrawTo.y + 1;
        !           159:        
        !           160:        black.size= redraw.size;
        !           161: 
        !           162:        [self updateGrid];
        !           163: 
        !           164:        [buffer lockFocus];
        !           165:        PSsetgray(0);
        !           166:        NXRectFill(&black);
        !           167:        
        !           168:        ballTo.x = new.l - redrawTo.x;
        !           169:        ballTo.y = new.b - redrawTo.y;
        !           170: 
        !           171:        [self drawLinesInBuffer];
        !           172:        
        !           173:        [balls composite:NX_SOVER fromRect:&ballRect toPoint:&ballTo];
        !           174:        [buffer unlockFocus];
        !           175:        
        !           176:        
        !           177:        // Now bring it onto the screen
        !           178:        
        !           179:        [buffer composite:NX_COPY fromRect:&redraw toPoint:&redrawTo];
        !           180: 
        !           181:        old = new;
        !           182: 
        !           183:        return self;
        !           184: }
        !           185: 
        !           186: 
        !           187: 
        !           188: /* calculate a vertical launch speed which will get the ball almost to */
        !           189: /* the top of the window before gravity pulls it back down. Little bit */
        !           190: /* of physics lesson here...                                                                                   */
        !           191: 
        !           192: - newSpeed
        !           193: {
        !           194:        lastLaunchSpeed = yspeed = REAL_LAUNCH_SPEEd;
        !           195:        if (yspeed > MAX_Y_SPEED) yspeed = MAX_Y_SPEED;
        !           196:        xpos = 0;
        !           197:        ypos = 0;
        !           198: 
        !           199:        if (viewWidth <= WIDTH) xspeed = 0;
        !           200:        else xspeed = [self getRandomXspeed];
        !           201: 
        !           202:        [self checkXspeed:&xspeed];
        !           203:        rebound = REBOUND;
        !           204:        return self;
        !           205: }
        !           206: 
        !           207: 
        !           208: - initFrame:(const NXRect *)frameRect
        !           209: {
        !           210:        NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT };
        !           211: 
        !           212:        [super initFrame:frameRect];
        !           213:        [self allocateGState];          // For faster lock/unlockFocus
        !           214:        [self setClipping:NO];          // even faster...
        !           215: 
        !           216:        accel = ACCEL;
        !           217:        spinDir = 1;
        !           218: 
        !           219:        //in this case, I only need one buffer for several Views
        !           220:        if (!(buffer = [NXImage findImageNamed:"boinkBuffer"]))
        !           221:        {
        !           222:                buffer = [[NXImage alloc] initSize:&black.size];
        !           223:                [buffer setName:"boinkBuffer"];
        !           224:        }
        !           225:        
        !           226:        if ([buffer lockFocus])
        !           227:        {
        !           228:                PSsetgray(0);
        !           229:                NXRectFill(&black);
        !           230:                [buffer unlockFocus];
        !           231:        }
        !           232: 
        !           233:        balls = [NXImage findImageNamed:"balls"];
        !           234: 
        !           235:        [self newViewSize];
        !           236: 
        !           237:        return self;
        !           238: }
        !           239: 
        !           240: - setAccel:(float)val
        !           241: {
        !           242:        accel = val;
        !           243:        return self;
        !           244: }
        !           245: 
        !           246: - sizeTo:(NXCoord)width :(NXCoord)height
        !           247: {
        !           248:        [super sizeTo:width :height];
        !           249:        [self newViewSize];
        !           250:        return self;
        !           251: }
        !           252: 
        !           253: - drawSelf:(const NXRect *)rects :(int)rectCount
        !           254: {
        !           255:        if (!rects || !rectCount) return self;
        !           256:        
        !           257:        //PSsetgray(0);
        !           258:        //NXRectFill(rects);
        !           259:        
        !           260:        NXRectClip(rects);
        !           261:        [self drawGrid];
        !           262: 
        !           263:        return self;
        !           264: }
        !           265: 
        !           266: - newViewSize
        !           267: {
        !           268:        int i;
        !           269:        //this is called every time View size changes
        !           270:        NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT };
        !           271: 
        !           272:        then = now = currentTimeInMs();
        !           273: 
        !           274:        if (oldSize.width == bounds.size.width &&
        !           275:                        oldSize.height == bounds.size.height)
        !           276:                return self;
        !           277:        else
        !           278:        {
        !           279:                oldSize.width = bounds.size.width;
        !           280:                oldSize.height = bounds.size.height;
        !           281:        }
        !           282:        
        !           283:        old.l = old.r = old.b = old.t = ballTo.x = ballTo.y = 0;
        !           284: 
        !           285:        viewWidth = bounds.size.width;
        !           286:        viewHeight = bounds.size.height;
        !           287:        if (viewHeight > SCREEN_HEIGHT) viewHeight = SCREEN_HEIGHT;
        !           288:        
        !           289:        nvert = viewWidth/130;
        !           290:        if (nvert > NVERT) nvert = NVERT;
        !           291:        nhoriz = viewHeight/130;
        !           292:        if (nhoriz > NHORIZ) nhoriz = NHORIZ;
        !           293:        
        !           294:        if (viewWidth < WIDTH) nvert = 0;
        !           295:        if (viewHeight < HEIGHT) nhoriz= 0;
        !           296:        vcount = hcount = 0;
        !           297:        
        !           298:        for (i=0; i<nvert; i++)
        !           299:        {
        !           300:                vertLines[i].hue = i * 0.17;
        !           301:                while (vertLines[i].hue > 1) vertLines[i].hue -= 1;
        !           302:                vertLines[i].pos = floor(i * (viewWidth/nvert));
        !           303:        }
        !           304:        
        !           305:        for (i=0; i<nhoriz; i++)
        !           306:        {
        !           307:                horizLines[i].hue = i * 0.17 + 0.1;
        !           308:                while (horizLines[i].hue > 1) horizLines[i].hue -= 1;
        !           309:                horizLines[i].pos = i * floor((viewHeight/nhoriz)) + 1;
        !           310:        }
        !           311:        
        !           312:        if ([buffer lockFocus])
        !           313:        {
        !           314:                PSsetgray(0);
        !           315:                NXRectFill(&black);
        !           316:                [buffer unlockFocus];
        !           317:        }
        !           318: 
        !           319:        [self newSpeed];
        !           320:        return self;
        !           321: }
        !           322: 
        !           323: - incrementBallNumber
        !           324: {
        !           325:        if (now > nextRotationTime)
        !           326:        {
        !           327:                ballNum += spinDir;
        !           328: 
        !           329:                if (ballNum >= COUNT) ballNum = 0;
        !           330:                else if (ballNum < 0) ballNum = COUNT-1;
        !           331:                nextRotationTime = now + 24;
        !           332:        }
        !           333: 
        !           334:        return self;
        !           335: }
        !           336: 
        !           337: - (float) getRandomXspeed
        !           338: {
        !           339:        return randBetween(MIN_X_SPEED, MAX_X_SPEED);
        !           340: }
        !           341: 
        !           342: - (float) timeCorrectedXSpeed
        !           343: {
        !           344:        float ret = xspeed * ((float)(now - then) / ASSUMED_INTERVAL);
        !           345:        [self checkXspeed:&ret];
        !           346:        return ret;
        !           347: }
        !           348: 
        !           349: - checkXspeed:(float *)speed
        !           350: {
        !           351:        if (*speed > MAX_X_SPEED) *speed = MAX_X_SPEED;
        !           352:        else if (*speed < -MAX_X_SPEED) *speed = -MAX_X_SPEED;
        !           353:        return self;
        !           354: }
        !           355: 
        !           356: - (const char *)windowTitle
        !           357: {
        !           358:        return "Boink!";
        !           359: }
        !           360: 
        !           361: 
        !           362: - drawGrid
        !           363: {
        !           364:        int i;
        !           365:        float *fp;
        !           366:                
        !           367:        for (i=0; i<nvert; i++)
        !           368:        {
        !           369:                fp = &vertLines[i].pos;
        !           370:                colorLine(*fp, 0, *fp, viewHeight, vertLines[i].hue, 1);
        !           371:        }
        !           372:        
        !           373:        for (i=0; i<nhoriz; i++)
        !           374:        {
        !           375:                fp = &horizLines[i].pos;
        !           376:                colorLine(0, *fp, viewWidth, *fp, horizLines[i].hue, 1);
        !           377:        }
        !           378:        
        !           379:        return self;
        !           380: }
        !           381: 
        !           382: - updateGrid
        !           383: {
        !           384:        NXRect avoid;
        !           385:        float oldPos;
        !           386:        float *fp;
        !           387:        
        !           388:        if (!nvert && !nhoriz) return self;
        !           389: 
        !           390:        if (now < nextLineDrawTime) return self;
        !           391: 
        !           392:        nextLineDrawTime = now + 3300;
        !           393:        
        !           394:        avoid.origin = redrawTo;
        !           395:        avoid.size = redraw.size;
        !           396: 
        !           397:        if (++toggle & 1)
        !           398:        {
        !           399:                //advance vertical line
        !           400:                
        !           401:                if (!nvert) return self;
        !           402:                
        !           403:                fp = &vertLines[vcount].pos;
        !           404:                oldPos = *fp;
        !           405:                *fp += 1;
        !           406:                if (*fp > viewWidth) *fp = 0;
        !           407:                vertLines[vcount].hue += 0.005;
        !           408:                if (vertLines[vcount].hue > 1) vertLines[vcount].hue -= 1;
        !           409:                
        !           410: 
        !           411:                verticalLineWithAvoidance(*fp, 0, *fp, viewHeight, vertLines[vcount].hue, 1, &avoid);
        !           412:                verticalLineWithAvoidance(oldPos, 0, oldPos, viewHeight, 0, 0, &avoid);
        !           413: 
        !           414:                if (++vcount >= nvert) vcount = 0;
        !           415:        }
        !           416:        else
        !           417:        {
        !           418:                //advance horiz line
        !           419:                
        !           420:                if (!nhoriz) return self;
        !           421:                
        !           422:                fp = &horizLines[hcount].pos;
        !           423:                oldPos = *fp;
        !           424:                *fp += 1;
        !           425:                if (*fp > viewHeight) *fp = 0;
        !           426:                horizLines[hcount].hue += 0.005;
        !           427:                if (horizLines[hcount].hue > 1) horizLines[hcount].hue -= 1;
        !           428:                
        !           429: 
        !           430:                horizLineWithAvoidance(0, *fp, viewWidth, *fp, horizLines[hcount].hue, 1, &avoid);
        !           431:                horizLineWithAvoidance(0, oldPos, viewWidth, oldPos, 0, 0, &avoid);
        !           432: 
        !           433:                if (++hcount >= nhoriz) hcount = 0;
        !           434:        }
        !           435:        
        !           436:        return self;
        !           437: }
        !           438: 
        !           439: void horizLineWithAvoidance(float x1, float y1, float x2,float y2,
        !           440:                        float hue,float brightness, const NXRect *r)
        !           441: {
        !           442:        if (y1 <= r->origin.y || y1 >= r->origin.y+r->size.height)
        !           443:                colorLine(x1, y1, x2, y2, hue, brightness);
        !           444:        else
        !           445:        {
        !           446:                colorLine(x1, y1, r->origin.x, y2, hue, brightness);
        !           447:                colorLine(r->origin.x+r->size.width, y1, x2, y2, hue, brightness);
        !           448:        }
        !           449: }
        !           450: 
        !           451: void verticalLineWithAvoidance(float x1, float y1, float x2,float y2,
        !           452:                        float hue,float brightness, const NXRect *r)
        !           453: {
        !           454:        if (x1 <= r->origin.x || x1 >= r->origin.x+r->size.width)
        !           455:                colorLine(x1, y1, x2, y2, hue, brightness);
        !           456:        else
        !           457:        {
        !           458:                colorLine(x1, y1, x2, r->origin.y, hue, brightness);
        !           459:                colorLine(x1, r->origin.y+r->size.height, x2, y2, hue, brightness);
        !           460:        }
        !           461: }
        !           462: 
        !           463: - drawLinesInBuffer
        !           464: {
        !           465:        NXRect avoid;
        !           466:        int i;
        !           467:                
        !           468:        avoid.origin = redrawTo;
        !           469:        avoid.size = redraw.size;
        !           470: 
        !           471:        for (i=0; i<nvert; i++)
        !           472:        {
        !           473:                float x = vertLines[i].pos;
        !           474: 
        !           475:                if (x >= avoid.origin.x && x <= avoid.origin.x + avoid.size.width)
        !           476:                {
        !           477:                        colorLine(x-redrawTo.x, 0, x-redrawTo.x, avoid.size.height, vertLines[i].hue, 1);
        !           478:                }
        !           479:        }
        !           480:        
        !           481:        for (i=0; i<nhoriz; i++)
        !           482:        {
        !           483:                float y = horizLines[i].pos;
        !           484: 
        !           485:                if (y >= avoid.origin.y && y <= avoid.origin.y + avoid.size.height)
        !           486:                {
        !           487:                        colorLine(0, y-redrawTo.y, avoid.size.width, y-redrawTo.y, horizLines[i].hue, 1);
        !           488:                }
        !           489:        }
        !           490:        
        !           491:        return self;
        !           492: }
        !           493: 
        !           494: - inspector:sender
        !           495: {
        !           496:     return [sender boinkInspector];
        !           497: }
        !           498: 
        !           499: 
        !           500: 
        !           501: @end
        !           502: 
        !           503: 
        !           504: 
        !           505: 
        !           506: 
        !           507: 
        !           508: 

unix.superglobalmegacorp.com

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