home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / C / CSOURCE.ZIP / BLEND.C next >
Encoding:
C/C++ Source or Header  |  1994-07-07  |  11.3 KB  |  440 lines

  1. /****************************************************************
  2. * FILE:    blend.c
  3. * DESC:    This program demonstrates how a color blend can be
  4. *        created by tweened morphing.
  5. * HISTORY:     7/05/1994
  6. * LAST CHANGED:  
  7. *    Copyright (c) 1994 by Scott Anderson
  8. *
  9. ****************************************************************/
  10.  
  11. /* ----------------------INCLUDES----------------------------- */
  12.  
  13. #include <conio.h>
  14. #include <stdio.h>
  15. #include <math.h>
  16. #include <graph.h>
  17.  
  18. /* ----------------------DEFINES------------------------------ */
  19.  
  20. #define YES            1
  21. #define NO            0
  22.  
  23. #define GRAY        8
  24.  
  25. #define XMIN        0
  26. #define XMAX        319
  27. #define XMID        ((XMAX + XMIN) / 2)
  28. #define YMIN        0
  29. #define YMAX        199
  30. #define YMID        ((YMAX + YMIN) / 2)
  31.  
  32. #define COLORS        256
  33. #define COLOR1        32
  34.  
  35. #define FACTOR        16    /* Bit rotate factor for fixed point */
  36. #define SHIFT_BITS     8    /* Rotate factor for color blend */
  37.  
  38. #define MAX_POINTS    32
  39. #define NTWEENS     32
  40.  
  41. #define ESC_KEY     27
  42.  
  43. #define PI            3.1415926535;
  44.  
  45. #define QUIT        (-1)
  46. #define SKIP        1
  47.  
  48. /* ----------------------TYPEDEFS/STRUCTS--------------------- */
  49.  
  50. typedef struct {    /* for the screen coordinates */
  51.     int x, y;                
  52. }
  53. POINT;
  54.  
  55. /* Delta is the difference array that gets added to Tween */
  56. typedef struct {
  57.     long x, y;                
  58. }
  59. DELTA;
  60.  
  61. typedef struct {    /* The high & low words in a long word */
  62.     int lo, hi;                
  63. }
  64. LO_HI;
  65.  
  66. /* A Fixed-point union:
  67.  * a long word broken up into low & high words */
  68. typedef union {
  69.     long lword;                /* The long word portion */
  70.     LO_HI word;    /* The high and low parts of this long word */
  71. }
  72. FIXED;
  73.  
  74. typedef struct {    /* A fixed-point coordinate pair */
  75.     FIXED x, y;                
  76. }
  77. TWEEN;
  78.  
  79. typedef struct {
  80.     /* red, green, and blue color components */
  81.     unsigned char r, g, b;    
  82. }
  83. COLOR;
  84.  
  85. /* ----------------------PROTOTYPES--------------------------- */
  86.  
  87. void    setGraphicsMode();
  88. void    setTextMode();
  89. int        blendPoly();
  90. void    calcTweens(int npoints, int ntweens);
  91. void    tweenObject(int npoints, int ntweens);
  92. void    getXY(POINT *point);
  93. void    getPoly(POINT array[], int npoints, int maxRad);
  94. void    drawObject(int npoints, int color);
  95. void    setSpread();
  96. void    setRandColor (int min, int max, COLOR *color);
  97. void    setPalColor(int index, int red, int green, int blue);
  98. int        quitCheck();
  99. int        keyCode(int key);
  100.  
  101. /* ----------------------GLOBAL DATA-------------------------- */
  102.  
  103. POINT    Source[MAX_POINTS];
  104. POINT    Target[MAX_POINTS];
  105. DELTA    Delta [MAX_POINTS];
  106. TWEEN    Tween [MAX_POINTS];
  107.  
  108. /*****************************************************************
  109. * FUNC: main (int argc, char *argv[])
  110. * DESC: Kickstart the random number generator, set the graphics
  111. *        mode and run blendPoly until Esc is pressed.
  112. *****************************************************************/
  113.  
  114. main (int argc, char *argv[])
  115. {
  116.     srand((unsigned int) time());
  117.     setGraphicsMode();
  118.     while (blendPoly());
  119.     setTextMode();
  120. }
  121.  
  122. /*****************************************************************
  123. * FUNC: int    blendPoly()
  124. * DESC: blend a random polygon into another one.
  125. *****************************************************************/
  126.  
  127. int
  128. blendPoly()
  129. {
  130.     int keyCode;
  131.     long start;
  132.     int npoints = random (3, MAX_POINTS);
  133.  
  134.     clearScreen(GRAY);
  135.     setSpread();
  136.     getPoly (Source, npoints, XMID);
  137.     getPoly (Target, npoints, XMID/4);
  138.  
  139.     calcTweens(npoints, NTWEENS);
  140.     tweenObject(npoints, NTWEENS);
  141.  
  142.     /* Wait a few seconds for a keystroke.
  143.      * Return 0 if ESC is pressed */
  144.     start = (long) time();
  145.     while ((long) time() - start < 3) {
  146.         keyCode = quitCheck();
  147.         if (keyCode == QUIT)
  148.             return 0;
  149.         else if (keyCode == SKIP)
  150.             return 1;
  151.     }
  152.     return 1;
  153. }
  154.  
  155. /*****************************************************************
  156. * FUNC: void    calcTweens(int npoints, int ntweens)
  157. * DESC: Calculate the Delta array from the Source and Target
  158. *****************************************************************/
  159.  
  160. void
  161. calcTweens(int npoints, int ntweens)
  162. {
  163.     int pt;
  164.     for (pt = 0; pt < npoints; pt++)
  165.     {    /* use fixed point long words to store the deltas */
  166.         Delta[pt].x = ((long)(Target[pt].x - Source[pt].x)
  167.                         << FACTOR) / ntweens;
  168.         Delta[pt].y = ((long)(Target[pt].y - Source[pt].y)
  169.                         << FACTOR) / ntweens;
  170.         Tween[pt].x.word.hi = Source[pt].x;    /* set high word */
  171.         Tween[pt].y.word.hi = Source[pt].y;
  172.         Tween[pt].x.word.lo = 0;            /* clear low word */
  173.         Tween[pt].y.word.lo = 0;
  174.     }
  175. }
  176.  
  177. /*****************************************************************
  178. * FUNC: void    tweenObject(int npoints, int ntweens)
  179. * DESC: Metamophose the Source polygon into the Target polygon
  180. *        by adding the Delta array.
  181. *****************************************************************/
  182.  
  183. void
  184. tweenObject(int npoints, int ntweens)
  185. {    /* Tween one object into another */
  186.     int tween, point;
  187.     int color = COLOR1;
  188.  
  189.      for (tween = 0; tween < ntweens; tween++)
  190.     {    /* Add deltas to tween array & draw new polygon */
  191.         for (point = 0; point < npoints; point++)
  192.         {    /* Add delta to tween the line */
  193.             Tween[point].x.lword += Delta[point].x;
  194.             Tween[point].y.lword += Delta[point].y;
  195.         }
  196.         drawObject(npoints, color++);
  197.     }    
  198. }
  199.  
  200. /*****************************************************************
  201. * FUNC: void    drawObject(int npoints, int color)
  202. * DESC: Copy the points into an xycoord struct & draw the poly.
  203. *****************************************************************/
  204.  
  205. void
  206. drawObject(int npoints, int color)
  207. {
  208.     struct _xycoord poly[MAX_POINTS];
  209.     int point;
  210.     
  211.     int fillOK = NO;
  212.     int oldY = Tween[0].y.word.hi;
  213.  
  214.     for (point = 0; point < npoints; point++)
  215.     {    /* get the coords from the hi word of the Tween array */
  216.         poly[point].xcoord = Tween[point].x.word.hi;
  217.         poly[point].ycoord = Tween[point].y.word.hi;
  218.  
  219.         /* The following code is to fix a fatal bug in the
  220.          * Microsoft polygon fill routine that occurs when all
  221.          * of the Y-values are the same (a horizontal line).
  222.          * There is also a bug when the bottom line of the poly
  223.          * is horizontal, but at least that bug doesn't crash
  224.          * the machine...
  225.          */
  226.         if (poly[point].ycoord != oldY)
  227.             fillOK = YES;    /* y is different, so fill poly */
  228.     }
  229.     _setcolor(color);
  230.     if (fillOK)                    /* don't crash the system! */
  231.         _polygon(_GFILLINTERIOR, poly, npoints);
  232. }
  233.  
  234. /*****************************************************************
  235. * FUNC: void    getPoly(POINT array[], int npoints, int maxRad)
  236. * DESC: Create a random polygon and put it in array
  237. *****************************************************************/
  238.  
  239. void
  240. getPoly(POINT array[], int npoints, int maxRad)
  241. {    /* Generate a random set of points */
  242.     int point;
  243.     int rad, phase, jagFactor;
  244.     float theta;
  245.     float twoPi = 2 * PI;
  246.  
  247.     jagFactor = random(1, 4);
  248.     phase = twoPi / random(6, 20);
  249.     for (point = 0, theta = 0; point < npoints;
  250.             point++, theta += twoPi / npoints) {
  251.         rad = random(maxRad / jagFactor, maxRad);
  252.         array[point].x = XMID + rad * cos(theta + phase);
  253.         array[point].y = YMID + rad * sin(theta + phase);
  254.     }
  255. }
  256.  
  257. /*****************************************************************
  258. * FUNC: void    setSpread()
  259. * DESC: Create a random color spread
  260. *****************************************************************/
  261.  
  262. void
  263. setSpread()
  264. {
  265.     int    index;
  266.     int    rotRed, rotGreen, rotBlue;
  267.     int    dRed,   dGreen,   dBlue;
  268.     COLOR colorA, colorB;
  269.  
  270.     if (rand() & 1) {
  271.         setRandColor ( 0, 16, &colorA);
  272.         setRandColor (22, 32, &colorB);
  273.     }
  274.     else {
  275.         setRandColor (22, 32, &colorA);
  276.         setRandColor ( 0, 16, &colorB);
  277.     }
  278.  
  279.     rotRed   = (int) colorA.r << SHIFT_BITS;
  280.     rotGreen = (int) colorA.g << SHIFT_BITS;
  281.     rotBlue  = (int) colorA.b << SHIFT_BITS;
  282.  
  283.     dRed   =  ((int)(colorB.r - colorA.r) << SHIFT_BITS)
  284.                     / NTWEENS;
  285.     dGreen =  ((int)(colorB.g - colorA.g) << SHIFT_BITS)
  286.                     / NTWEENS;
  287.     dBlue  =  ((int)(colorB.b - colorA.b) << SHIFT_BITS)
  288.                     / NTWEENS;
  289.  
  290.     for (index = 0; index < NTWEENS; index++) {  
  291.         setPalColor(index + COLOR1,
  292.                     rotRed   >> SHIFT_BITS,
  293.                     rotGreen >> SHIFT_BITS,
  294.                     rotBlue  >> SHIFT_BITS);
  295.  
  296.         rotRed        += dRed;
  297.         rotGreen    += dGreen;
  298.         rotBlue        += dBlue;
  299.     }
  300. }
  301.  
  302. /*****************************************************************
  303. * FUNC: void setRandColor  (int min, int max, COLOR *color)
  304. * DESC: Create a pointer to a random color with RGB components
  305. *            between the min and max component value.
  306. *****************************************************************/
  307.  
  308. void
  309. setRandColor (int min, int max, COLOR *color)
  310. {
  311.     color->r = min + random(0, max - min);
  312.     color->g = min + random(0, max - min);
  313.     color->b = min + random(0, max - min);
  314. }
  315.  
  316. /*****************************************************************
  317. * FUNC: int    random(int low, int high)
  318. * DESC: Return a random number between the low and high values
  319. *****************************************************************/
  320.  
  321. int
  322. random (int low, int high)
  323. {    /* get a random number between low and high, inclusively */
  324.     if (high < low) return (low);    /* don't divide by zero */
  325.     return (low + (rand() % (high - low + 1)));
  326. }
  327.  
  328. /*****************************************************************
  329. * FUNC: int    quitCheck()
  330. * DESC: Check keyboard. If there is no key waiting, return 0,
  331. *        for OK. If a number from 1-9 is typed, change the wait
  332. *        between frames. Otherwise, the user wants to quit,
  333. *        so return 1.
  334. *****************************************************************/
  335.  
  336. int
  337. quitCheck()
  338. {
  339.     int    key;
  340.     static int spaceWait = NO;
  341.  
  342.     if (spaceWait) {
  343.         key = getch();
  344.         if (key != ' ')
  345.             spaceWait = NO;
  346.         return keyCode(key);
  347.     }
  348.     else if (_kbhit()) {
  349.         key = _getch();
  350.         if (key == ' ') {
  351.             /* turn on space bar stepping */
  352.             spaceWait = YES;
  353.             /* pause for space key */
  354.             key = _getch();
  355.         }
  356.         return keyCode(key);
  357.     }
  358.     return 0;
  359. }
  360.  
  361. /*****************************************************************
  362. * FUNC: int    keyCode(int key)
  363. * DESC: Parse the key and return a quit or skip code.
  364. *****************************************************************/
  365.  
  366. int
  367. keyCode(int key)
  368. {
  369.     if (key == ESC_KEY || key == 'q' || key == 'Q')
  370.         return QUIT;    /* a quit key */
  371.     else return SKIP;    /* otherwise, skip */
  372. }
  373.  
  374. /*****************************************************************
  375. * FUNC: void    setGraphicsMode()
  376. * DESC: Set up the graphics screen
  377. *****************************************************************/
  378.  
  379. void
  380. setGraphicsMode()
  381. {
  382.     _setvideomode(_MRES256COLOR);
  383. }
  384.  
  385. /*****************************************************************
  386. * FUNC: void    setTextMode()
  387. * DESC: Set the screen to the startup text mode
  388. *****************************************************************/
  389.  
  390. void
  391. setTextMode()
  392. {
  393.     _setvideomode(_DEFAULTMODE);
  394. }
  395.  
  396. /*****************************************************************
  397. * FUNC: int    clearScreen(int color)
  398. * DESC: Clear screen to the given color
  399. *****************************************************************/
  400.  
  401. int
  402. clearScreen(int color)
  403. {
  404.     _setcolor(color);
  405.     _rectangle(_GFILLINTERIOR, XMIN, YMIN, XMAX, YMAX);
  406. }
  407.  
  408. /*****************************************************************
  409. * FUNC: void setPalColor(int index, int red, int green, int blue)
  410. * DESC:set the palette register to the color components
  411. *****************************************************************/
  412.  
  413. void
  414. setPalColor(int index, int red, int green, int blue)
  415. {
  416.     _outp (0x3c7, index-1);
  417.     _outp (0x3c9, red);
  418.     _outp (0x3c9, green);
  419.     _outp (0x3c9, blue);
  420. }
  421.  
  422.  
  423.