/* TURTLE - Module of functions to implement turtle graphics. Turtle graphics * is a model for specifying relative movements of an imaginary pointer whose * direction, color, visibility, and other attributes are given default * values using turtle functions. To use the turtle module, include TURTLE.H * in your program. The following functions (many defined as macros) * are public : * * InitTurtle - Initiate turtle graphics * Home - Reset turtle defaults * PenDown - Set pen visibility * SetFill - Set fill state * PenColor - Set pen color index * BorderColor - Set border color index * Turn - Set direction relative to current * TurnTo - Set absolute direction * Move - Move in current direction * MoveTo - Move to absolute location * Poly - Draw a polygon * Circle - Draw a circle with center at current location * Ellipse - Draw an ellipse with center at current location * Rectangle - Draw a rectangle with center at current location * ImageSize - Get size of rectangle with top-left origin * GetImage - Get rectangular image with top-left origin * PutImage - Put rectangular image with top-left origin * FillIn - Fill from the current location to border * NextColorIndex - Rotate to next color index * NextColorValue - Rotate to next color value * OnScreen - Report whether current location is on screen * RGB - Combine Red, Green, and Blue elements of color value * * The TURTLE structure, the "tc" global variable (having TURTLE type), and * "vlColors" variable are defined. However, these are not normally used * directly by the programmer. */ #include #include #include #include "turtle.h" #define PI 3.141593 long cvlColors[256]; /* Array of long color values */ struct TURTLE tc = { 1.39 }; /* Initial aspect - adjust for your screen */ /* InitTurtle - Initializes all turtle defaults. This function should be * called at least once (after _setvideomode and _getvideoconfig) and * additionally after any change to a new graphics mode. * * Params: vc - pointer to videoconfig structure * * Return: 0 if fail, 1 if success * * Uses: tc structure variable cvlColors array */ short InitTurtle( struct videoconfig *vc ) { int i; unsigned cvuInc, cvuRed, cvuGreen, cvuBlue; /* Unsigned portions of */ static int mode = -1; /* color values */ /* Terminate if not graphics mode. */ if( !vc->numxpixels ) return 0; /* If mode has changed, set window coordinates. */ if( mode != vc->mode ) { mode = vc->mode; tc.xsLeft = tc.ysTop = 0; tc.xsRight = vc->numxpixels - 1; tc.ysBot = vc->numypixels - 1; } /* Set palette flag. */ switch( vc->adapter ) { case _MDPA: case _CGA: case _OCGA: case _HGC: tc.fPalette = FALSE; break; default: tc.fPalette = TRUE; break; } /* Set palette defaults. */ switch( vc->mode ) { case _HRESBW: case _HERCMONO: case _ERESNOCOLOR: case _ORESCOLOR: case _VRES2COLOR: tc.ccv = 0; tc.cci = 2; return Home( vc ); case _MRES256COLOR: /* Active bits in this order: */ cvuInc = 12; tc.ccv = tc.cci = 125; /* ???????? ??bbbbbb ??gggggg ??rrrrrr */ break; case _ERESCOLOR: if( vc->memory == 64 ) { cvuInc = 32; tc.ccv = 16; /* ???????? ??????Bb ??????Gg ??????Rr */ tc.cci = 4; break; } /* Else fall through */ case _VRES16COLOR: cvuInc = 16; tc.ccv = 64; /* ???????? ??????bb ??????gg ??????rr */ tc.cci = 16; break; case _MRES4COLOR: case _MRESNOCOLOR: cvuInc = 32; tc.ccv = 16; /* ???????? ??????Bb ??????Gg ??????Rr */ tc.cci = 4; break; case _MRES16COLOR: case _HRES16COLOR: cvuInc = 32; tc.cci = tc.ccv = 16; /* ???????? ??????Bb ??????Gg ??????Rr */ break; } /* Fill palette arrays. */ for( i = 0, cvuBlue = 0; cvuBlue < 64; cvuBlue += cvuInc ) for( cvuGreen = 0; cvuGreen < 64; cvuGreen += cvuInc ) for( cvuRed = 0; cvuRed < 64; cvuRed += cvuInc ) { cvlColors[i] = RGB( cvuRed, cvuGreen, cvuBlue ); /* Special case of 6 bits for 16 colors (RGBI). * If both bits are on for any color, intensity is set. * If one bit is set for a color, that color is on. */ if( cvuInc == 32 ) cvlColors[i + 8] = cvlColors[i] | (cvlColors[i] >> 1); i++; } cvlColors[tc.ccv - 1] = _BRIGHTWHITE; NextColorValue( DEFAULT ); return Home( vc ); } /* Home - Resets turtle defaults. This function can be called if you have * not changed the video mode, but you want to put the turtle back in * the center of the window and restore all defaults. For example, you can * change the absolute window corners and then call it to set a new * turtle window. * * Params: vc - pointer to videoconfig structure * * Return: 0 if fail, 1 if success * * Uses: tc */ short Home( struct videoconfig *vc ) { struct _wxycoord xy1, xy2; _setviewport( tc.xsLeft, tc.ysTop, tc.xsRight, tc.ysBot ); /* Set the window based on screen height 1000 and width based on * aspect ratio. */ tc.yMax = 500.0; tc.xMax = tc.yMax * tc.yxRatio; if( !_setwindow( FALSE, -tc.xMax, -tc.yMax, tc.xMax, tc.yMax ) ) return 0; /* Calculate the unit size of 1 pixel using Y axis. */ xy1 = _getwindowcoord( 1, 1 ); xy2 = _getwindowcoord( 1, 2 ); tc.yUnit = xy2.wy - xy1.wy; /* Set defaults for current pixel, angle, pen state and fill state. */ tc.xCur = tc.yCur = 0.0; _moveto_w( tc.xCur, tc.yCur ); TurnTo( 0 ); PenDown( TRUE ); SetFill( FALSE ); /* Make white the last color index and set pen and border to it. */ _remappalette( WHITE, _BRIGHTWHITE ); BorderColor( WHITE ); PenColor( WHITE ); _setbkcolor( _BLACK ); return 1; } /* PenDown - Sets the visibility of the pen used by Move and MoveTo. The * state can be TRUE (visible), FALSE (invisible), or DEFAULT (return * current without changing). * * Params: fPenDown * * Return: current pen state * * Uses: tc */ int PenDown( int fPenDown ) { switch( fPenDown ) { case DEFAULT: break; case FALSE: tc.fPenDown = FALSE; break; default: tc.fPenDown = TRUE; break; } return tc.fPenDown; } /* SetFill - Determines the state of filling figures such as Rectangle, * Circle, and Ellipse. State can be TRUE (fill inside), FALSE (border * only), or DEFAULT (return current fill state). * * Params: fFill * * Return: current fill state * * Uses: tc */ short SetFill( short fFill ) { switch( fFill ) { case DEFAULT: break; case _GBORDER: case FALSE: tc.fFill = _GBORDER; break; default: tc.fFill = _GFILLINTERIOR; break; } return tc.fFill; } /* PenColor - Sets the color index of the pen. * * Params: ciCur - any color index of DEFAULT to return without changing * * Return: current pen color index * * Uses: tc */ short PenColor( short ciCur ) { if( ciCur != DEFAULT ) _setcolor( tc.ciCur = ciCur ); return tc.ciCur; } /* BorderColor - Sets the color index of the border that will be recognized * by fills. * * Params: ciBorder - any color index of DEFAULT to return without changing * * Return: current border color index * * Uses: tc */ short BorderColor( short border ) { if( border != DEFAULT ) tc.ciBorder = border; return tc.ciBorder; } /* Turn - Sets a new direction relative to the current direction. * * Params: angCur - a positive (clockwise) or negative (counterclockwise) * angle in degrees * * Return: new current absolute angle * * Uses: tc */ short Turn( short angCur ) { return( tc.angCur = ((tc.angCur + angCur) % CIRCUMFERENCE) ); } /* TurnTo - Sets a new absolute direction. * * Params: angCur - a positive (clockwise) or negative (counterclockwise) * angle in degrees (0 points to 12 o'clock) * * Return: new current absolute angle * * Uses: tc */ short TurnTo( short angCur ) { if( angCur < 0 ) return( tc.angCur = 360 - (angCur % CIRCUMFERENCE) ); else return( tc.angCur = angCur % CIRCUMFERENCE ); } /* Move - Moves from the current position in the current direction for a * specified distance. A line is drawn if the pen is down. The current * position is reset to the destination. * * Params: dxy - difference between current xy and new xy * * Return: 0 if new position is off screen, nonzero if on screen * * Uses: tc */ short Move( double dxy ) { double dx, dy; /* Differences of X and Y */ double angT; /* Calculate new X and Y positions. */ angT = (tc.angCur - 90) * (PI / HALFCIRCUMFERENCE); dx = dxy * cos( angT ); dy = dxy * sin( angT ); /* Move, drawing if pen down, then update position */ if( tc.fPenDown ) _lineto_w( tc.xCur + dx, tc.yCur + dy ); else _moveto_w( tc.xCur + dx, tc.yCur + dy ); tc.xCur += dx; tc.yCur += dy; return OnScreen(); } /* MoveTo - Moves from the current position to a specified position. A * line is drawn if the pen is down. The current position is reset to the * destination. The current direction is not changed. * * Params: x and y - destination position * * Return: 0 if new position is off screen, nonzero if on screen * * Uses: tc */ short MoveTo( double x, double y ) { if( tc.fPenDown ) _lineto_w( x, y ); else _moveto_w( x, y ); tc.xCur = x; tc.yCur = y; return OnScreen(); } /* Poly - Draws a polygon. * * Params: cSide - count of polygon sides * dxySide - distance of each side * * Return: 0 if any part of polygon is off screen, nonzero if on screen */ short Poly( int cSide, double dxySide ) { short i, angT, fPen, ret = TRUE; /* Make sure pen is down (restore pen state when done). */ fPen = PenDown( TRUE ); /* Calculate angle, then draw each side. */ angT = 360 / cSide; for( i = 1; i <= cSide; i++ ) { ret = Move( dxySide ) && ret; Turn( angT ); } PenDown( fPen ); return ret; } /* NextColorIndex - Rotate to next color index. First attribute (normally * background) and last attribute (white) are skipped. * * Params: ciCur - Specify DEFAULT to use color index from last call, * or specify a new color to rotate from * * Return: rotated color index * * Uses: tc */ short NextColorIndex( short ciCur ) { static short ciPrev = 0; /* Static to retain index between calls */ /* Assign new current if given. */ if( ciCur != DEFAULT ) ciPrev = ciCur; /* Toggle for two-color modes, rotate for multi-color modes. */ if( tc.cci == 2 ) return( ciPrev = !ciPrev ); else return( ciPrev = (++ciPrev % (tc.cci - 1)) ); } /* NextColorValue - Rotate to next color value for adapters (EGA * and higher) that support remappable palettes. * * Params: fAction - DEFAULT (rotate all) or LIMITED (rotate first 14 only) * * Return: None * * Uses: tc */ void NextColorValue( int fAction ) { static int icvCur = 1; /* Current index into color value array */ static int ciCur = 1; /* Current color index */ int icvT; /* Temporary index into color values */ int i; /* Ignore modes with no palette values. */ if( !tc.fPalette || !tc.ccv ) return; /* Increment and rotate color value index. */ icvT = (++icvCur % (tc.ccv - 2)) + 1; /* DEFAULT - Remap all color indexes, 14 at a time. For most modes, * this is all the indexes except first and last. For 256-color * mode, rotating all available indexes would be too slow. */ if( fAction == DEFAULT ) for( i = 1; i <= 14; i++ ) _remappalette( (ciCur++ % (tc.cci - 2)) + 1, cvlColors[(icvT++ % (tc.ccv - 2)) + 1] ); /* LIMITED - Rotate only the first 14 color indexes. */ else for( i = 1; i <= 14; i++ ) _remappalette( i, cvlColors[(icvT++ % (tc.ccv - 1)) + 1] ); }