home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Connectivity / GateKeeper-2.1 / SpaceView.m < prev    next >
Encoding:
Text File  |  1996-10-27  |  12.3 KB  |  589 lines

  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 "psfuncts.h"
  12.  
  13. #import <appkit/Application.h>
  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.  
  25.         // used in producing timed events
  26. static void AnimateSpace();
  27. static void AnimateSpaceIT();
  28.  
  29.  
  30.         // This should return a float between 0 and 1
  31. float frandom()
  32. {
  33.     float val = (random() & 0x7fffffff);
  34.     val /= 0x7fffffff;
  35.     return val;
  36. }
  37. float randBetween(float a, float b)
  38. {
  39.     float val, scale, t;
  40.  
  41.     if (a > b)
  42.     {    t = a; a = b; b = t;
  43.     }
  44.     
  45.     scale = (b-a);
  46.     val = scale * frandom();
  47.     return (a + val);
  48. }
  49.  
  50. @implementation SpaceView
  51.  
  52.         //takes theta and distance and stuffs it into x &y for *p
  53. - convertToXY:(STAR *)p
  54. {
  55.     p->draw->x = floor(bounds.size.width / 2 + (p->distance * cos(p-> theta)));
  56.     p->draw->y = floor(bounds.size.height / 2 + (p->distance * sin(p-> theta)));
  57.     return self;
  58. }
  59.  
  60. - oneStep
  61. {
  62.     int i, count, starsInArray = 0;
  63.     STAR *p;
  64.     NXPoint *t;
  65.     
  66.     if (nstars < NSTARS) [self addStar];
  67.  
  68.     for (i=0; i<nstars; i++)
  69.     {
  70.         p = &stars[i];
  71.         p->distance += p->delta;
  72.         p->delta *= p->ddelta;
  73.  
  74.         [self convertToXY:p];
  75.  
  76.         // only draw the star if it moved > 1 pixel
  77.         if (p->draw->x != p->erase->x || 
  78.             p->draw->y != p->erase->y)
  79.         {
  80.             BOOL mustErase = NO;
  81.             // add star to the erasure array
  82.             b[starsInArray] = *p->erase;
  83.             bc[starsInArray] = p->c;
  84.  
  85.             if (p->distance > p->changepoint[p->changemode])
  86.             {
  87.                 (p->c)++;    // increment character for next star size
  88.                 (p->changemode)++;
  89.             }
  90.  
  91.             // clipping is off, so we must not draw outside view.
  92.             // replace stars that go too far...
  93.             if (p->draw->x < 0 ||
  94.                 p->draw->y < 0 ||
  95.                 p->draw->x + 7 > bounds.size.width ||
  96.                 p->draw->y + 7 > bounds.size.height)
  97.             {
  98.                 [self replaceStarAt:i];
  99.                 mustErase = YES;
  100.             }
  101.  
  102.             w[starsInArray] = *p->draw;
  103.             wc[starsInArray] = p->c;
  104.             
  105.             if (mustErase || [self allowStars:p]) starsInArray++;
  106.         
  107.             t = p->draw; p->draw = p->erase; p->erase = t;
  108.         }
  109.     }
  110.  
  111.     bc[starsInArray] = wc[starsInArray] = 0;    //null terminate string
  112.     if (starsInArray)
  113.     {
  114.         for (i=0; i<(starsInArray-1); i++)
  115.         {
  116.             bOffsets[i].x = b[i+1].x - b[i].x;
  117.             bOffsets[i].y = b[i+1].y - b[i].y;
  118.             wOffsets[i].x = w[i+1].x - w[i].x;
  119.             wOffsets[i].y = w[i+1].y - w[i].y;
  120.         }
  121.         bOffsets[i].x = bOffsets[i].y = wOffsets[i].x = wOffsets[i].y = 0;
  122.  
  123.         count = 0;
  124.         while (count < starsInArray)
  125.         {    char tc;
  126.             int j;
  127.             // You get the best performance if you put out all the stars
  128.             // at once.  This causes noticable flicker, so I put out 
  129.             // 100 of the stars per iteration.  This gives reasonable speed
  130.             // and flicker is hardly noticable.  Besides, stars
  131.             // _should_ flicker a little...
  132.         
  133.             int t = (starsInArray - count);
  134.             i = (t < STARSPERIT)?t:STARSPERIT;
  135.             j = i + count;
  136.             
  137.             PSsetgray(NX_BLACK);
  138.             tc = bc[j]; bc[j] = 0;
  139.             PSWXYShow(b[count].x, b[count].y, &bc[count], 
  140.                 (float *)(&bOffsets[count].x), i*2);
  141.             bc[j] = tc;
  142.             
  143.             PSsetgray(NX_WHITE);
  144.             tc = wc[j]; wc[j] = 0;
  145.             PSWXYShow(w[count].x, w[count].y, &wc[count], 
  146.                 (float *)(&wOffsets[count].x), i*2);
  147.             wc[j] = tc;
  148.             
  149.             count += STARSPERIT;
  150.         }
  151.     }
  152.  
  153.     return self;
  154. }
  155.  
  156.         // returns yes if the star is outside the avoidance rectangle
  157.         // this is really fast and loose but it works acceptibly well
  158.         // ps I could just use NXIntersectsRect() but I want to avoid
  159.         // trap overhead.  Call me paranoid...
  160. - (BOOL) allowStars:(const STAR *)p
  161. {
  162.                 // just return if voidRect not set
  163.     if ((!voidRect.size.width) ||
  164.         p->draw->x < voidRect.origin.x ||
  165.         p->draw->y < voidRect.origin.y ||
  166.         p->draw->x+7 > voidRect.origin.x+voidRect.size.width ||
  167.         p->draw->y+7 > voidRect.origin.y+voidRect.size.height ||
  168.  
  169.         p->erase->x < voidRect.origin. x ||
  170.         p->erase->y < voidRect.origin. y ||
  171.         p->erase->x+7 > voidRect.origin.x+voidRect.size.width ||
  172.         p->erase->y+7 > voidRect.origin.y+voidRect.size.height) return YES;
  173.  
  174.     return NO;
  175. }
  176.  
  177. - initFrame:(const NXRect *)frameRect
  178. {
  179.     [super initFrame:frameRect];
  180.     [self allocateGState];        // For faster lock/unlockFocus
  181.     [self setClipping:NO];        // even faster...
  182.     [self setRadius];
  183.     loadPSProcedures();
  184.     PSWDefineFont("StarFont");
  185.  
  186.     return self;
  187. }
  188.  
  189. - drawSelf:(const NXRect *)rects :(int)rectCount
  190. {
  191.     // this drawself doesn't really draw the view at all.
  192.     // in fact it just promotes the window to screen depth...
  193.  
  194.     NXRect t = {0,0,1,1};
  195.  
  196.     PSsetrgbcolor(1,0,0);
  197.     NXRectFill(&t);    //yucky trick for window depth promotion!
  198.     PSsetgray(NX_BLACK); NXRectFill(&t);
  199.  
  200.     PSselectfont("StarFont", 1.0);
  201.  
  202.     return self;
  203. }
  204.  
  205. - sizeTo:(NXCoord)width :(NXCoord)height
  206. {
  207.     [super sizeTo:width :height];
  208.  
  209.     if (oldSize.width != bounds.size.width ||
  210.             oldSize.height != bounds.size.height)
  211.     {
  212.         oldSize.width = bounds.size.width;
  213.         oldSize.height = bounds.size.height;
  214.         [self setRadius];
  215.         nstars = 0;
  216.         [self display];
  217.     }
  218.     
  219.     return self;
  220. }
  221.  
  222.         // only call addStar if there is room in the stars array!
  223. - addStar
  224. {
  225.     [self replaceStarAt:nstars++];
  226.     return self;
  227. }
  228.  
  229. - replaceStarAt:(int)index
  230. {
  231.     float dist, t;
  232.     int tries = 0;
  233.     STAR *p = &stars[index];
  234.     BOOL inBounds;
  235.  
  236.     p->draw = &p->r1;
  237.     p->erase = &p->r2;
  238.  
  239.     
  240.     do {
  241.         p->theta = randBetween(0,(2*PI));
  242.  
  243.         if (tries++ < 3) p->distance = randBetween(1, radius);
  244.         else p->distance = randBetween(1, p->distance);
  245.  
  246.         inBounds = YES;
  247.         [self convertToXY:p];
  248.  
  249.         if (p->draw->x < 0 || p->draw->y < 0 ||
  250.             p->draw->x + 7 > bounds.size.width ||
  251.             p->draw->y + 7 > bounds.size.height)
  252.         {
  253.             inBounds = NO;
  254.         }
  255.     } while (!inBounds);
  256.  
  257.     p->delta = (0.1);
  258.  
  259.     p->ddelta = randBetween(1.0, 1.1);
  260.  
  261.  
  262.  
  263.     t = randBetween(0, (0.42*radius));
  264.     dist = MAX(20,t);
  265.     p->changepoint[0] = p->distance + 5;            // to b
  266.     p->changepoint[1] = p->changepoint[0] - 5 + dist + dist;    // to c
  267.  
  268.  
  269.     p->changepoint[2] = p->changepoint[1] + dist;    // to d
  270.     p->changepoint[3] = p->changepoint[2] + dist;    // to e
  271.     p->changepoint[4] = p->changepoint[3] + dist;    // to f
  272.     p->changepoint[5] = 100000;                        // never change to g
  273.  
  274.     p->changemode = 0;
  275.     
  276.     if ((++toggle) & 1) p->c = 'a';
  277.     else p->c = 'g';
  278.  
  279.     p->r2 = p->r1;
  280.  
  281.     return self;
  282. }
  283.  
  284. - setRadius
  285. {
  286.     float x = bounds.size.width;
  287.     float y = bounds.size.height;
  288.     radius = (sqrt(x*x + y*y))/2;
  289.     return self;
  290. }
  291.  
  292. - (const char *)windowTitle
  293. {
  294.     return "The Final Frontier";
  295. }
  296.  
  297. - setVoidRect:(const NXRect *)r
  298. {
  299.     voidRect = *r;
  300.     return self;
  301. }
  302.  
  303. - didLockFocus
  304. {
  305.     PSselectfont("StarFont", 1.0);
  306.     return self;
  307. }
  308.  
  309. - (BOOL)useBufferedWindow
  310. {    return NO;
  311. }
  312.  
  313. - inspector:sender
  314. {
  315.     [self display];
  316.  
  317.     return self;
  318. }
  319.  
  320. - (BOOL)ignoreMouseMovement
  321. {    return NO;
  322. }
  323.  
  324. - inspectorWillBeRemoved
  325. {    return self;    // just a prototype
  326. }
  327.  
  328. - inspectorInstalled
  329. {    return self;    // just a prototype
  330. }
  331. //*****************************************************************************
  332. //
  333. //         circular clipping path 
  334. //
  335. //*****************************************************************************
  336.  
  337. - clipToFrame:(const NXRect *)frameRect
  338. {
  339. float x, y, cradius;
  340.  
  341.                     // Center the circle and pick an appropriate radius
  342.     x = frameRect->origin.x + frameRect->size.width/2.0;
  343.     y = frameRect->origin.y + frameRect->size.height/2.0;
  344.     cradius = frameRect->size.height/2.0;
  345.  
  346.                     // Create a circular clipping path
  347.     PSnewpath();
  348.     PSarc(x, y, cradius, 0.0, 360.0);
  349.     PSclosepath();
  350.     PSclip();
  351.  
  352.     return self;
  353. }
  354.  
  355.  
  356. @end
  357.  
  358.  
  359.  
  360.         // this class is only used in the inspector, it animates
  361.         // when it draws itself.
  362.  
  363. @implementation StaticSpaceView
  364.  
  365. - drawSelf:(const NXRect *)rects :(int)rectCount
  366. {
  367.     int i;
  368.     
  369.     if (!rects || !rectCount) return self;
  370.     
  371.     PSselectfont("StarFont", 1.0);
  372.  
  373.     PSsetgray(NX_BLACK);
  374.     NXRectFill(rects);
  375.     
  376.     for (i=0; i<20; i++)
  377.     {
  378.         [self oneStep];
  379.         [[self window] flushWindow];
  380.         NXPing();
  381.     }
  382.  
  383.     return self;
  384. }
  385.  
  386. - initFrame:(const NXRect *)frameRect
  387. {
  388.     [super initFrame:frameRect];
  389.     [super setClipping:YES];
  390.  
  391.     while (nstars < NSTARS) [self addStar];
  392.  
  393.     if(!aniSpaceTag)  
  394.         aniSpaceTag = DPSAddTimedEntry(            // register function Animate
  395.             0.08,                                 // to be called every period of         
  396.             (DPSTimedEntryProc)AnimateSpace,     // arg0
  397.             (id)self, 
  398.             NX_BASETHRESHOLD);
  399.  
  400.     return self;
  401. }
  402.  
  403. - sizeTo:(NXCoord)width :(NXCoord)height
  404. {
  405.     [super sizeTo:width :height];
  406.  
  407.     nstars = 0;
  408.     while (nstars < NSTARS) [self addStar];    
  409.     return self;
  410. }
  411. //************************************************************************
  412. //
  413. //         remove the timed entry when we exit
  414. //
  415. //************************************************************************
  416.  
  417. - free
  418. {
  419.     if (aniSpaceTag)  
  420.         DPSRemoveTimedEntry (aniSpaceTag);
  421.     aniSpaceTag = 0;
  422.         
  423.     return [super free];
  424. }
  425. @end
  426.  
  427. //************************************************************************
  428. //
  429. //        This fucntion is registered by DPSaddtimedentry.
  430. //        It is subsequently called every period t as registered  
  431. //        in arg 0 of DPSaddtimedentry.
  432. //
  433. //************************************************************************
  434.  
  435. static void AnimateSpace(DPSTimedEntry time_tag, double now, id self)
  436. {
  437.     [self display];
  438. }
  439.  
  440.  
  441.  
  442.  
  443. @implementation View(nonretainedFillMethod)
  444.  
  445. // I add this method as a category of View to be sure that all
  446. // my views implement it.  I really want to use nonretained windows
  447. // but they are drawn via drawSelf at all kinds of goofy times.  It
  448. // seems like the kit kind of throws up its hands when it doesn't have
  449. // a buffer to draw from, so you get a lot more drawSelfs than you need,
  450. // and sometimes you don't get them when you really want them.  I know
  451. // when I need the background filled in black, so I factor that out of
  452. // my drawSelf and then drawself only draws things that are already on
  453. // screen so you don't see it happen.  I will only call this method on
  454. // a nonretained (and full screen) window.
  455.  
  456. - fillBoundsWithBlack
  457. {
  458.     if ([self canDraw])
  459.     {
  460.         [self lockFocus];
  461.         PSsetgray(NX_BLACK);
  462.         NXRectFill(&bounds);
  463.         [self unlockFocus];
  464.     }
  465.     return self;
  466. }
  467. @end
  468.  
  469.  
  470. #import "InactivityTimer.h"
  471. #import <appkit/Application.h>
  472.  
  473.  
  474. @implementation StaticSpaceITimerView
  475.  
  476. //************************************************************************
  477. //
  478. //        sent to us after nib objects are unarchived and init'd 
  479. //
  480. //************************************************************************
  481.  
  482. - awakeFromNib
  483. {
  484.     [secTillTimeoutField setIntValue:10];
  485.  
  486.     return self;
  487. }
  488.  
  489. - initFrame:(const NXRect *)frameRect
  490. {
  491.     [super initFrame:frameRect];
  492.     [super setClipping:YES];
  493.  
  494.     while (nstars < NSTARS2) [self addStar];
  495.  
  496.     if(!aniSpaceITimerTag)  
  497.         aniSpaceITimerTag = DPSAddTimedEntry(    // register function Animate
  498.             0.08,                                 // to be called every period of         
  499.             (DPSTimedEntryProc)AnimateSpaceIT,     // arg0
  500.             (id)self, 
  501.             NX_BASETHRESHOLD);
  502.  
  503.     return self;
  504. }
  505.  
  506. - drawSelf:(const NXRect *)rects :(int)rectCount
  507. {
  508.     int i;
  509.     
  510.     if (!rects || !rectCount) return self;
  511.     
  512.     PSselectfont("StarFont", 1.0);
  513.  
  514.     PSsetgray(NX_BLACK);
  515.     NXRectFill(rects);
  516.     
  517.     for (i=0; i<20; i++)
  518.     {
  519.         [self oneStep];
  520.         [[self window] flushWindow];
  521.         NXPing();
  522.     }
  523.  
  524.     return self;
  525. }
  526.  
  527. - sizeTo:(NXCoord)width :(NXCoord)height
  528. {
  529.     [super sizeTo:width :height];
  530.  
  531.     nstars = 0;
  532.     while (nstars < NSTARS2) [self addStar];    
  533.     return self;
  534. }
  535. //************************************************************************
  536. //
  537. //         remove the timed entry when we exit
  538. //
  539. //************************************************************************
  540.  
  541. - removeTimedEntry
  542. {
  543.     if (aniSpaceITimerTag)  
  544.         DPSRemoveTimedEntry (aniSpaceITimerTag);
  545.     aniSpaceITimerTag = 0;
  546.         
  547.     return self;
  548. }
  549.  
  550. //************************************************************************
  551. //
  552. //         countdown to inactivity timeout
  553. //
  554. //************************************************************************
  555.  
  556. - countdown
  557. {
  558.     time(<ime);                        // Get time and place in time_t
  559.  
  560.     if(ltime > preltime)
  561.         {
  562.         if((seconds = [secTillTimeoutField intValue]) == 0)
  563.             [[window delegate] continue:self];
  564.         else
  565.             [secTillTimeoutField setIntValue:(seconds - 1)];
  566.         [secTillTimeoutField display];
  567.         preltime = ltime;
  568.         }
  569.         
  570.     return self;
  571. }
  572.  
  573.  
  574. @end
  575.  
  576. //************************************************************************
  577. //
  578. //        This fucntion is registered by DPSaddtimedentry.
  579. //        It is subsequently called every period t as registered  
  580. //        in arg 0 of DPSaddtimedentry.
  581. //
  582. //************************************************************************
  583.  
  584. static void AnimateSpaceIT(DPSTimedEntry time_tag, double now, id self)
  585. {
  586.     [self countdown];
  587.     [self display];
  588. }
  589.