home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CAnimCursor / CQixableCursor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  7.5 KB  |  374 lines  |  [TEXT/KAHL]

  1. /*
  2.  * CQixableCursor.c
  3.  * A subclass of CAnimCursor;  draws a "Qix" over your B&W cursors.
  4.  * Version 1.0, 13 May 1992
  5.  *
  6.  * by Jamie McCarthy
  7.  * Internet: k044477@kzoo.edu                AppleLink: j.mccarthy
  8.  * Telephone:  800-421-4157 (9:00-5:00 Eastern time)
  9.  * I'm releasing this code with the hope that someone will get something
  10.  * out of it.  Feedback of any sort, even just letting me know that you're
  11.  * using it, is greatly appreciated!
  12.  *
  13.  * CQixableCursor's source code is in the public domain.  If you make changes,
  14.  * please do me the courtesy of letting me know before you redistribute it.
  15.  *
  16.  * This class basically does nothing special except draw lines over the
  17.  * cursors it finds.  If you want it to not do that, call setQixing(FALSE).
  18.  *
  19.  * CQixableCursor requires CRandom, which is available at ftp.brown.edu and
  20.  * other fine archives.
  21.  *
  22.  * Changes from 1.0b3 to 1.0:
  23.  * Changed name from CQixCursor to CQixableCursor.
  24.  * Added and implemented the setQixing() and getQixing() calls.
  25.  * Initialized gRandom if it wasn't already.
  26.  *
  27.  * Changes from 1.0b1 to 1.0b3:
  28.  * Fixed the "if srcXor and an odd number of lines, leave a stray pixel" bug.
  29.  * Fixed the "if max number of lines, hover in the bottom left corner" bug.
  30.  * Improved efficiency somewhat.
  31.  *
  32.  */
  33.  
  34.  
  35.  
  36. /********************************/
  37.  
  38. #include "CQixableCursor.h"
  39.  
  40. /********************************/
  41.  
  42. #include <QuickDraw.h>
  43.  
  44. #include "CRandom.h"
  45.  
  46. /********************************/
  47.  
  48. static void doDrawLine(Bits16 theData,
  49.     short lineLoc[2][2],
  50.     short xferMode);
  51.  
  52. static void randomPositiveVelocity(short *theVelocity);
  53.  
  54. /********************************/
  55.  
  56.  
  57.  
  58. void CQixableCursor::IQixableCursor(short rsrcID)
  59. {
  60.     register short i, j, k;
  61.     
  62.     isQixing = TRUE;
  63.     
  64.     inherited::IAnimCursor(rsrcID);
  65.     
  66.     setNQixLines(5);
  67.     setQixXferMode(srcOr);
  68.     
  69.     for (i = 0; i < 2; ++i) {
  70.         for (j = 0; j < 2; ++j) {
  71.             for (k = 0; k < kMaxNQixLines; ++k) {
  72.                 lineLoc[k][i][j] = 1;
  73.                 lineLoc[k][i][j] = 1;
  74.             }
  75.             randomPositiveVelocity(&velocity[i][j]);
  76.             if (j == 1) {
  77.                 while (velocity[i][1] == velocity[i][0]) {
  78.                     randomPositiveVelocity(&velocity[i][1]);
  79.                 }
  80.             }
  81.         }
  82.     }
  83.     
  84.     setTicksBetweenCursors(kDefaultQixTicksBetweenCursors);
  85.     
  86.     setMode(kCACModeInterrupted);
  87.     
  88.     if (gRandom == NULL) {
  89.         gRandom = new(CRandom);
  90.         gRandom->IRandom();
  91.     }
  92. }
  93.  
  94.  
  95.  
  96. void CQixableCursor::setNQixLines(short nLines)
  97. {
  98.     nQixLines = nLines;
  99.     
  100.     if (nQixLines < 1) nQixLines = 1;
  101.     else if (nQixLines > kMaxNQixLines) nQixLines = kMaxNQixLines;
  102. }
  103.  
  104.  
  105.  
  106. short CQixableCursor::getNQixLines(void)
  107. {
  108.     return nQixLines;
  109. }
  110.  
  111.  
  112.  
  113. void CQixableCursor::setQixXferMode(short newXferMode)
  114. {
  115.     switch (newXferMode) {
  116.         
  117.         case srcOr:
  118.         case srcXor:
  119.             xferMode = newXferMode;
  120.             break;
  121.         
  122.         default:
  123.                 /* Invalid mode passed -- do nothing. */
  124.             break;
  125.         
  126.     }
  127. }
  128.  
  129.  
  130.  
  131. short CQixableCursor::getQixXferMode(void)
  132. {
  133.     return xferMode;
  134. }
  135.  
  136.  
  137.  
  138. void CQixableCursor::setQixing(Boolean newQixing)
  139. {
  140.     isQixing = newQixing;
  141.     determineTryToUseColor();
  142. }
  143.  
  144.  
  145.  
  146. Boolean CQixableCursor::getQixing(void)
  147. {
  148.     return isQixing;
  149. }
  150.  
  151.  
  152.  
  153. void CQixableCursor::nextCursor(void)
  154. {
  155.     register short i, j, k;
  156.     register short cQixLine;
  157.     register short temp;
  158.     
  159.     inherited::nextCursor();
  160.     
  161.     if (getQixing() && !usingColorCursors) {
  162.         
  163.             /* Update the now-current cursor to put the lines in it. */
  164.         
  165.         cQixLine = nQixLines-1;
  166.     
  167.         
  168.         undrawLine(0);
  169.         
  170.         for (i = 1; i <= cQixLine; ++i) {
  171.             for (j = 0; j < 2; ++j) {
  172.                 for (k = 0; k < 2; ++k) {
  173.                     lineLoc[i-1][j][k] = lineLoc[i][j][k];
  174.                 }
  175.             }
  176.         }
  177.         
  178.         for (i = 0; i < 2; ++i) {
  179.             for (j = 0; j < 2; ++j) {
  180.                 temp = lineLoc[cQixLine][i][j];
  181.                 temp += velocity[i][j];
  182.                 if (temp < 1 || temp > 14) {
  183.                     short newSign;
  184.                     newSign = (velocity[i][j] < 0 ? 1 : -1);
  185.                     randomPositiveVelocity(&velocity[i][j]);
  186.                     velocity[i][j] *= newSign;
  187.                     if (temp < 1) temp = 1; else temp = 14;
  188.                     temp += velocity[i][j];
  189.                 }
  190.                 lineLoc[cQixLine][i][j] = temp;
  191.             }
  192.         }
  193.         
  194.         drawLine(cQixLine);
  195.         
  196.     }
  197. }
  198.  
  199.  
  200.  
  201. void CQixableCursor::determineTryToUseColor(void)
  202. {
  203.         /*
  204.          * If we're presently Qixing, don't try to load color.  If not, then
  205.          * load color--which may disable Qixing later.  The moral is--if you
  206.          * want Qixing, be sure to call setQixing(TRUE) before you call
  207.          * useAnimCursorID().
  208.          */
  209.     inherited::determineTryToUseColor();
  210.     if (tryToUseColor) {
  211.         tryToUseColor = (!isQixing);
  212.     }
  213. }
  214.  
  215.  
  216.  
  217. void CQixableCursor::undrawLine(short wLine)
  218. {
  219.     register acurPtr theAcurPtr;
  220.     theAcurPtr = *itsAcurHndl;
  221.     
  222.     if (getQixXferMode() == srcXor) {
  223.         
  224.         if (lineLoc[wLine][0][0] == 1
  225.             && lineLoc[wLine][0][1] == 1
  226.             && lineLoc[wLine][1][0] == 1
  227.             && lineLoc[wLine][1][1] == 1) {
  228.             
  229.             return ;
  230.             
  231.         }
  232.         
  233.         doDrawLine( (**theAcurPtr->cursor[theAcurPtr->cCursor]).data,
  234.             lineLoc[wLine],
  235.             srcXor );
  236.         
  237.     } else {
  238.         
  239.         doDrawLine( (**theAcurPtr->cursor[theAcurPtr->cCursor]).data,
  240.             lineLoc[wLine],
  241.             srcBic );
  242.         
  243.     }
  244. }
  245.  
  246.  
  247.  
  248. void CQixableCursor::drawLine(short wLine)
  249. {
  250.     register acurPtr theAcurPtr;
  251.     theAcurPtr = *itsAcurHndl;
  252.     
  253.     if (lineLoc[wLine][0][0] == 1
  254.         && lineLoc[wLine][0][1] == 1
  255.         && lineLoc[wLine][1][0] == 1
  256.         && lineLoc[wLine][1][1] == 1) {
  257.         
  258.         return ;
  259.         
  260.     }
  261.     
  262.     doDrawLine( (**theAcurPtr->cursor[theAcurPtr->cCursor]).data,
  263.         lineLoc[wLine],
  264.         getQixXferMode() );
  265. }
  266.  
  267.  
  268.  
  269.     /* Note that the macros are for column 0 on the right, 15 on the left. */
  270. #define setBit(theBits16,wCol,wRow) theBits16[wRow] |=  (1<<wCol)
  271. #define clrBit(theBits16,wCol,wRow) theBits16[wRow] &= ~(1<<wCol)
  272. #define xorBit(theBits16,wCol,wRow) theBits16[wRow] ^=  (1<<wCol)
  273. #define drawBit(theBits16,wCol,wRow,xferMode) {                                        \
  274.         if (xferMode==srcOr) setBit(theBits16,wCol,wRow);                            \
  275.         else if (xferMode==srcBic) clrBit(theBits16,wCol,wRow);                    \
  276.         else xorBit(theBits16,wCol,wRow);                                                \
  277.     }
  278.  
  279. static void doDrawLine(register Bits16 theData,
  280.     register short lineLoc[2][2],
  281.     register short xferMode)
  282. {
  283.         /* Bresenham's line-drawing algorithm, in integer arithmetic. */
  284.     
  285.     register short hSign, vSign;
  286.     short deltaH, deltaV;
  287.     register short cOffsetH, cOffsetV;
  288.     register short d, inc1, inc2;
  289.     
  290.     cOffsetH = lineLoc[0][0];
  291.     cOffsetV = lineLoc[0][1];
  292.     
  293.         /*
  294.          * Set the sign flags, and perform an absolute-value on the deltas
  295.          * at the same time.  By taking the absolute values, the number of
  296.          * cases is reduced from twelve to three.
  297.          */
  298.     if ( (deltaH = lineLoc[1][0]-cOffsetH) >= 0) {
  299.         hSign = 1;
  300.     } else {
  301.         hSign = -1;
  302.         deltaH = -deltaH;
  303.     }
  304.     if ( (deltaV = lineLoc[1][1]-cOffsetV) >= 0) {
  305.         vSign = 1;
  306.     } else {
  307.         vSign = -1;
  308.         deltaV = -deltaV;
  309.     }
  310.     
  311.     if (deltaH > deltaV) {
  312.         
  313.         d = (deltaV << 1) - deltaH;
  314.         inc1 = deltaV << 1;
  315.         inc2 = (deltaV - deltaH) << 1;
  316.         
  317.         drawBit(theData, cOffsetH, cOffsetV, xferMode);
  318.         while (cOffsetH != lineLoc[1][0]) {
  319.             cOffsetH += hSign;
  320.             if (d < 0) {
  321.                 d += inc1;
  322.             } else {
  323.                 cOffsetV += vSign;
  324.                 d += inc2;
  325.             }
  326.             drawBit(theData, cOffsetH, cOffsetV, xferMode);
  327.         }
  328.         
  329.     }
  330.     
  331.     else
  332.     
  333.     if (deltaH < deltaV) {
  334.         
  335.         d = (deltaH << 1) - deltaV;
  336.         inc1 = deltaH << 1;
  337.         inc2 = (deltaH - deltaV) << 1;
  338.         
  339.         drawBit(theData, cOffsetH, cOffsetV, xferMode);
  340.         while (cOffsetV != lineLoc[1][1]) {
  341.             cOffsetV += vSign;
  342.             if (d < 0) {
  343.                 d += inc1;
  344.             } else {
  345.                 cOffsetH += hSign;
  346.                 d += inc2;
  347.             }
  348.             drawBit(theData, cOffsetH, cOffsetV, xferMode);
  349.         }
  350.         
  351.     }
  352.     
  353.     else
  354.     
  355.     /* we know that (deltaH == deltaV) */ {
  356.         
  357.         drawBit(theData, cOffsetH, cOffsetV, xferMode);
  358.         while (cOffsetH != lineLoc[1][0]) {
  359.             cOffsetH += hSign;
  360.             cOffsetV += vSign;
  361.             drawBit(theData, cOffsetH, cOffsetV, xferMode);
  362.         }
  363.         
  364.     }
  365. }
  366.  
  367.  
  368.  
  369. static void randomPositiveVelocity(short *theVelocity)
  370. {
  371.         /* Get a random number from 1 to 3, with 2 most likely. */
  372.     *theVelocity = (gRandom->linearShort(3, 6) >> 1);
  373. }
  374.