home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * FILE: blend.c
- * DESC: This program demonstrates how a color blend can be
- * created by tweened morphing.
- *
- * HISTORY: 7/05/1994
- * LAST CHANGED:
- *
- * Copyright (c) 1994 by Scott Anderson
- *
- ****************************************************************/
-
- /* ----------------------INCLUDES----------------------------- */
-
- #include <conio.h>
- #include <stdio.h>
- #include <math.h>
- #include <graph.h>
-
- /* ----------------------DEFINES------------------------------ */
-
- #define YES 1
- #define NO 0
-
- #define GRAY 8
-
- #define XMIN 0
- #define XMAX 319
- #define XMID ((XMAX + XMIN) / 2)
- #define YMIN 0
- #define YMAX 199
- #define YMID ((YMAX + YMIN) / 2)
-
- #define COLORS 256
- #define COLOR1 32
-
- #define FACTOR 16 /* Bit rotate factor for fixed point */
- #define SHIFT_BITS 8 /* Rotate factor for color blend */
-
- #define MAX_POINTS 32
- #define NTWEENS 32
-
- #define ESC_KEY 27
-
- #define PI 3.1415926535;
-
- #define QUIT (-1)
- #define SKIP 1
-
- /* ----------------------TYPEDEFS/STRUCTS--------------------- */
-
- typedef struct { /* for the screen coordinates */
- int x, y;
- }
- POINT;
-
- /* Delta is the difference array that gets added to Tween */
- typedef struct {
- long x, y;
- }
- DELTA;
-
- typedef struct { /* The high & low words in a long word */
- int lo, hi;
- }
- LO_HI;
-
- /* A Fixed-point union:
- * a long word broken up into low & high words */
- typedef union {
- long lword; /* The long word portion */
- LO_HI word; /* The high and low parts of this long word */
- }
- FIXED;
-
- typedef struct { /* A fixed-point coordinate pair */
- FIXED x, y;
- }
- TWEEN;
-
- typedef struct {
- /* red, green, and blue color components */
- unsigned char r, g, b;
- }
- COLOR;
-
- /* ----------------------PROTOTYPES--------------------------- */
-
- void setGraphicsMode();
- void setTextMode();
- int blendPoly();
- void calcTweens(int npoints, int ntweens);
- void tweenObject(int npoints, int ntweens);
- void getXY(POINT *point);
- void getPoly(POINT array[], int npoints, int maxRad);
- void drawObject(int npoints, int color);
- void setSpread();
- void setRandColor (int min, int max, COLOR *color);
- void setPalColor(int index, int red, int green, int blue);
- int quitCheck();
- int keyCode(int key);
-
- /* ----------------------GLOBAL DATA-------------------------- */
-
- POINT Source[MAX_POINTS];
- POINT Target[MAX_POINTS];
- DELTA Delta [MAX_POINTS];
- TWEEN Tween [MAX_POINTS];
-
- /*****************************************************************
- * FUNC: main (int argc, char *argv[])
- *
- * DESC: Kickstart the random number generator, set the graphics
- * mode and run blendPoly until Esc is pressed.
- *****************************************************************/
-
- main (int argc, char *argv[])
- {
- srand((unsigned int) time());
- setGraphicsMode();
- while (blendPoly());
- setTextMode();
- }
-
- /*****************************************************************
- * FUNC: int blendPoly()
- *
- * DESC: blend a random polygon into another one.
- *****************************************************************/
-
- int
- blendPoly()
- {
- int keyCode;
- long start;
- int npoints = random (3, MAX_POINTS);
-
- clearScreen(GRAY);
- setSpread();
- getPoly (Source, npoints, XMID);
- getPoly (Target, npoints, XMID/4);
-
- calcTweens(npoints, NTWEENS);
- tweenObject(npoints, NTWEENS);
-
- /* Wait a few seconds for a keystroke.
- * Return 0 if ESC is pressed */
- start = (long) time();
- while ((long) time() - start < 3) {
- keyCode = quitCheck();
- if (keyCode == QUIT)
- return 0;
- else if (keyCode == SKIP)
- return 1;
- }
- return 1;
- }
-
- /*****************************************************************
- * FUNC: void calcTweens(int npoints, int ntweens)
- *
- * DESC: Calculate the Delta array from the Source and Target
- *****************************************************************/
-
- void
- calcTweens(int npoints, int ntweens)
- {
- int pt;
- for (pt = 0; pt < npoints; pt++)
- { /* use fixed point long words to store the deltas */
- Delta[pt].x = ((long)(Target[pt].x - Source[pt].x)
- << FACTOR) / ntweens;
- Delta[pt].y = ((long)(Target[pt].y - Source[pt].y)
- << FACTOR) / ntweens;
- Tween[pt].x.word.hi = Source[pt].x; /* set high word */
- Tween[pt].y.word.hi = Source[pt].y;
- Tween[pt].x.word.lo = 0; /* clear low word */
- Tween[pt].y.word.lo = 0;
- }
- }
-
- /*****************************************************************
- * FUNC: void tweenObject(int npoints, int ntweens)
- *
- * DESC: Metamophose the Source polygon into the Target polygon
- * by adding the Delta array.
- *****************************************************************/
-
- void
- tweenObject(int npoints, int ntweens)
- { /* Tween one object into another */
- int tween, point;
- int color = COLOR1;
-
- for (tween = 0; tween < ntweens; tween++)
- { /* Add deltas to tween array & draw new polygon */
- for (point = 0; point < npoints; point++)
- { /* Add delta to tween the line */
- Tween[point].x.lword += Delta[point].x;
- Tween[point].y.lword += Delta[point].y;
- }
- drawObject(npoints, color++);
- }
- }
-
- /*****************************************************************
- * FUNC: void drawObject(int npoints, int color)
- *
- * DESC: Copy the points into an xycoord struct & draw the poly.
- *****************************************************************/
-
- void
- drawObject(int npoints, int color)
- {
- struct _xycoord poly[MAX_POINTS];
- int point;
-
- int fillOK = NO;
- int oldY = Tween[0].y.word.hi;
-
- for (point = 0; point < npoints; point++)
- { /* get the coords from the hi word of the Tween array */
- poly[point].xcoord = Tween[point].x.word.hi;
- poly[point].ycoord = Tween[point].y.word.hi;
-
- /* The following code is to fix a fatal bug in the
- * Microsoft polygon fill routine that occurs when all
- * of the Y-values are the same (a horizontal line).
- * There is also a bug when the bottom line of the poly
- * is horizontal, but at least that bug doesn't crash
- * the machine...
- */
- if (poly[point].ycoord != oldY)
- fillOK = YES; /* y is different, so fill poly */
- }
- _setcolor(color);
- if (fillOK) /* don't crash the system! */
- _polygon(_GFILLINTERIOR, poly, npoints);
- }
-
- /*****************************************************************
- * FUNC: void getPoly(POINT array[], int npoints, int maxRad)
- *
- * DESC: Create a random polygon and put it in array
- *****************************************************************/
-
- void
- getPoly(POINT array[], int npoints, int maxRad)
- { /* Generate a random set of points */
- int point;
- int rad, phase, jagFactor;
- float theta;
- float twoPi = 2 * PI;
-
- jagFactor = random(1, 4);
- phase = twoPi / random(6, 20);
- for (point = 0, theta = 0; point < npoints;
- point++, theta += twoPi / npoints) {
- rad = random(maxRad / jagFactor, maxRad);
- array[point].x = XMID + rad * cos(theta + phase);
- array[point].y = YMID + rad * sin(theta + phase);
- }
- }
-
- /*****************************************************************
- * FUNC: void setSpread()
- *
- * DESC: Create a random color spread
- *****************************************************************/
-
- void
- setSpread()
- {
- int index;
- int rotRed, rotGreen, rotBlue;
- int dRed, dGreen, dBlue;
- COLOR colorA, colorB;
-
- if (rand() & 1) {
- setRandColor ( 0, 16, &colorA);
- setRandColor (22, 32, &colorB);
- }
- else {
- setRandColor (22, 32, &colorA);
- setRandColor ( 0, 16, &colorB);
- }
-
- rotRed = (int) colorA.r << SHIFT_BITS;
- rotGreen = (int) colorA.g << SHIFT_BITS;
- rotBlue = (int) colorA.b << SHIFT_BITS;
-
- dRed = ((int)(colorB.r - colorA.r) << SHIFT_BITS)
- / NTWEENS;
- dGreen = ((int)(colorB.g - colorA.g) << SHIFT_BITS)
- / NTWEENS;
- dBlue = ((int)(colorB.b - colorA.b) << SHIFT_BITS)
- / NTWEENS;
-
- for (index = 0; index < NTWEENS; index++) {
- setPalColor(index + COLOR1,
- rotRed >> SHIFT_BITS,
- rotGreen >> SHIFT_BITS,
- rotBlue >> SHIFT_BITS);
-
- rotRed += dRed;
- rotGreen += dGreen;
- rotBlue += dBlue;
- }
- }
-
- /*****************************************************************
- * FUNC: void setRandColor (int min, int max, COLOR *color)
- *
- * DESC: Create a pointer to a random color with RGB components
- * between the min and max component value.
- *****************************************************************/
-
- void
- setRandColor (int min, int max, COLOR *color)
- {
- color->r = min + random(0, max - min);
- color->g = min + random(0, max - min);
- color->b = min + random(0, max - min);
- }
-
- /*****************************************************************
- * FUNC: int random(int low, int high)
- *
- * DESC: Return a random number between the low and high values
- *****************************************************************/
-
- int
- random (int low, int high)
- { /* get a random number between low and high, inclusively */
- if (high < low) return (low); /* don't divide by zero */
- return (low + (rand() % (high - low + 1)));
- }
-
- /*****************************************************************
- * FUNC: int quitCheck()
- *
- * DESC: Check keyboard. If there is no key waiting, return 0,
- * for OK. If a number from 1-9 is typed, change the wait
- * between frames. Otherwise, the user wants to quit,
- * so return 1.
- *****************************************************************/
-
- int
- quitCheck()
- {
- int key;
- static int spaceWait = NO;
-
- if (spaceWait) {
- key = getch();
- if (key != ' ')
- spaceWait = NO;
- return keyCode(key);
- }
- else if (_kbhit()) {
- key = _getch();
- if (key == ' ') {
- /* turn on space bar stepping */
- spaceWait = YES;
- /* pause for space key */
- key = _getch();
- }
- return keyCode(key);
- }
- return 0;
- }
-
- /*****************************************************************
- * FUNC: int keyCode(int key)
- *
- * DESC: Parse the key and return a quit or skip code.
- *****************************************************************/
-
- int
- keyCode(int key)
- {
- if (key == ESC_KEY || key == 'q' || key == 'Q')
- return QUIT; /* a quit key */
- else return SKIP; /* otherwise, skip */
- }
-
- /*****************************************************************
- * FUNC: void setGraphicsMode()
- *
- * DESC: Set up the graphics screen
- *****************************************************************/
-
- void
- setGraphicsMode()
- {
- _setvideomode(_MRES256COLOR);
- }
-
- /*****************************************************************
- * FUNC: void setTextMode()
- *
- * DESC: Set the screen to the startup text mode
- *****************************************************************/
-
- void
- setTextMode()
- {
- _setvideomode(_DEFAULTMODE);
- }
-
- /*****************************************************************
- * FUNC: int clearScreen(int color)
- *
- * DESC: Clear screen to the given color
- *****************************************************************/
-
- int
- clearScreen(int color)
- {
- _setcolor(color);
- _rectangle(_GFILLINTERIOR, XMIN, YMIN, XMAX, YMAX);
- }
-
- /*****************************************************************
- * FUNC: void setPalColor(int index, int red, int green, int blue)
- *
- * DESC:set the palette register to the color components
- *****************************************************************/
-
- void
- setPalColor(int index, int red, int green, int blue)
- {
- _outp (0x3c7, index-1);
- _outp (0x3c9, red);
- _outp (0x3c9, green);
- _outp (0x3c9, blue);
- }
-
-
-