home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / AppKit / BackspaceViews / Sperm / SpermView.m < prev    next >
Text File  |  1992-04-06  |  10KB  |  457 lines

  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 UC7g 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. #ifdef VANNA
  22. #import <math.h>
  23. #import <libc.h>
  24. #import <dpsclient/wraps.h>        // For PS and DPS function prototypes
  25. #import <appkit/color.h>        // For color stuff
  26. #import <appkit/nextstd.h>        // For MIN MAX
  27. #import <appkit/Button.h>        // intValue, etc
  28. #import <appkit/Application.h>  // For NX_BASETHRESHOLD and peek event
  29. #import <appkit/Window.h>
  30. #import <defaults/defaults.h>
  31. #endif
  32.  
  33. #define VEC_DOT(x, y) (x[0]*y[0] + x[1]*y[1])
  34. #define VEC_LEN(x) (sqrt(x[0]*x[0] + x[1]*x[1]))
  35.  
  36. #define VEC_SET(x, a, b) x[0] = a, x[1] = b
  37. #define VEC_COPY(y, x) y[0] = x[0], y[1] = x[1]
  38. #define VEC_NEG(x) x[0] = -x[0], x[1] = -x[1]
  39. #define VEC_ADD(z, x, y) z[0] = x[0] + y[0], z[1] = x[1] + y[1]
  40. #define VEC_SUB(z, x, y) z[0] = x[0] - y[0], z[1] = x[1] - y[1]
  41. #define VEC_MULT(x, a) x[0] *= a, x[1] *= a
  42. #define VEC_DIV(x, a) x[0] /= a, x[1] /= a
  43. #define VEC_ADDS(z, x, a, y) z[0] = x[0] + (a)*y[0], z[1] = x[1] + (a)*y[1]
  44. #define VEC_NORM(x) { double l = VEC_LEN(x); VEC_DIV(x, l); }
  45.  
  46. #define MINRAD 0.1
  47. #define RADSTEP 2.0
  48. #define MAXRAD (MINRAD * RADSTEP * RADSTEP * RADSTEP * RADSTEP * RADSTEP * RADSTEP)
  49. #define INITRAD (MINRAD * RADSTEP * RADSTEP * RADSTEP)
  50.  
  51. // RANDINT(n) returns an integer 0..n-1
  52. // RANDFLOAT(f) returns a float [0..f] (inclusive on both ends)
  53.  
  54. #define RANDINT(n) (random() % (n))
  55. #define RANDFLOAT(f) (((f) * (float)(random() & 0x0ffff)) / (float)0x0ffff)
  56.  
  57. @implementation SpermView
  58.  
  59. - initFrame:(const NXRect *)rect
  60. {
  61.     [super initFrame:rect];
  62.  
  63.     [self allocateGState];        // For faster lock/unlockFocus
  64.  
  65.     dir = 1.0;
  66.     rad = INITRAD;
  67.     [self getSpermCount];
  68.     [self getLineWidth];
  69.     [self getUseColor];
  70.     [inspectorPanel display];
  71.  
  72.     color = NX_COLORWHITE;
  73.     alreadyInitialized = NO;
  74.     randCount1 = 100;
  75.     randCount2 = 200;
  76.     
  77.     uPath = newUserPath();
  78.  
  79.     return self;
  80. }
  81.  
  82. - (void)initializeLine:(int)i
  83. {
  84.     double angle = RANDFLOAT(10.0) + 5.0;
  85.     prevX[i][0] = x[i][0] = (double) (RANDINT((int)NX_WIDTH(&bounds)));
  86.     prevX[i][1] = x[i][1] = (double) (RANDINT((int)NX_HEIGHT(&bounds)));
  87.     v[i][0] = RANDFLOAT(2.0) - 1.0;
  88.     v[i][1] = RANDFLOAT(2.0) - 1.0;    
  89.     sine[i] = sin(angle*M_PI/180.0);
  90.     cosine[i] = cos(angle*M_PI/180.0);
  91.     vel[UC8 RANDFLOAT(4.0) + 4.0;
  92.     VEC_NORM(v[i]);
  93. }
  94.  
  95. - (void)getFocusFromEvent:(NXEvent *)event
  96. {
  97.     NXPoint loc = event->location;
  98.     [self convertPoint:&loc fromView:nil];
  99.     mouse[0] = loc.x;
  100.     mouse[1] = loc.y;
  101. }
  102.  
  103. - (BOOL)acceptsFirstMouse
  104. {    return YES;
  105. }
  106.  
  107. - mouseDown:(NXEvent *)event
  108. {
  109.     [self getFocusFromEvent:event];
  110.     return self;
  111. }
  112.  
  113. - effectOne
  114. {
  115.     VECTOR y;
  116.     int i;
  117.  
  118.     dir *= -1.0;
  119.     for (i = 0; i < MAXCOUNT; i++) {
  120.     VEC_COPY(y, v[i]);
  121.     if (dir == -1.0) {
  122.         v[i][0] = y[1];
  123.         v[i][1] = -y[0];
  124.     } else {
  125.         v[i][0] = -y[1];
  126.         v[i][1] = y[0];
  127.     }
  128.     }
  129.     return self;
  130. }
  131.  
  132. - effectTwo
  133. {
  134.     int i;
  135.     for (i = 0; i < MAXCOUNT; i++) {
  136.     v[i][0] = -v[i][0];
  137.     }
  138.     return self;
  139. }
  140.  
  141. - effectThree
  142. {
  143.     int i;
  144.     for (i = 0; i < MAXCOUNT; i++) {
  145.     v[i][1] = -v[i][1];
  146.     }
  147.     return self;
  148. }
  149.  
  150. - effectFour
  151. {
  152.     [self effectTwo];
  153.     [self effectThree];
  154.     return self;
  155. }
  156.  
  157. - effectFive
  158. {
  159.     [self effectOne];
  160.     [self effectFour];
  161.     return self;
  162. }
  163.  
  164. - effectSix
  165. {
  166.     rad = MIN(rad * RADSTEP, MAXRAD);
  167.     return self;
  168. }
  169.  
  170. - effectSeven
  171. {
  172.     rad = MAX(rad / RADSTEP, MINRAD);
  173.     return self;
  174. }
  175.  
  176. - doEffectNumber:(int)val
  177. {
  178.     switch (val) {
  179.     case 0: [self effectOne]; break;
  180.     case 1: [self effectTwo]; break;
  181.     case 2: [self effectThree]; break;
  182.     case 3: [self effectFour]; break;
  183.     case 4: [self effectFive]; break;
  184.     case 5: [self effectSix]; break;
  185.     case 6: [self effectSeven]; break;
  186.     default: break;
  187.     }
  188.     return self;
  189. }
  190.  
  191. - oneStep
  192. {
  193.     int i, cnt;
  194.         POINT lLeft, uRight;
  195.     NXRect eraseRect;
  196.  
  197.     uRight[0] = lLeft[0] = x[0][0];
  198.     uRight[1] = lLeft[1] = x[0][1];
  199.  
  200.     for (i = 0; i < count; i++) {
  201.         VECTOR w, y;
  202.         POINT p;
  203.         double r;
  204.  
  205.         for (cnt = 0; cnt < 2; cnt++) {
  206.             if (prevX[i][cnt] < lLeft[cnt]) lLeft[cnt] = prevX[i][cnt];
  207.             else if (prevX[i][cnt] > uRight[cnt]) uRight[cnt] = prevX[i][cnt];
  208.             if (x[i][cnt] < lLeft[cnt]) lLeft[cnt] = x[i][cnt];
  209.             else if (x[i][cnt] > uRight[cnt]) uRight[cnt] = x[i][cnt];
  210.         }
  211.  
  212.         prevX[i][0] = x[i][0];    /* old location */
  213.         prevX[i][1] = x[i][1];
  214.     
  215.         VEC_SUB(w, x[i], mouse);
  216.         VEC_NORM(w);
  217.         VEC_COPY(y, w);
  218.         w[0] = y[0]*cosine[i] - dir*y[1]*sine[i];
  219.         w[1] = y[1]*cosine[i] + dir*y[0]*sine[i];
  220.         VEC_ADDS(p, mouse, rad*(160.0 - vel[i]*20.0), w);
  221.     
  222.         VEC_SUB(w, p, x[i]);
  223.         r = VEC_LEN(w);
  224.         VEC_DIUC9 r);
  225.     
  226.         VEC_ADDS(v[i], v[i], 1.0, w);
  227.     
  228.         VEC_NORM(v[i]);
  229.         VEC_MULT(v[i], vel[i]);
  230.     
  231.         VEC_ADD(x[i], x[i], v[i]);
  232.  
  233.     }
  234.  
  235.     NXSetRect (&eraseRect, lLeft[0], lLeft[1], uRight[0]-lLeft[0], uRight[1]-lLeft[1]);
  236.     NXInsetRect (&eraseRect, -1.0-lineWidth, -1.0-lineWidth);
  237.     PSsetgray(0);
  238.     NXRectFill(&eraseRect);
  239.  
  240.     [self drawPath];
  241.  
  242.     if (--randCount1 < 0)
  243.     {
  244.         randCount1 = RANDINT(700);
  245.         mouse[0] = randBetween(0,bounds.size.width);
  246.         mouse[1] = randBetween(0,bounds.size.height);
  247.     }
  248.     if (--randCount2 < 0)
  249.     {
  250.         randCount2 = RANDINT(600);
  251.         [self doEffectNumber:(randCount2 % 7)];
  252.     }
  253.     return self;
  254. }
  255.  
  256. // Modify "orig" by upto plus or minus "by" keeping it in the specified range...
  257.  
  258. static float randMod(float orig, float by, float min, float max)
  259. {
  260.     orig = orig + RANDFLOAT(by * 2.0) - by;
  261.     return (orig < min) ? min : ((orig > max) ? max : orig);
  262. }
  263.  
  264. - drawPath
  265. {
  266.     int cnt;
  267.  
  268.     PSsetlinewidth (lineWidth);
  269.     if (useColors) {
  270.     color = NXConvertRGBToColor(randMod(NXRedComponent(color), 0.05, 0.0, 1.0),
  271.         randMod(NXGreenComponent(color), 0.05, 0.0, 1.0), 
  272.         randMod(NXBlueComponent(color), 0.05, 0.0, 1.0));
  273.     }
  274.     else color = NX_COLORWHITE;
  275.     
  276.     NXSetColor (color);
  277.  
  278.     beginUserPath(uPath, NO);
  279.     for (cnt = 0; cnt < count; cnt++) {
  280.     UPmoveto(uPath, (float)prevX[cnt][0], (float)prevX[cnt][1]);
  281.     UPlineto(uPath, (float)x[cnt][0], (float)x[cnt][1]);
  282.     }
  283.     closePath(uPath);
  284.     endUserPath(uPath, dps_ustroke);
  285.     sendUserPath(uPath);
  286.  
  287.     return self;
  288. }
  289.     
  290. - drawSelf:(const NXRect *)rects :(int)rectCount
  291. {
  292.     if (!rects || !rectCount) return self;
  293.     
  294.     PSsetgray(NX_BLACK);
  295.     NXRectFill(rects);
  296.     [self drawPath];
  297.     return self;
  298. }
  299.  
  300. - newWindow
  301. {
  302.     mouse[0] = randBetween(0,bounds.size.width);
  303.     mouse[1] = randBetween(0,bounds.size.height);
  304.  
  305.     return self;
  306. }
  307.  
  308. - free
  309. {
  310.     freeUserPath(uPath);
  311.     return [super free];
  312. }
  313.  
  314. - setNumLines:sender
  315. {
  316.     int       i;
  317.     int    oldCount = count;
  318.     char str[100];
  319.  
  320.     // set the number of lines
  321.     count = MIN(MAXCOUNT, MAX([sender intValue], 1));
  322.  
  323.     // initialize velocities & such
  324.     for (i = oldCount; i < count; i++) {
  325.         [self initializeLine:i];
  326.     }
  327.  
  328.     [self display];
  329.  
  330.     sprintf(str,"%d", count);
  331.     NXWriteDefault([NXApp appName], "SpermViewCount", str);
  332.  
  333.     return self;
  334. }
  335.  
  336. - getSpermCount
  337. {
  338.     const char *ptr;
  339.     int val;
  340.  
  341.     [spermCountSlider setMinUC@e: 10];
  342.     [spermCountSlider setMaxValue: MAXCOUNT];
  343.     
  344.     ptr = NXGetDefaultValue([NXApp appName], "SpermViewCount");
  345.     if (ptr)
  346.     {
  347.         sscanf(ptr,"%d",&val);
  348.         if (val >= 10 && val <= MAXCOUNT) count = val;
  349.         else count = MAXCOUNT;
  350.     }
  351.     else count = MAXCOUNT;
  352.     
  353.     return self;
  354. }
  355.  
  356. - setUseColor:sender
  357. {
  358.     useColors = [sender state];
  359.  
  360.     if (useColors)
  361.         NXWriteDefault([NXApp appName], "SpermViewColor", "Yes");
  362.     else
  363.         NXRemoveDefault([NXApp appName], "SpermViewColor");
  364.  
  365.     return self;
  366. }
  367.  
  368. - getUseColor
  369. {
  370.     const char *ptr;
  371.     
  372.     ptr = NXGetDefaultValue([NXApp appName], "SpermViewColor");
  373.  
  374.     if (!ptr || !strcmp(ptr,"No")) useColors = NO;
  375.     else useColors = YES;
  376.     
  377.     return self;
  378. }
  379.  
  380. - setLineWidth:sender
  381. {
  382.     char str[50];
  383.  
  384.     lineWidth = MAX([sender floatValue], 0.0);
  385.     sprintf(str,"%5.1f", lineWidth);
  386.     NXWriteDefault([NXApp appName], "SpermViewWidth", str);
  387.  
  388.     return self;
  389. }
  390.  
  391. - getLineWidth
  392. {
  393.     const char *ptr;
  394.     float val;
  395.  
  396.     [spermWidthSlider setMinValue: 0];
  397.     [spermWidthSlider setMaxValue: 8];
  398.     
  399.     ptr = NXGetDefaultValue([NXApp appName], "SpermViewWidth");
  400.     if (ptr)
  401.     {
  402.         sscanf(ptr,"%f",&val);
  403.         if (val >= 0 && val <= 8) lineWidth = val;
  404.         else lineWidth = 0;
  405.     }
  406.     else lineWidth = 0;
  407.     
  408.     return self;
  409. }
  410.  
  411. - sizeTo:(NXCoord)width :(NXCoord)height
  412. {
  413.     [super sizeTo:width :height];
  414.     
  415.     if (!alreadyInitialized)
  416.     {    int i;
  417.         mouse[0] = NX_MIDX(&bounds);
  418.         mouse[1] = NX_MIDY(&bounds);
  419.  
  420.         for (i = 0; i < MAXCOUNT; i++) {
  421.             [self initializeLine:i];
  422.         }
  423.         alreadyInitialized = YES;
  424.     }
  425.  
  426.     [self newWindow];
  427.     return self;
  428. }
  429.  
  430. - (const char *)windowTitle
  431. {    return "Sperm";
  432. }
  433.  
  434. - (BOOL) useBufferedWindow;
  435. {    return YES;
  436. }
  437.  
  438.  
  439. - inspector:sender
  440. {
  441.     char buf[MAXPATHLEN];
  442.     
  443.    UC2(!inspectorPanel)
  444.     {
  445.         // [NXApp loadNibSection:"sperm.nib" owner:self withNames:NO];
  446.         sprintf(buf,"%s/sperm.nib",[sender moduleDirectory:"Sperm"]);
  447.         [NXApp loadNibFile:buf owner:self withNames:NO];
  448.  
  449.         [spermCountSlider setIntValue:count];
  450.         [spermWidthSlider setFloatValue:lineWidth];
  451.         [colorButton setState: (useColors ? 1:0)];
  452.     }
  453.     return inspectorPanel;
  454. }
  455.  
  456. @end
  457.