dos_compilers/Microsoft QuickC v251/SAMPLES/GRDEMO.C
2024-07-02 08:12:15 -07:00

683 lines
19 KiB
C

/* GRDEMO.C - Demonstrates capabilities of the Microsoft graphics library.
* Uses MENU module to display menus. Uses TURTLE module for Turtle
* graphics.
*
* If GRAPHICS.LIB was not included in your run-time libraries during
* setup, you must you must add it to the GRDEMO.MAK program list or
* give it on the QCL command line.
*/
#include <graph.h>
#include <math.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include "turtle.h"
#include "menu.h"
/* Function prototypes */
int main( void );
void Circles( void );
void Sphere( void );
int Polygons( void );
int Spiral( int angle, double inc );
int InSpiral( double side, int angle, int inc );
void Bug( void );
void Adjust( void );
void Diamond( double xy );
/* Returns a random number between min and max, which must be in
* integer range.
*/
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
/* Constants */
#define PI 3.141593
#define LASTATR 15
#define NLASTATR 14
/* Array and enum for main menu */
ITEM mnuMain[] =
{ /* Highlight Char Pos */
{ 0, "Quit" }, /* Q 0 */
{ 0, "Circles" }, /* C 0 */
{ 0, "Rotating Sphere" }, /* R 0 */
{ 0, "Tunnel" }, /* T 0 */
{ 0, "Spiral" }, /* S 0 */
{ 0, "Inverted Spiral" }, /* I 0 */
{ 0, "Bug" }, /* B 0 */
{ 0, "Adjust Window" }, /* A 0 */
{ 0, "Mode Change" }, /* M 0 */
{ 0, "" }
};
/* Define constants (0, 1, 2,...) for menu choices */
enum CHOICES
{
QUIT, CIRCLES, SPHERE, TUNNEL, SPIRAL, INSPIRAL, BUG, ADJUST, CHANGE
};
/* Arrays of video mode menu items and of corresponding mode numbers.
* Each has a temporary array containing all items, and a pointer version
* including all except Olivetti.
*/
ITEM mnuModesT[] =
{ /* Highlight Char Pos */
{ 0, "ORESCOLOR " }, /* O 0 */
{ 4, "MRES4COLOR " }, /* 4 4 */
{ 4, "MRESNOCOLOR" }, /* N 4 */
{ 4, "HRESBW" }, /* B 4 */
{ 0, "MRES16COLOR" }, /* M 0 */
{ 0, "HRES16COLOR" }, /* H 0 */
{ 0, "ERESCOLOR" }, /* E 0 */
{ 4, "VRES2COLOR" }, /* 2 4 */
{ 0, "VRES16COLOR" }, /* V 0 */
{ 1, "MRES256COLOR" }, /* R 4 */
{ 0, "" }
};
ITEM *mnuModes = &mnuModesT[1]; /* Default is no Olivetti mode */
int aModesT[] =
{
_ORESCOLOR,
_MRES4COLOR,
_MRESNOCOLOR,
_HRESBW,
_MRES16COLOR,
_HRES16COLOR,
_ERESCOLOR,
_VRES2COLOR,
_VRES16COLOR,
_MRES256COLOR,
_TEXTMONO,
_ERESNOCOLOR,
_HERCMONO
};
int *aModes = &aModesT[1]; /* Default is no Olivetti mode */
/* Global video configuration */
struct videoconfig vc;
int main()
{
int rowMid, colMid;
int fColor, fFirstTime = TRUE;
int iMode, iMainCur = 0, iModesCur = 0;
_displaycursor( _GCURSOROFF );
_getvideoconfig( &vc );
rowMid = vc.numtextrows / 2;
colMid = vc.numtextcols / 2;
/* Select best graphics mode, adjust menus, set color flag. Note
* that this requires checking both the adapter and the mode.
*/
switch( vc.adapter )
{
case _OCGA:
mnuModes = &mnuModesT[0]; /* Turn on Olivetti mode */
aModes = &aModesT[0];
case _CGA:
mnuModesT[4].achItem[0] = '\0'; /* Turn off EGA modes */
iMode = _MRES4COLOR;
break;
case _HGC:
mnuModesT[7].achItem[0] = '\0';
iMode = _HERCMONO;
break;
case _OEGA:
mnuModes = &mnuModesT[0]; /* Turn on Olivetti mode */
aModes = &aModesT[0];
case _EGA:
mnuModesT[7].achItem[0] = '\0'; /* Turn off VGA modes */
if( vc.memory > 64 )
iMode = _ERESCOLOR;
else
iMode = _HRES16COLOR;
break;
case _OVGA:
mnuModes = &mnuModesT[0]; /* Turn on Olivetti mode */
aModes = &aModesT[0];
case _VGA:
iMode = _VRES16COLOR;
break;
case _MCGA:
iMode = _MRES256COLOR;
break;
case _MDPA:
default:
puts( "No graphics mode available.\n" );
return TRUE;
}
switch( vc.mode )
{
case _TEXTBW80:
case _TEXTBW40:
fColor = FALSE;
break;
case _TEXTMONO:
case _ERESNOCOLOR:
case _HERCMONO:
fColor = FALSE;
if( iMode != _HERCMONO )
iMode = _ERESNOCOLOR;
mnuMain[8].achItem[0] = '\0'; /* Turn off mode change */
break;
default:
fColor = TRUE;
break;
}
/* Find current mode in mode array. */
for( iModesCur = 0; aModes[iModesCur] != iMode; iModesCur++ )
;
/* Seed randomizer with time. */
srand( (unsigned)time( NULL ) );
while( TRUE )
{
/* Set text mode and optionally clear the screen to blue. */
_setvideomode(_DEFAULTMODE );
if( fColor )
_setbkcolor( (long)_TBLUE );
_clearscreen( _GCLEARSCREEN );
/* Select from menu. */
iMainCur = Menu( rowMid, colMid, mnuMain, iMainCur );
/* Set graphics mode and initialize turtle graphics. Put border
* on window.
*/
if( iMainCur != CHANGE )
{
_setvideomode( iMode );
_displaycursor( _GCURSOROFF );
_getvideoconfig( &vc );
InitTurtle( &vc );
Rectangle( 2 * tc.xMax, 2 * tc.yMax );
}
/* Branch to menu choice. */
switch( iMainCur )
{
case QUIT:
_setvideomode( _DEFAULTMODE );
return FALSE;
case CIRCLES:
Circles();
break;
case SPHERE:
Sphere();
break;
case TUNNEL:
PenDown( FALSE );
MoveTo( -tc.xMax * .2, tc.yMax * .15 );
PenDown( TRUE );
Polygons();
while( !ClickOrPress() )
NextColorValue( DEFAULT ); /* Rotate palette */
break;
case SPIRAL:
if( Spiral( getrandom( 30, 80 ), (double)getrandom( 1, 5 ) ) )
break;
while( !ClickOrPress() )
NextColorValue( DEFAULT );
break;
case INSPIRAL:
NextColorIndex( 0 );
if( InSpiral( (double)getrandom( 8, 20 ),
getrandom( 4, 22 ),
getrandom( 3, 31 ) ) )
break;
while( !ClickOrPress() )
NextColorValue( DEFAULT );
break;
case BUG:
Bug();
break;
case ADJUST:
Adjust();
continue;
case CHANGE:
if( fColor )
_setbkcolor( (long)_TBLUE );
_clearscreen( _GCLEARSCREEN );
iModesCur = Menu( rowMid, colMid, mnuModes, iModesCur );
iMode = aModes[iModesCur];
if( vc.adapter == _MCGA )
switch( iMode )
{
case _MRES16COLOR:
case _HRES16COLOR:
case _ERESCOLOR:
case _VRES16COLOR:
_settextposition( 1, 22 );
_outtext( "Mode not recognized" );
iMode = _MRES256COLOR;
}
break;
}
}
}
/* Circles - Draw circles of varying sizes and colors on screen in a
* round pattern.
*
* Params: None
*
* Return: None
*
* Uses: tc
*/
void Circles()
{
double x, y, xyRadius;
int fFill, fPenDown;
/* Initialize and save pen and fill flags. */
if( tc.cci <= 4 )
fFill = SetFill( FALSE );
else
fFill = SetFill( TRUE );
fPenDown = PenDown( FALSE );
while( TRUE )
{
/* Draw circles. */
for( xyRadius = 10.0; xyRadius <= 130.0; xyRadius++ )
{
x = (tc.xMax - 30) * atan( sin( xyRadius / PI ) );
y = (tc.yMax - 30) * atan( cos( xyRadius / PI ) );
MoveTo( x, y );
PenColor( NextColorIndex( DEFAULT ) );
Circle( xyRadius );
if( ClickOrPress() )
{
PenDown( fPenDown );
SetFill( fFill );
return;
}
}
/* For palette modes (except 256 color), start over. */
if( tc.ccv == 64 || tc.ccv == 16 )
{
_clearscreen( _GCLEARSCREEN );
SetFill( FALSE );
MoveTo( 0.0, 0.0 );
PenColor( WHITE );
Rectangle( 2 * tc.xMax, 2 * tc.yMax );
SetFill( fFill );
NextColorValue( DEFAULT );
}
}
}
/* Sphere - Draw and fill slices of a sphere. Rotate colors in EGA+ modes
* with more than 4 color indexes.
*
* Params: None
*
* Return: None
*
* Uses: tc
*/
void Sphere()
{
double xCur, xSize, ySize, xInc;
short ciBorder, fFill;
ySize = xSize = tc.yMax * 0.9 * 2;
fFill = SetFill( FALSE );
NextColorIndex( 0 );
xInc = xSize / 14;
ciBorder = PenColor( DEFAULT );
BorderColor( ciBorder );
/* Draw slices. */
for( xCur = xInc; xCur <= xSize; xCur += xInc * 2 )
Ellipse( xCur, ySize );
SetFill( TRUE );
PenDown( FALSE );
Turn( 90 );
xSize /= 2;
MoveTo( xSize - xInc, 0.0 );
NextColorValue( LIMITED );
/* Fill slices. */
while( tc.xCur >= (-xSize + xInc))
{
PenColor( NextColorIndex( DEFAULT ) );
FillIn();
Move( -xInc );
}
while( !GetKey( NO_WAIT ) )
NextColorValue( LIMITED );
PenDown( TRUE );
SetFill( fFill );
}
/* Polygons - Draws polygons (starting with triangle) of increasing
* size by incrementing the number of sides without changing the
* length of sides. Make sure pen is down.
*
* Params: None
*
* Return: 1 for user interrupt, 0 for edge of screen encountered
*
* Uses: tc
*/
int Polygons()
{
int cSides = 3, atrib = 1;
double dxy = tc.yUnit;
while( TRUE )
{
PenColor( NextColorIndex( DEFAULT ) );
if( !Poly( cSides++, dxy += 1.5 ) )
return FALSE;
if( ClickOrPress() )
return TRUE;
}
}
/* Spiral - Draw a spiral by incrementing the length of each side
* of a rotating figure.
*
* Params: ang - determines tightness
* xyInc - determines size of sides
*
* Return: 1 for user interrupt, 0 for edge of screen encountered
*
* Uses: tc
*/
int Spiral( int ang, double xyInc )
{
double xy = tc.yUnit;
while( TRUE )
{
PenColor( NextColorIndex( DEFAULT ) );
if( !Move( xy += xyInc ) )
return FALSE;
Turn( ang );
if( ClickOrPress() )
return TRUE;
}
}
/* InSpiral - Draw an inverted spiral by increasing each angle
* of a rotating figure while keeping the length of sides constant.
*
* Params: xy - determines size
* ang - initial angle determines shape
* angInc - determines tightness and shape
*
* Return: 1 for user interrupt, 0 for edge of screen encountered
*/
int InSpiral( double xy, int ang, int angInc )
{
while( TRUE )
{
PenColor( NextColorIndex( DEFAULT ) );
if( !Move( xy ) )
return FALSE;
Turn( ang += angInc );
if( ClickOrPress())
return TRUE;
}
}
/* Bug - Draws a winged bug on the screen. Then moves it randomly
* around the screen.
*
* Params: None
*
* Return: None
*
* Uses: tc
*/
void Bug()
{
static unsigned char uTopWing[] = { 0x81, 0x3c, 0xc3, 0x66,
0x66, 0x0f, 0xf0, 0x18 };
static unsigned char uBotWing[] = { 0x66, 0x0f, 0xf0, 0x18,
0x81, 0x3c, 0xc3, 0x66 };
char *buffer; /* Buffer for image */
/* Draw bug. */
PenDown( FALSE );
SetFill( TRUE );
Move( 40.0 ); /* Draw and fill front wings */
Turn( 90 );
Move( 80.0 );
PenColor( 1 );
_setfillmask( uTopWing );
Ellipse( 172.0, 70.0 );
Turn( 180 );
Move( 160.0 );
Ellipse( 172.0, 70.0 );
Turn(-90 );
MoveTo( 0.0, 0.0 );
Move( 25.0 ); /* Draw and fill back wings */
Turn( 90 );
Move( 70.0 );
PenColor( 2 );
_setfillmask( uBotWing );
Ellipse( 150.0, 70.0 );
Turn( 180 );
Move( 140.0 );
Ellipse( 150.0, 70.0 );
Turn(-90 );
MoveTo( 0.0, 0.0 );
_setfillmask( NULL ); /* Draw body */
PenColor( 3 );
BorderColor( 3 );
Ellipse( 52.0, 220.0 );
PenColor( 1 ); /* Drill eyes */
BorderColor( 1 );
SetFill( FALSE );
Move( 90.0 );
Turn( 90 );
Move( 22.0 );
Circle( 20.0 );
PenColor( 0 );
FillIn();
PenColor( 1 );
Turn( 180 );
Move( 44.0 );
Circle( 20.0 );
PenColor( 0 );
FillIn();
/* Move into position - top-right of image. */
MoveTo( 0.0, 0.0 );
TurnTo( 0 );
Move( 120.0 );
Turn( -90 );
Move( 175.0 );
Turn( 90 );
/* Size image and allocate memory for it. */
buffer = (char *)malloc( (size_t)ImageSize( 350.0, 240.0 ) );
GetImage( 350.0, 240.0, buffer );
/* Move randomly, adjusting at edges. */
while( !ClickOrPress() )
{
if( tc.xCur <= (-tc.xMax + 15.0) )
TurnTo( 90 );
else if( tc.yCur <= (-tc.yMax + 15.0) )
TurnTo( 180 );
else if( tc.xCur >= (tc.xMax - 365.0) )
TurnTo( 270 );
else if( tc.yCur >= (tc.yMax - 255.0) )
TurnTo( 0 );
else
Turn( getrandom( -20, 20 ) );
Move( 3.0 );
PutImage( buffer, _GPSET );
}
free( (char *)buffer );
}
/* Adjust - Allow the user to interactively adjust the display window.
* Unshifted direction keys adjust the window size. Shifted direction
* keys move the window. The numeric keypad plus and minus keys adjust
* aspect without changing the window. A window frame and a diamond give
* visual feedback on adjustments.
*
* Params: None
*
* Return: None
*
* Uses: tc and vc
*/
#define WININC 4
void Adjust()
{
short i, iWriteMode;
double xyRadius = 400.0, xEdge, yEdge;
char achT[40];
/* Display instructions. */
_clearscreen( _GCLEARSCREEN );
_settextposition( 2, 2 );
_outtext(" Grey PLUS and MINUS Adjust aspect" );
_settextposition( 3, 2 );
_outtext(" Cursor keys Size window" );
_settextposition( 4, 2 );
_outtext(" SHIFT cursor keys Move window" );
_settextposition( 5, 2 );
_outtext(" ENTER Finished" );
/* Save old write mode and set XOR so you can erase figures by
* redrawing. This allows lines to overwrite text without erasing.
*/
iWriteMode = _getwritemode();
_setwritemode( _GXOR );
while( TRUE )
{
/* Display data. */
_settextposition( 6, 2 );
sprintf( achT, " ratio=%1.2f xMax=%.f yMax=%.f",
tc.yxRatio, tc.xMax, tc.yMax );
_outtext( achT );
/* Calculate current box edges. */
xEdge = 2 * tc.xMax;
yEdge = 2 * tc.yMax;
/* Draw border rectangle and diamond that illustrates ratio. */
Rectangle( xEdge, yEdge );
Diamond( xyRadius );
switch( GetKey( CLEAR_WAIT ) )
{
/* Adjust aspect. */
case N_MINUS:
if( tc.yxRatio > 0.4 )
tc.yxRatio = (tc.xMax - (WININC * tc.yUnit)) / tc.yMax;
break;
case N_PLUS:
if( tc.yxRatio < 8.0 )
tc.yxRatio = (tc.xMax + (WININC * tc.yUnit)) / tc.yMax;
break;
/* Adjust window size. */
case U_RT:
if( tc.xsLeft < (vc.numxpixels / 3) )
tc.xsLeft += WININC;
if( tc.xsRight > (vc.numxpixels - (vc.numxpixels / 3)) )
tc.xsRight -= WININC;
break;
case U_LT:
if( tc.xsLeft )
tc.xsLeft -= WININC;
if( tc.xsRight < vc.numxpixels )
tc.xsRight += WININC;
break;
case U_DN:
if( tc.ysTop < (vc.numypixels / 3) )
tc.ysTop += WININC;
if( tc.ysBot > (vc.numypixels - (vc.numypixels / 3)) )
tc.ysBot -= WININC;
break;
case U_UP:
if( tc.ysTop )
tc.ysTop -= WININC;
if( tc.ysBot < vc.numypixels )
tc.ysBot += WININC;
break;
/* Adjust window position. */
case S_LT:
if( tc.xsLeft )
{
tc.xsLeft -= WININC;
tc.xsRight -= WININC;
}
break;
case S_RT:
if( tc.xsRight < vc.numxpixels )
{
tc.xsLeft += WININC;
tc.xsRight += WININC;
}
break;
case S_UP:
if( tc.ysTop )
{
tc.ysTop -= WININC;
tc.ysBot -= WININC;
}
break;
case S_DN:
if( tc.ysBot < vc.numypixels )
{
tc.ysTop += WININC;
tc.ysBot += WININC;
}
break;
/* Finished. */
case ENTER:
_setwritemode( iWriteMode );
return;
/* Ignore unknown key. */
default:
break;
}
/* Redraw figures to erase them. Reset defaults. */
Rectangle( xEdge, yEdge );
Diamond( xyRadius );
Home();
}
}
/* Routine used by Adjust to draw its diamond. */
void Diamond( double xy )
{
PenDown( FALSE );
MoveTo( 0.0, xy );
PenDown( TRUE );
MoveTo( xy, 0.0 );
MoveTo( 0.0, -xy );
MoveTo( -xy, 0.0 );
MoveTo( 0.0, xy );
PenDown( FALSE );
MoveTo( 0.0, 0.0 );
PenDown( TRUE );
}