Annotation of Examples/AppKit/Lines/LinesView.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * LinesView.m, a small sample view for showing timed entries & userpaths.
                      3:  * Author: Ali T. Ozer, NeXT Computer, Inc.
                      4:  * Written March 19, 1989.
                      5:  * Updated for 2.0 Oct 16, 1990 by Jayson Adams to use UserPath.[hm].
                      6:  * Updated for 3.0 March 24, 1992 by Ali Ozer
                      7:  *
                      8:  * You may freely copy, distribute and reuse the code in this example.
                      9:  * NeXT disclaims any warranty of any kind, expressed or implied, as to its
                     10:  * fitness for any particular use.
                     11:  *
                     12:  * LinesView draws a number of connected lines whose endpoints bounce around
                     13:  * randomly within the bounds of the view. The endpoints are stored in
                     14:  * an data array which is passed to PostScript as a user path. The
                     15:  * animation is performed by calling the "animate" method as often as
                     16:  * possible through a timed entry.
                     17:  */
                     18: 
                     19: #import <appkit/appkit.h>
                     20: #import <libc.h>                // For random(), etc...
                     21: #import <dpsclient/wraps.h>    // For PS and DPS function prototypes
                     22: #import "LinesView.h"
                     23: 
                     24: #define RANDINT(n) (random() % (n+1))          // Return random integer 0..n
                     25: 
                     26: #define XVEL corners[count].xVel  // Some slimy shortcuts, asuuming we're
                     27: #define YVEL corners[count].yVel  // using "count" as corner counter.
                     28: #define XLOC corners[count].xLoc
                     29: #define YLOC corners[count].yLoc
                     30: 
                     31: #define MAXVEL 12              // Maximum velocity of corners
                     32: 
                     33: 
                     34: @implementation LinesView
                     35: 
                     36: - initFrame:(NXRect *)rect
                     37: {
                     38:     [super initFrame:rect];
                     39: 
                     40:   /* create a user path */
                     41:     userPath = newUserPath();
                     42:     
                     43:     running = NO;
                     44: 
                     45:     return self;
                     46: }
                     47: 
                     48: - free
                     49: {
                     50:   /* be sure to stop the timed entry */
                     51:     if (running) {
                     52:        DPSRemoveTimedEntry(linesTimedEntry);
                     53:     }
                     54:     freeUserPath(userPath);
                     55:     
                     56:     return [super free];
                     57: }
                     58: 
                     59: void DrawIt(DPSTimedEntry te, double timeNow, void *data)
                     60: {
                     61:   /* we set data to self so we can call this method from the timed entry */
                     62:     [(id)data animate];
                     63: }
                     64: 
                     65: - toggleRun:sender
                     66: {
                     67:   /* start or stop the timed entry (we're called by a two-state button) */
                     68:     if (running) {
                     69:        DPSRemoveTimedEntry(linesTimedEntry);
                     70:        running = NO;
                     71:     } else {
                     72:       /* Call the DrawIt() function as often as possible... */
                     73:        linesTimedEntry = DPSAddTimedEntry(0.0, &DrawIt, self,
                     74:                                           NX_BASETHRESHOLD);
                     75:        running = YES;
                     76:     }
                     77: 
                     78:     return self;
                     79: }
                     80: 
                     81: /*
                     82:  * This method should be connected to a UI object capable of generating
                     83:  * int numbers. Note that to successfully detect the initial value of this
                     84:  * slider as set through IB, we also declare an outlet named "numberOfCorners,"
                     85:  * and connect it to this UI object. Thus this method (setNumberOfCorners:)
                     86:  * gets called when the .nib is being loaded, and we can detect the
                     87:  * initial value of the slider.  Because at initialization time the window
                     88:  * isn't up yet, we won't really update the display at that time, even though
                     89:  * display is called below.
                     90:  */
                     91: - setNumberOfCorners:sender
                     92: {
                     93:     int           count;
                     94:     int    oldNumCorners = numCorners;
                     95: 
                     96:   /* set the number of corners based on the "corners" slider */
                     97:     numCorners = MIN(MAXNUMCORNERS, MAX([sender intValue], MINNUMCORNERS));
                     98: 
                     99:   /* set the new corner starting positions & velocities */
                    100:     for (count = oldNumCorners; count < numCorners; count++) {
                    101:       XLOC = (int)(bounds.size.width) / 2;      
                    102:       YLOC = (int)(bounds.size.height) / 2;      
                    103:       XVEL = (RANDINT(4) ? 1 : -1) * (1 + RANDINT(MAXVEL/2));
                    104:       YVEL = (RANDINT(4) ? 1 : -1) * (1 + RANDINT(MAXVEL/2));
                    105:     }
                    106:     [self display];
                    107: 
                    108:     return self;
                    109: }
                    110: 
                    111: - drawSelf:(const NXRect *)rects :(int)rectCount
                    112: {
                    113:     int          count;
                    114:     
                    115:   /* fill with the background color */
                    116:     NXEraseRect(&bounds);
                    117:     
                    118:     PSsetgray(NX_BLACK);
                    119:     PSsetlinewidth(0.0);
                    120: 
                    121:   /* "plot" the points */
                    122:     beginUserPath(userPath, NO);
                    123:     for (count = 0; count < numCorners; count++) {
                    124:        if (count) {
                    125:            UPlineto(userPath, XLOC, YLOC);
                    126:        } else {
                    127:            UPmoveto(userPath, XLOC, YLOC);
                    128:        }
                    129:     }
                    130:     closePath(userPath);
                    131:     
                    132:   /* draw it */
                    133:     endUserPath(userPath, dps_ustroke);
                    134:     sendUserPath(userPath);
                    135:     
                    136:     return self;
                    137: }
                    138: 
                    139: - animate
                    140: /*
                    141:  * Lines is an unusual animation program in that it runs untimed; that is,
                    142:  * it runs as fast as the CPU will allow, and it doesn't care that on faster
                    143:  * CPUs the animation will run faster. An animation or game application
                    144:  * will usually want to limit to frame rate to a value (for instance, 30
                    145:  * frames a second), and on hardware not capable of that rate, end up doing
                    146:  * the best it can. Such an application would also look at the time
                    147:  * that actually passed between frames and increment the animation or game play
                    148:  * accordingly. (See the sources to the BreakApp example on how it does it
                    149:  * animation timing. BreakApp also allocates a graphic state for its view so
                    150:  * that the lock/unlockFocus is faster.)
                    151:  *
                    152:  * Lines accomplishes its goal of running as fast as possible by creating
                    153:  * a timed entry with a 0.0 second period. This means that the timed entry
                    154:  * will fire and this method (animate) will be called as soon as possible.
                    155:  * To make things even faster, we stay in this method until some event comes
                    156:  * along. Staying in this method has the advantage that we do not need to
                    157:  * lock or unlockFocus every frame. Of course, this only works as desired
                    158:  * if the timed entry was placed with a period of 0.0 seconds.
                    159:  * 
                    160:  * If an event comes along, we return from this method and process the event.
                    161:  * Then, unless the user stopped the animation, the timed entry brings us
                    162:  * right back in to continue with the animation.
                    163:  *
                    164:  * Lines uses a buffered output window as a means to fake double-buffered
                    165:  * animation. The current frame is drawn directly into the window. However,
                    166:  * because the window is buffered, the drawing goes to the backing store,
                    167:  * and not the screen.  Only when the frame is complete does Lines flush the
                    168:  * window contents to the screen; this process is fast and provides a
                    169:  * flicker-free update.  The next frame is then drawn into the backing store,
                    170:  * and the cycle continues.
                    171:  */
                    172: {
                    173:     int count;  
                    174:     NXEvent dummyEvent;  // For peeking at the event queue. 
                    175:     
                    176:     [self lockFocus];
                    177:     
                    178:     do {
                    179:       /* move all the corners... */
                    180:        for (count = 0; count < numCorners; count++) {
                    181:            XLOC += XVEL;
                    182:            YLOC += YVEL;
                    183: 
                    184:          /*
                    185:           * Detect collision with sides; if we collide, bounce back in some
                    186:           * random fashion.
                    187:           */
                    188:            if (XLOC >= bounds.size.width) {
                    189:                XLOC = bounds.size.width-1;
                    190:                XVEL = -1-RANDINT(MAXVEL);
                    191:            } else if (XLOC < bounds.origin.x) {
                    192:                XLOC = bounds.origin.x;
                    193:                XVEL = 1+RANDINT(MAXVEL);
                    194:            }
                    195:            if (YLOC >= bounds.size.height) {
                    196:                YLOC = bounds.size.height-1;
                    197:                YVEL = -1-RANDINT(MAXVEL);
                    198:            } else if (YLOC < bounds.origin.y) {
                    199:                YLOC = bounds.origin.y;
                    200:                YVEL = 1+RANDINT(MAXVEL);
                    201:            }
                    202:        }
                    203: 
                    204:       /* draw our path and flush to the screen */
                    205:        [self drawSelf:&bounds :1];
                    206:        [window flushWindow];
                    207:        
                    208:     } while ([NXApp peekNextEvent:NX_ALLEVENTS
                    209:                    into:&dummyEvent 
                    210:                    waitFor:0.0
                    211:                    threshold:NX_BASETHRESHOLD] == NULL);
                    212: 
                    213:     [self unlockFocus];
                    214: 
                    215:     return self;
                    216: }
                    217: 
                    218: @end

unix.superglobalmegacorp.com

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