dos_compilers/Zortech C++ v30r1/SAMPLE/FG/FGDEMO.C
2024-07-02 08:01:21 -07:00

1867 lines
57 KiB
C

/*_ fgdemo.c */
/* Copyright Prototronics */
/* 6490 Kaniksu Shores Circle */
/* Sandpoint, ID 83864-9445 */
/* Joe Huffman */
/* September 18, 1990 */
/* FAX: 208-263-8772 */
/* email: fg@proto.com */
/* Modified by Joe Huffman March 30, 1991*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <fg.h>
struct fg_state *demostate_p = &fg;
/**********************************/
/* Useful macros. */
#define arraysize(array) (sizeof(array) / sizeof(array[0]))
#define key_waiting() kbhit()
#define key_input() getch()
#define ESC 27
typedef struct {fg_coord_t x, y;} point_t; /* an (x,y) pair */
typedef struct {fg_coord_t g_x0, g_y0, g_z0, g_x, g_y, g_z;} three_d_t;
fg_box_t inner_box;
fg_color_t next_color (fg_color_t ex_color);
void beam_bounce (void);
void fancy_lines (void);
void lots_of_boxes (void);
void next_color_init (void), next_color_term (void);
void next_color_setcolormap (void);
fg_pbox_t rand_box (fg_pbox_t to_box, fg_pbox_t outer_box);
void press_any (void);
fg_coord_t star_delta (long int, fg_coord_t, fg_coord_t);
void explode_box (fg_const_pbox_t box);
void fixed_stars (int num, fg_box_t clipbox);
void clearscreen(void);
void stars (void);
void terminate (void);
void border (void);
void demo_text (char *);
void dissolve_demo(void);
void bounce_line (fg_box_t clipbox, int erase);
#define BOUNCE_INIT 0
#define BOUNCE_NORMAL 1
#define BOUNCE_ERASE -1
static char press_any_string [] = "Esc to exit, any other key to continue.";
void demo_functions (void);
void ellipse_demo (void);
typedef long int scale_t;
#define SCALE(a) ((scale_t)(a * 200.0))
#define UNSCALE(a) ((scale_t)((a)/200))
scale_t int_sin (int);
scale_t int_cos (int);
int int_arctan (scale_t slope);
void pyramid(int mode,point_t loc, scale_t scale_x, int phi);
void rotate_pyramids (void);
void blit_demo(void);
void mouse_demo(void);
void demo_fill_patterns(void);
main()
{
if (fg_init_all () == FG_NULL)
{
fputs (
#if DOS386 /* 8514A not supported yet. */
"Unable to initialize graphics display device.\n\
This demo requires a CGA, EGA, VGA, TOSHIBA or Hercules graphics board.\n\
If this program was unable to properly sense the correct graphics board\n\
automatically type \"set FG_DISPLAY=XXXX\" at the DOS prompt where XXXX is one\n\
of the following:\n\
\tCGAHIRES\t\tCGAMEDRES\n\
\tEGAECD\t\t\tEGACOLOR\n\
\tEGALOWRES\t\tEVGAHIRES\n\
\tHERC\t\t\tORCHIDPROHIRES\n\
\tPARADISEHIRES\t\tTRIDENTHIRES\n\
\tVGA11\t\t\tVGA12\n\
\tVGA13\t\t\tVEGAVGAHIRES\n\
\tVESA{0|1|2|3|5|7}\tVESA6A\n\
\tTOSHIBA\n\
\tDFIHIRES\n\n\
Where:\tEGAECD means the EGA card with an enhanced color display.\n\
\tEGACOLOR means the EGA card with a color display.\n\
\tVEGAVGAHIRES means Video 7 Vega VGA card in 800 x 600 mode.\n\
\tVGA11 means the VGA card is to be run in mode 11 (hex).\n\
\tVGA12 means the VGA card is to be run in mode 12 (hex).\netc...", stderr);
#else /* DOS386 */
#if M_UNIX || M_XENIX
"Unable to initialize graphics display device.\n\
This demo requires a EGA or VGA graphics board.\n\
If this program was unable to properly sense the correct graphics board\n\
automatically type \"setenv FG_DISPLAY XXXX\" at the shell prompt where\n\
XXXX is one of the following:\n\
\tEGAECD\t\t\tEGACOLOR\n\
\tVGA12\t\t\tVGA13\n\
Where:\tEGAECD means the EGA card with an enhanced color display.\n\
\tEGACOLOR means the EGA card with a color display.\n\
\tVGA12 means the VGA card is to be run in mode 12 (hex).\netc...\n", stderr);
#else /* M_UNIX || M_XENIX */
"Unable to initialize graphics display device.\n\
This demo requires a CGA, EGA, VGA, 8514A, TOSHIBA or Hercules graphics board.\n\
If this program was unable to properly sense the correct graphics board\n\
automatically type \"set FG_DISPLAY=XXXX\" at the DOS prompt where XXXX is one\n\
of the following:\n\
\tCGAHIRES\t\tCGAMEDRES\n\
\tEGAECD\t\t\tEGACOLOR\n\
\tEGALOWRES\t\tEVGAHIRES\n\
\tHERC\t\t\tORCHIDPROHIRES\n\
\tPARADISEHIRES\t\tTRIDENTHIRES\n\
\tVGA11\t\t\tVGA12\n\
\tVGA13\t\t\tVEGAVGAHIRES\n\
\tVESA{0|1|2|3|5|7}\tVESA6A\n\
\tTOSHIBA\t\t\t8514A\n\
\tDFIHIRES\n\n\
Where:\tEGAECD means the EGA card with an enhanced color display.\n\
\tEGACOLOR means the EGA card with a color display.\n\
\tVEGAVGAHIRES means Video 7 Vega VGA card in 800 x 600 mode.\n\
\tVGA11 means the VGA card is to be run in mode 11 (hex).\n\
\tVGA12 means the VGA card is to be run in mode 12 (hex).\netc...", stderr);
#endif /* M_UNIX || M_XENIX */
#endif /* DOS386 */
exit (1);
}
next_color_init ();
demo_text (press_any_string);
ellipse_demo ();
blit_demo();
clearscreen();
demo_fill_patterns();
mouse_demo();
clearscreen();
lots_of_boxes ();
clearscreen();
border ();
fixed_stars (200, inner_box);
stars ();
dissolve_demo();
clearscreen();
rotate_pyramids ();
demo_text ("Press any key to exit...");
terminate ();
return 0;
}
int _FAR dissolve_stop(void)
{
if(key_waiting())
{
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
return 0; /* Stop. */
}
return 1; /* Keep going. */
}
/****************************************************************************
Helper function for dissolve_demo(). Returns non-zero if specified bit is
set.
March 30, 1991
****************************************************************************/
int matrix_bit(char *m_p, fg_const_pbox_t box, fg_coord_t x, fg_coord_t y)
{
int offset = y * ((fg_box_width(box) + 7)/CHAR_BIT) + x/CHAR_BIT;
unsigned char mask = 1 << ((CHAR_BIT - 1) - (x % CHAR_BIT));
return m_p[offset] & mask;
}
void dissolve_demo()
{
static fg_box_t box_dissolve = {0,0,88,16};
#define BOX_WIDTH 89
#define BOX_HEIGHT 17
#define BOX_AREA (BOX_WIDTH * BOX_HEIGHT)
static char matrix_dissolve [204] =
{
0xff,0x06,0x0f,0xc1,0xf8,0x3f,0x83,0x00,0xc0,0x18,0x7f,0x80, /* XXXXXXXX XX XXXXXX XXXXXX XXXXXXX XX XX XX XXXXXXXX */
0xff,0x86,0x1f,0xc3,0xf8,0x7f,0xc3,0x00,0xc0,0x18,0x7f,0x80, /* XXXXXXXXX XX XXXXXXX XXXXXXX XXXXXXXXX XX XX XX XXXXXXXX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0xc0,0x18,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0x60,0x30,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0x60,0x30,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0x60,0x30,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0x30,0x60,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x18,0x03,0x00,0x60,0xc3,0x00,0x30,0x60,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x1f,0xc3,0xf8,0x60,0xc3,0x00,0x30,0x60,0x7c,0x00, /* XX XX XX XXXXXXX XXXXXXX XX XX XX XX XX XXXXX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x18,0xc0,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x18,0xc0,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x18,0xc0,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x0d,0x80,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x0d,0x80,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xc1,0x86,0x00,0xc0,0x18,0x60,0xc3,0x00,0x0d,0x80,0x60,0x00, /* XX XX XX XX XX XX XX XX XX XX XX */
0xff,0x86,0x1f,0xc3,0xf8,0x7f,0xc3,0xfe,0x07,0x00,0x7f,0x80, /* XXXXXXXXX XX XXXXXXX XXXXXXX XXXXXXXXX XXXXXXXXX XXX XXXXXXXX */
0xff,0x06,0x1f,0x83,0xf0,0x3f,0x83,0xfe,0x07,0x00,0x7f,0x80, /* XXXXXXXX XX XXXXXX XXXXXX XXXXXXX XXXXXXXXX XXX XXXXXXXX */
};
fg_coord_t x, y;
fg_box_t box;
fg_color_t text[BOX_AREA], back_color, fore_color;
back_color = FG_LIGHT_BLUE == -1? FG_BLACK: FG_LIGHT_BLUE;
fore_color = FG_LIGHT_WHITE;
fg_fillboxdissolve(FG_WHITE,FG_MODE_SET,~0,fg.displaybox,1000,dissolve_stop);
for(y = 0; y < BOX_HEIGHT; y++)
{
for(x = 0; x < BOX_WIDTH; x++)
{
fg_color_t *t_p = &text[y * BOX_WIDTH + x];
if(matrix_bit(matrix_dissolve,box_dissolve,x,box_dissolve[FG_Y2] - y))
*t_p = fore_color;
else
*t_p = back_color;
}
}
fg_box_cpy(box,box_dissolve);
x = (fg_box_width(fg.displaybox) - fg_box_width(box_dissolve))/2;
box[FG_X1] += x;
box[FG_X2] += x;
box[FG_Y1] += y = fg_box_height(fg.displaybox)/2;
box[FG_Y2] += y;
fg_writeboxdissolve(box, text, 1, dissolve_stop);
fg_fillboxdissolve(back_color,FG_MODE_SET,~0,fg.displaybox,1000,dissolve_stop);
#undef BOX_WIDTH
#undef BOX_HEIGHT
#undef BOX_AREA
}
void blit_demo(void)
{
fg_line_t line;
fg_box_t box;
fg_coord_t delta_x, x, delta_y, y;
fg_color_t color = 0;
clearscreen();
line[FG_X1] = fg_box_width(fg.displaybox)/2;
line[FG_Y1] = fg_box_height(fg.displaybox)/2;
for(y = 0; y <= fg.displaybox[FG_Y2]; y += 10)
{
line[FG_Y2] = y;
line[FG_X2] = 0;
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
line[FG_X2] = fg.displaybox[FG_X2];
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
}
for(x = 0; x <= fg.displaybox[FG_X2]; x += 10)
{
line[FG_X2] = x;
line[FG_Y2] = 0;
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
line[FG_Y2] = fg.displaybox[FG_Y2];
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
}
delta_x = fg_box_width(fg.displaybox)/8;
delta_y = fg_box_height(fg.displaybox)/50;
for(x = 0; !key_waiting() && x <= fg.displaybox[FG_X2]; x += delta_x)
{
fg_box_cpy(box,fg.displaybox);
box[FG_X1] = x;
box[FG_X2] = x + delta_x;
if(box[FG_X2] > fg.displaybox[FG_X2])
box[FG_X2] = fg.displaybox[FG_X2];
box[FG_Y1] = box[FG_Y2] - delta_y;
fg_fillbox(FG_BLACK, FG_MODE_SET, ~0, box);
box[FG_Y1] = delta_y;
do
{
fg_blit(box,box[FG_X1],0,0,0);
box[FG_Y2] -= delta_y;
} while (box[FG_Y2] >= box[FG_Y1] && !key_waiting());
}
while(key_waiting())
{
if (key_input () == ESC)
terminate ();
}
}
void center_string(fg_coord_t y, char _FAR *string)
{
char _FAR *p = string;
while(*p) /* Find the length of the string. */
p++;
fg_puts(FG_HIGHLIGHT,FG_MODE_SET, ~0, FG_ROT0,
(fg.displaybox[FG_X2] - ((p - string) * fg_box_width(fg.charbox)))/2, y,
string, fg.displaybox);
}
void rand_fill_pattern(void)
{
fg_pattern_t p;
int i = 15;
do
{
p[i] = rand() & 1? ~rand(): rand();
} while (i-- >= 0);
fg_setfillpattern(FG_FILL_USER_DEFINED,p);
}
void polygon_translate(fg_coord_t *pdest,fg_coord_t *psrc,int vertices,
fg_coord_t x, fg_coord_t y)
{
while(vertices-- >= 0)
{
*pdest++ = *psrc++ + x;
*pdest++ = *psrc++ + y;
}
}
void demo_fill_patterns()
{
fg_coord_t p0[8], pout[8];
int fill_type = FG_FILL_PATTERN_MAX;
/* Initialize the user definable pattern. */
rand_fill_pattern();
/* create a origin based polygon (triangle with one corner at 0,0). */
memset(p0,0,sizeof(p0));
p0[2] = fg_box_width(fg_displaybox)/5;
p0[4] = p0[2]/2;
p0[5] = fg_box_height(fg_displaybox)/4;
do
{
fg_color_t color, erase_color;
fg_coord_t x, y;
char *type_p;
switch(fill_type)
{
default: /* This will initialize things. */
fill_type = FG_FILL_SOLID;
type_p = "SOLID";
x = 0;
y = 0;
break;
case FG_FILL_SOLID: fill_type = FG_FILL_BSLASH; type_p = "BSLASH";
break;
case FG_FILL_BSLASH: fill_type = FG_FILL_SLASH; type_p = "SLASH";
break;
case FG_FILL_SLASH: fill_type = FG_FILL_HATCH; type_p = "HATCH";
break;
case FG_FILL_HATCH: fill_type = FG_FILL_LINE; type_p = "LINE";
x = 0;
y += fg_box_height(fg_displaybox)/3;
break;
case FG_FILL_LINE: fill_type = FG_FILL_THICK_X; type_p = "THICK_X";
break;
case FG_FILL_THICK_X: fill_type = FG_FILL_THIN_X; type_p = "THIN_X";
break;
case FG_FILL_THIN_X: fill_type = FG_FILL_SCALE; type_p = "SCALE";
break;
case FG_FILL_SCALE: fill_type = FG_FILL_WIDEDOT; type_p = "WIDEDOT";
x = 0;
y += fg_box_height(fg_displaybox)/3;
break;
case FG_FILL_WIDEDOT: fill_type = FG_FILL_CLOSEDOT;type_p = "CLOSEDOT";
break;
case FG_FILL_CLOSEDOT: fill_type = FG_FILL_DIAMOND; type_p = "DIAMOND";
break;
case FG_FILL_DIAMOND: fill_type = FG_FILL_USER_DEFINED; type_p = "USER";
break;
}
fg_puts(FG_HIGHLIGHT,FG_MODE_SET,~0,FG_ROT0,x,y,type_p,fg.displaybox);
polygon_translate(pout,p0,3,x,y + fg_box_height(fg.charbox) + 2);
fg_fillpolygonpattern(FG_HIGHLIGHT,FG_MODE_SET,~0,3,pout,fg.displaybox,
fill_type);
color = erase_color = 0;
while(fill_type == FG_FILL_USER_DEFINED && !key_waiting())
{
rand_fill_pattern();
color = (color + 1) % fg.nsimulcolor;
if(color == erase_color)
{
/* Test for a signed or signed number underflow. */
if(--erase_color < 0 || erase_color > fg.nsimulcolor)
erase_color = fg.nsimulcolor - 1;
}
fg_flush();
sleep(2);
fg_fillpolygon(erase_color,FG_MODE_SET,~0,3,pout,fg.displaybox);
fg_fillpolygonpattern(color,FG_MODE_SET,~0,3,pout,fg.displaybox,
fill_type);
}
x += fg_box_width(fg.displaybox)/4;
} while(fill_type != FG_FILL_USER_DEFINED);
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
return;
}
#ifdef __OS2__ /* No support for mouse under OS2. */
void mouse_demo(void)
{
}
#else
/****************************************************************************
A simple demo of the mouse capabilities.
April 10, 1990
****************************************************************************/
char bat_matrix[48] =
{
/* This is drawn with the X's set to WHITE, blanks are unchanged. */
0x00,0x0a,0x00,0x00, /* X X */
0x00,0x0e,0x00,0x00, /* XXX */
0x02,0x15,0x08,0x00, /* X X X X X */
0x07,0x9f,0x3c,0x00, /* XXXX XXXXX XXXX */
0x0f,0xff,0xfe,0x00, /* XXXXXXXXXXXXXXXXXXX */
0x1f,0xff,0xff,0x00, /* XXXXXXXXXXXXXXXXXXXXX */
0x3f,0xff,0xff,0x80, /* XXXXXXXXXXXXXXXXXXXXXXX */
0x7f,0xff,0xff,0xc0, /* XXXXXXXXXXXXXXXXXXXXXXXXX */
0xc7,0x3b,0x9c,0x60, /* XX XXX XXX XXX XXX XX */
0x82,0x11,0x08,0x20, /* X X X X X X */
0x00,0x11,0x00,0x00, /* X X */
0x00,0x2a,0x80,0x00 /* X X X X */
};
char arrow_matrix[15] =
{
0x80, /* X */
0xc0, /* XX */
0xe0, /* XXX */
0xf0, /* XXXX */
0xf8, /* XXXXX */
0xfc, /* XXXXXX */
0xfe, /* XXXXXXX */
0xff, /* XXXXXXXX */
0xfc, /* XXXXXX */
0xf8, /* XXXXX */
0xf8, /* XXXXX */
0xcc, /* XX XX */
0x8c, /* X XX */
0x06, /* XX */
0x06, /* XX */
};
fg_msm_cursor_t bat = {bat_matrix, {0,0,26,11}, 13, 11};
fg_msm_cursor_t arrow = {arrow_matrix,{0,0,7,14}, 0, 14};
void mouse_demo(void)
{
clearscreen();
if(fg.msm)
{
unsigned int status, last_status = 0xffff;
fg_box_t status_box;
static char bat_string[] = "BAT";
static char arrow_string[] = "ARROW";
fg_box_t bat_select, arrow_select;
fg_coord_t x, y, temp;
int in_char, active_page = 0;
char done = 0;
/* Make a box for selecting the bat cursor. */
bat_select[FG_X1] = 0;
bat_select[FG_X2] = sizeof(bat_string) * fg_box_width(fg.charbox);
bat_select[FG_Y2] = fg.displaybox[FG_Y2] - 2 * fg_box_height(fg.charbox);;
bat_select[FG_Y1] = bat_select[FG_Y2] - fg_box_height(fg.charbox);
/* Make a box for selecting the arrow cursor. */
fg_box_cpy(arrow_select, bat_select);
arrow_select[FG_X2] = sizeof(arrow_string) * fg_box_width(fg.charbox);
/* Put the boxes at the correct locations. */
temp = fg_box_width(fg.displaybox)/2;
bat_select[FG_X1] += temp;
bat_select[FG_X2] += temp;
temp -= arrow_select[FG_X2] + fg_box_width(fg.charbox);
arrow_select[FG_X1] += temp;
arrow_select[FG_X2] += temp;
/* Fill in the cursor select boxes on the screen. */
fg_fillbox(FG_HIGHLIGHT, FG_MODE_SET, ~0, arrow_select);
fg_fillbox(FG_HIGHLIGHT, FG_MODE_SET, ~0, bat_select);
temp = fg_box_width(fg.charbox)/2;
fg_puts(FG_HIGHLIGHT, FG_MODE_XOR, ~0, FG_ROT0, arrow_select[FG_X1] + temp,
arrow_select[FG_Y1], arrow_string, fg.displaybox);
fg_puts(FG_HIGHLIGHT, FG_MODE_XOR, ~0, FG_ROT0, bat_select[FG_X1] + temp,
bat_select[FG_Y1], bat_string, fg.displaybox);
center_string(fg.displaybox[FG_Y2]-fg_box_height(fg.charbox),
"Left button selects cursor.");
center_string(3 * fg_box_height(fg.charbox),
"Press F1, F2, F3 to query presses.");
center_string(2 * fg_box_height(fg.charbox),
"Press ^F1, ^F2, ^F3 to query releases.");
center_string(fg_box_height(fg.charbox),
"Press mouse button(s) to change status.");
fg_msm_setcurpos(fg_box_width(fg_displaybox)/2,
fg_box_height(fg_displaybox)/2);
fg_msm_showcursor();
fg_flush();
fg_box_cpy(status_box,fg.displaybox);
status_box[FG_Y2] = fg.charbox[FG_Y2];
do
{
static char press_format[] = "status %d, %u presses, last @%d,%d.";
static char release_format[] = "status %d, %u releases, last @%d,%d.";
char out_string[50];
unsigned int count;
static unsigned int ratio_x = 8, ratio_y = 16;
do
{
status = fg_msm_getstatus(&x, &y);
if(status != last_status)
{
static char motion = 1; /* The default. */
if(status & FG_MSM_RIGHT)
{
motion = ++motion % 2;
fg_msm_motion(motion);
}
if(status & FG_MSM_LEFT)
{
if(fg_pt_inbox(bat_select,x,y))
{
fg_msm_setcursor(bat);
}else
if(fg_pt_inbox(arrow_select,x,y))
{
fg_msm_setcursor(arrow);
}
}
sprintf(out_string, "status:%x, motion:%d, x:%d, y:%d", status,
motion,x,y);
fg_fillbox(FG_BLACK,FG_MODE_SET, ~0, status_box);
center_string(0, out_string);
fg_flush();
last_status = status;
}
} while(!key_waiting());
in_char = key_input();
if (in_char == 0) /* Extended key, function key, whatever. */
in_char = key_input() << 8;
#define F1 (59 << 8)
#define F2 (60 << 8)
#define F3 (61 << 8)
#define F4 (62 << 8)
#define CTRLF1 (94 << 8)
#define CTRLF2 (95 << 8)
#define CTRLF3 (96 << 8)
#define CTRLF4 (97 << 8)
#define UP (72 << 8)
#define DOWN (80 << 8)
out_string[0] = '\0';
switch (in_char)
{
case ESC:
terminate();
break;
case F1:
count = FG_MSM_LEFT;
status = fg_msm_getpress(&count, &x, &y);
sprintf(out_string, press_format, status, count, x, y);
break;
case F2:
count = FG_MSM_MIDDLE;
status = fg_msm_getpress(&count, &x, &y);
sprintf(out_string, press_format, status, count, x, y);
break;
case F3:
count = FG_MSM_RIGHT;
status = fg_msm_getpress(&count, &x, &y);
sprintf(out_string, press_format, status, count, x, y);
break;
case F4:
active_page = (active_page + 1) % fg.numpages;
fg_setactivepage(active_page);
fg_flush();
break;
case CTRLF4:
fg_setdisplaypage(active_page);
fg_flush();
break;
case CTRLF1:
count = FG_MSM_LEFT;
status = fg_msm_getrelease(&count, &x, &y);
sprintf(out_string, release_format, status, count, x, y);
break;
case CTRLF2:
count = FG_MSM_MIDDLE;
status = fg_msm_getrelease(&count, &x, &y);
sprintf(out_string, release_format, status, count, x, y);
break;
case CTRLF3:
count = FG_MSM_RIGHT;
status = fg_msm_getrelease(&count, &x, &y);
sprintf(out_string, release_format, status, count, x, y);
break;
case UP: /* Higher numbers mean slower mouse. */
if(ratio_y < UINT_MAX/2)
{
ratio_x *= 2;
ratio_y *= 2;
}
fg_msm_setratio(ratio_x, ratio_y);
break;
case DOWN: /* Lower numbers mean faster mouse. */
if(ratio_x > 1)
{
ratio_x /= 2;
ratio_y /= 2;
}
fg_msm_setratio(ratio_x, ratio_y);
break;
default:
done = 1;
break;
}
if(out_string[0])
{
fg_fillbox(FG_BLACK,FG_MODE_SET, ~0, status_box);
center_string(0, out_string);
fg_flush();
}
} while(!done);
fg_msm_hidecursor();
while (key_waiting ())
{
if (key_input () == ESC)
terminate ();
}
}
else
{
static char no_mouse[] = "No mouse present.";
fg_puts(FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_ROT0,
(fg.displaybox[FG_X2] -
(sizeof(no_mouse) - 1) * fg_box_width(fg.charbox))/2,
fg_box_height(fg.charbox), no_mouse, fg.displaybox);
if (key_input () == ESC)
terminate ();
}
}
#endif /* __OS2__ */
void clearscreen(void)
{
fg_fillbox (FG_BLACK, FG_MODE_SET, ~0, fg.displaybox);
}
/**********************************
Ask the user to press a key to continue.
**********************************/
void press_any (void)
{
fg_color_t color;
fg_box_t string_box;
fg_box_cpy (string_box, fg.charbox);
string_box [FG_X1] = (fg_box_width (fg.displaybox) -
sizeof (press_any_string) * fg_box_width (fg.charbox))/2;
if (string_box[FG_X1] < fg.displaybox[FG_X1])
string_box[FG_X1] = fg.displaybox[FG_X1];
string_box [FG_X2] = (fg.displaybox [FG_X2] +
sizeof (press_any_string) * fg_box_width (fg.charbox))/2;
if (string_box[FG_X2] > fg.displaybox[FG_X2])
string_box[FG_X2] = fg.displaybox[FG_X2];
fg_fillbox (FG_BLACK, FG_MODE_SET, ~0, string_box);
fg_puts (FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_ROT0, string_box [FG_X1], 0,
press_any_string, fg.displaybox);
fg_flush ();
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
}
/**********************************
A demo of ellispes...
**********************************/
void ellipse_demo (void)
{
fg_coord_t x, y, x_radius, y_radius;
fg_box_t small_box;
clearscreen();
small_box [FG_X1] = fg_box_width (fg.displaybox)/4;
small_box [FG_X2] = 3 * small_box [FG_X1];
small_box [FG_Y1] = fg_box_height (fg.displaybox)/4;
small_box [FG_Y2] = 3 * small_box [FG_Y1];
fg_drawbox (FG_HIGHLIGHT,FG_MODE_SET, ~0,
FG_LINE_DASH_DOTTED, small_box, fg.displaybox);
x_radius = fg_box_width (small_box)/2;
x = fg.displaybox [FG_X2]/2;
y = fg.displaybox [FG_Y2]/2;
do
{
long int temp;
x_radius -= 5;
y -= 2;
temp = ((long int) (x_radius)) * fg.pixelx;
y_radius = temp/((long int)fg.pixely);
fg_drawellipse (next_color (FG_BLACK), FG_MODE_SET, ~0, x, y, x_radius,
y_radius, 0, 3600, small_box);
fg_flush();
} while (x_radius > 0 && !key_waiting ());
press_any ();
clearscreen();
x = fg_box_width (fg.displaybox)/2;
y = fg_box_height (fg.displaybox)/5;
x_radius = 0;
do
{
fg_color_t color = next_color (FG_BLACK);
long int temp = ((long int) (x_radius)) * fg.pixelx;
y_radius = temp/((long int)fg.pixely);
fg_drawellipse (color, FG_MODE_SET, ~0, x, y, x_radius,
y_radius/2, 1800, 3600, fg.displaybox);
fg_drawellipse (color, FG_MODE_SET, ~0, x, y, x_radius,
y_radius * 2, 0, 1800, fg.displaybox);
x_radius += 3;
fg_flush();
} while (x_radius < fg.displaybox [FG_X2]/2 &&
y_radius < fg.displaybox [FG_Y2]/4 && !key_waiting ());
beam_bounce (); /* Continues until a key is input. */
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
}
/**********************************
"Radar" beam bouncing around. Continues until a key is input.
**********************************/
void beam_bounce (void)
{
scale_t slope;
int start_angle, end_angle;
fg_coord_t radius, x, y, diag_len;
slope = SCALE (fg_box_height (fg.displaybox));
slope /= fg_box_width (fg.displaybox);
diag_len = SCALE(fg_box_width (fg.displaybox))/int_cos (int_arctan (slope));
do
{
next_color_init ();
start_angle = int_arctan (slope) * 10;
end_angle = start_angle + 100;
start_angle -= 100;
x = fg.displaybox [FG_X1];
y = fg.displaybox [FG_Y1];
radius = 0;
do
{
fg_drawarc (next_color (FG_BLACK), FG_MODE_XOR, ~0, x, y, radius,
start_angle, end_angle, fg.displaybox);
fg_flush();
radius += 10;
} while (radius <= diag_len && radius < 720);
x = fg.displaybox [FG_X2];
y = fg.displaybox [FG_Y2];
radius = 0;
do
{
fg_drawarc (next_color (FG_BLACK), FG_MODE_XOR, ~0, x, y, radius,
2600, 2700, fg.displaybox);
fg_flush();
radius += 10;
} while (radius <= fg.displaybox [FG_Y2]);
x = fg.displaybox [FG_X2];
y = fg.displaybox [FG_Y1];
start_angle = int_arctan (-slope) * 10;
end_angle = start_angle + 100;
start_angle -= 100;
radius = 0;
do
{
fg_drawarc (next_color (FG_BLACK), FG_MODE_XOR, ~0, x, y, radius,
start_angle, end_angle, fg.displaybox);
fg_flush();
radius += 10;
} while (radius <= diag_len && radius < 720);
x = fg.displaybox [FG_X1];
y = fg.displaybox [FG_Y2];
radius = 0;
do
{
fg_drawarc (next_color (FG_BLACK), FG_MODE_XOR, ~0, x, y, radius,
2700, 2800, fg.displaybox);
fg_flush();
radius += 10;
} while (radius <= fg.displaybox [FG_Y2]);
fg_flush ();
} while (!key_waiting ());
}
/**********************************
Lots of boxes, very fast.
**********************************/
void lots_of_boxes (void)
{
fg_box_t box;
const int n_col = fg.nsimulcolor;
do
{
fg_fillbox (rand() % n_col, FG_MODE_SET, ~0, rand_box(box, fg.displaybox));
fg_flush ();
} while (!key_waiting ());
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
}
/**********************************
Create a new box that fits inside of outer_box but of random size.
**********************************/
fg_pbox_t rand_box (to_box, outer_box)
fg_pbox_t to_box, outer_box;
{
to_box [FG_X2] = (rand () % (fg_box_width (outer_box) - 1)) + 1;
to_box [FG_Y2] = (rand () % (fg_box_height (outer_box) - 1)) + 1;
to_box [FG_X1] = rand () % to_box [FG_X2];
to_box [FG_Y1] = rand () % to_box [FG_Y2];
to_box [FG_X1] += outer_box [FG_X1];
to_box [FG_X2] += outer_box [FG_X1];
to_box [FG_Y1] += outer_box [FG_Y1];
to_box [FG_Y2] += outer_box [FG_Y1];
return to_box;
}
/**********************************
Some fancy looking lines.
**********************************/
void fancy_lines (void)
{
fg_line_t line;
border ();
line [FG_X1] = line [FG_X2] = inner_box [FG_X1];
line [FG_Y1] = inner_box [FG_Y1];
line [FG_Y2] = inner_box [FG_Y2];
do
{
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
line [FG_X2] += 10;
line [FG_Y1] += 10;
} while (line [FG_X2] < inner_box [FG_X2] &&
line [FG_Y1] < inner_box [FG_Y2]);
line [FG_X1] = line [FG_X2] = inner_box [FG_X2];
line [FG_Y1] = inner_box [FG_Y1];
line [FG_Y2] = inner_box [FG_Y2];
do
{
fg_drawline (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_LINE_SOLID, line);
line [FG_X1] -= 10;
line [FG_Y2] -= 10;
} while (line [FG_X1] > inner_box [FG_X1] &&
line [FG_Y2] > inner_box [FG_Y1]);
}
/**********************************
The title of the program.
**********************************/
void demo_text (press_any_string)
char *press_any_string;
{
static fg_box_t flash_box = {0,0,65,12};
static char flash_matrix[117] =
{
0x7f,0xe2,0x00,0x00,0x40,0x0f,0xf0,0x80,0x40, /* XXXXXXXXXX X X XXXXXXXX X X */
0x80,0x02,0x00,0x00,0x40,0x10,0x08,0x80,0x40, /* X X X X X X X */
0x80,0x02,0x00,0x00,0xa0,0x10,0x08,0x80,0x40, /* X X X X X X X X */
0x80,0x02,0x00,0x00,0xa0,0x10,0x00,0x80,0x40, /* X X X X X X X */
0x80,0x02,0x00,0x01,0x10,0x10,0x00,0x80,0x40, /* X X X X X X X */
0x80,0x02,0x00,0x01,0x10,0x10,0x00,0x80,0x40, /* X X X X X X X */
0xff,0x02,0x00,0x02,0x08,0x0f,0xf0,0xff,0xc0, /* XXXXXXXX X X X XXXXXXXX XXXXXXXXXX */
0x80,0x02,0x00,0x03,0xf8,0x00,0x08,0x80,0x40, /* X X XXXXXXX X X X */
0x80,0x02,0x00,0x04,0x04,0x00,0x08,0x80,0x40, /* X X X X X X X */
0x80,0x02,0x00,0x04,0x04,0x00,0x08,0x80,0x40, /* X X X X X X X */
0x80,0x02,0x00,0x08,0x02,0x10,0x08,0x80,0x40, /* X X X X X X X X */
0x80,0x02,0x00,0x08,0x02,0x10,0x08,0x80,0x40, /* X X X X X X X X */
0x80,0x01,0xff,0x10,0x01,0x0f,0xf0,0x80,0x40, /* X XXXXXXXXX X X XXXXXXXX X X */
};
static fg_box_t graphics_box = {0,0,92,12};
static char graphics_matrix[156] =
{
0x7f,0xc1,0xfc,0x00,0x80,0x3f,0x84,0x04,0x7c,0x3f,0x07,0xf0, /* XXXXXXXXX XXXXXXX X XXXXXXX X X XXXXX XXXXXX XXXXXXX */
0x80,0x22,0x02,0x01,0x40,0x20,0x44,0x04,0x10,0x40,0x88,0x08, /* X X X X X X X X X X X X X X X */
0x80,0x22,0x02,0x01,0x40,0x20,0x44,0x04,0x10,0x40,0x08,0x00, /* X X X X X X X X X X X X X */
0x80,0x02,0x02,0x02,0x20,0x20,0x44,0x04,0x10,0x40,0x08,0x00, /* X X X X X X X X X X X X */
0x80,0x02,0x02,0x02,0x20,0x20,0x44,0x04,0x10,0x40,0x08,0x00, /* X X X X X X X X X X X X */
0x80,0x02,0x02,0x04,0x10,0x20,0x44,0x04,0x10,0x40,0x08,0x00, /* X X X X X X X X X X X X */
0x80,0x03,0xfc,0x04,0x10,0x3f,0x87,0xfc,0x10,0x40,0x07,0xf0, /* X XXXXXXXX X X XXXXXXX XXXXXXXXX X X XXXXXXX */
0x83,0xc2,0x02,0x0f,0xf8,0x20,0x04,0x04,0x10,0x40,0x00,0x08, /* X XXXX X X XXXXXXXXX X X X X X X */
0x80,0x22,0x02,0x08,0x08,0x20,0x04,0x04,0x10,0x40,0x00,0x08, /* X X X X X X X X X X X X */
0x80,0x22,0x02,0x10,0x04,0x20,0x04,0x04,0x10,0x40,0x00,0x08, /* X X X X X X X X X X X X */
0x80,0x22,0x02,0x10,0x04,0x20,0x04,0x04,0x10,0x40,0x00,0x08, /* X X X X X X X X X X X X */
0x80,0x22,0x02,0x20,0x02,0x20,0x04,0x04,0x10,0x40,0x80,0x08, /* X X X X X X X X X X X X X */
0x7f,0xc2,0x02,0x20,0x02,0x20,0x04,0x04,0x7c,0x3f,0x07,0xf0, /* XXXXXXXXX X X X X X X X XXXXX XXXXXX XXXXXXX */
};
#if M_UNIX || M_XENIX
static char support_string [] = "Supports EGA and VGA.";
#else
#if !__OS2__
static char support_string [] = "Supports [C|E|V]GA, TIGA, and Hercules.";
#else
static char support_string [] = "Supports CGA, EGA, VGA, and Hercules.";
#endif
#endif
static char demo_string [] = "Demo program for:";
fg_coord_t x, y;
char *cptr, out_str [81];
clearscreen();
fancy_lines ();
x = (fg.displaybox [FG_X2] -
arraysize (demo_string) * fg_box_width(fg.charbox))/2;
y = fg_box_height (fg.displaybox)/4;
y *= 3;
fg_puts (FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_ROT0, x, y, demo_string,
fg.displaybox);
x = (fg_box_width (fg.displaybox) - fg_box_width (flash_box))/2;
y -= fg_box_height (flash_box) + fg_box_height (fg.charbox)/2;
fg_drawmatrix (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_ROT0, x, y,
flash_matrix, flash_box, fg.displaybox);
x = (fg_box_width (fg.displaybox) - fg_box_width (graphics_box))/2;
y -= fg_box_height (graphics_box) + fg_box_height (fg.charbox)/2;
fg_drawmatrix (next_color (FG_BLACK), FG_MODE_SET, ~0, FG_ROT0, x, y,
graphics_matrix, graphics_box, fg.displaybox);
x = (fg_box_width (fg.displaybox) -
sizeof (support_string) * fg_box_width (fg.charbox))/2;
y = fg_box_height (fg.displaybox)/2;
fg_puts (FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_ROT0, x, y, support_string,
fg.displaybox);
switch (fg.display)
{
#if !(M_UNIX || M_XENIX || __OS2__)
case FG_ATI61: /* ATI Wonder: 640 x 400 x 256 colors (mode 0x61). */
cptr = "ATI Wonder+ mode 0x61 (640 x 400 x 256 colors)";
break;
case FG_ATI62: /* ATI Wonderboard: 640 x 480 x 256 colors (mode 0x62). */
cptr = "ATI Wonder+ mode 0x62 (640 x 480 x 256 colors)";
break;
case FG_ATI63: /* ATI Wonderboard: 800 x 600 x 256 colors (mode 0x63). */
cptr = "ATI Wonder+ mode 0x63 (800 x 600 x 256 colors)";
break;
case FG_CGAMEDRES: /* IBM CGA in 320*200 color (mode 0x04) */
cptr = "CGA in med res mode";
break;
case FG_EGALOWRES: /* IBM EGA in 320*200 color (mode 0x0D) */
cptr = "EGA in low res mode";
break;
case FG_VGA13: /* IBM VGA in 320*200, 256 colors */
cptr = "VGA mode 13";
break;
case FG_HERCHALF: /* Hercules monochrome, 1 display page */
cptr = "Hercules in Half (one page) mode";
break;
case FG_HERCFULL: /* Hercules monochrome, 2 display pages */
cptr = "Hercules in Full (two page) mode";
break;
case FG_TOSHIBA: /* Toshiba J-3100 */
cptr = "Toshiba";
break;
case FG_8514A:
cptr = "IBM 8514A";
break;
case FG_EVGAHIRES:
cptr = "Everex EVGA board 800 x 600 mode";
break;
case FG_VEGAVGAHIRES:
cptr = "Video 7 Vega VGA 800 x 600 mode";
break;
case FG_PARADISEHIRES:
cptr = "Paradise VGA 800 x 600 mode";
break;
case FG_TRIDENTHIRES:
cptr = "Trident VGA 800 x 600 mode";
break;
case FG_TIGA:
cptr = "TIGA";
break;
case FG_ORCHIDPROHIRES:
cptr = "Orchid Pro Designer VGA 800 x 600 mode";
break;
case FG_DFIHIRES:
cptr = "Diamond Flower Instruments VGA 800 x 600 mode";
break;
case FG_VESA0: /* VESA super VGA in 640*400, 256 colors */
cptr = "VESA VGA mode 100, 640 x 400 x 256 colors";
break;
case FG_VESA1: /* VESA super VGA in 640*480, 256 colors */
cptr = "VESA VGA mode 101, 640 x 480 x 256 colors";
break;
case FG_VESA2: /* VESA super VGA in 800*600, 16 colors */
cptr = "VESA VGA mode 102, 800 x 600 x 16 colors";
break;
case FG_VESA3: /* VESA super VGA in 800*600, 256 colors */
cptr = "VESA VGA mode 103, 800 x 600 x 256 colors";
break;
case FG_VESA5: /* VESA super VGA in 1024*768, 256 colors */
cptr = "VESA VGA mode 105, 1024 x 768 x 256 colors";
break;
case FG_VESA7: /* VESA super VGA in 1280*1024, 256 colors */
cptr = "VESA VGA mode 107, 1280 x 1024 x 256 colors";
break;
case FG_VESA6A: /* VESA super VGA in 800*600, 16 colors */
cptr = "VESA VGA mode 6A, 800 x 600 x 16 colors";
break;
#endif /* UNIX || XENIX || __OS2__ */
case FG_CGAHIRES: /* IBM CGA in 640*200 (mode 0x06) */
cptr = "CGA high resolution mode";
break;
case FG_EGACOLOR: /* IBM EGA with regular color display (mode 0x0E) */
cptr = "EGA with a IBM Color Display";
break;
case FG_EGAMONO: /* IBM EGA with IBM monochrome monitor (mode 0x0F) */
cptr = "EGA with a Monochrome Display";
break;
case FG_EGAECD: /* IBM EGA with enhanced color display (mode 0x10) */
cptr = "EGA with an Enhanced Color Display";
break;
case FG_VGA11: /* IBM VGA in 640*480, 1 color */
cptr = "VGA mode 11, 2 color";
break;
case FG_VGA12: /* IBM VGA in 640*480, 16 colors */
cptr = "VGA mode 12, 16 colors";
break;
default:
assert (0);
}
sprintf (out_str, "Graphics device: %s.", cptr);
y -= 2 * fg_box_height (fg.charbox);
center_string(y, out_str);
y -= 2 * fg_box_height (fg.charbox);
center_string(y, "FG library version:");
y -= 2 * fg_box_height (fg.charbox);
center_string(y, fg.version);
y -= 2 * fg_box_height (fg.charbox);
center_string(y, press_any_string);
#if M_UNIX || M_XENIX
y -= 2 * fg_box_height (fg.charbox);
center_string(y, "Use 'Ctrl-Alt Fn' to change multiscreen.");
#endif
fg_flush ();
bounce_line (fg.displaybox, BOUNCE_INIT);
while (!key_waiting ())
bounce_line (fg.displaybox, BOUNCE_NORMAL);
do
{
if (key_input () == ESC)
terminate ();
} while (key_waiting ());
}
/**********************************
And now, an attempt to be clever.
**********************************/
void rotate_pyramids (void)
{
scale_t size;
int page;
int phi;
point_t loc1, loc2;
page = 0;
loc1.x = 0;
loc2.x = fg.displaybox [FG_X2];
loc1.y = fg.displaybox [FG_Y2]/2;
loc2.y = fg.displaybox [FG_Y2]/2;
phi = 0;
size = 1;
while (!key_waiting () && loc2.x > 0)
{
if (fg.numpages > 1) /* If more than one page swap back and forth.*/
{
page ^= 1;
fg_setactivepage (page); /* Swap output pages. */
}
clearscreen();
pyramid (FG_MODE_SET, loc1, size, phi);
pyramid (FG_MODE_SET, loc2, size, -phi);
#if 0
pyramid (FG_MODE_SET, loc1, size/4, -2 * phi);
pyramid (FG_MODE_SET, loc2, size/4, 2 * phi);
#endif
if (fg.numpages > 1) /* If more than one page swap back and forth. */
fg_setdisplaypage (page);
loc1.x += 2;
loc2.x -= 2;
phi += 5;
if (phi > 360)
phi -= 360;
if (loc2.x > fg.displaybox [FG_X2]/2)
size++;
else
size--;
}
while (key_waiting ())
{
if (key_input () == ESC)
terminate ();
}
}
/**********************************
Draw a three dimensional pyramid. It is upright when phi is PI/2;
**********************************/
void pyramid (int mode,point_t loc, scale_t scale_x, int phi)
{
#define PYR_POINT 0
#define PYR_BASE1 1
#define PYR_BASE2 2
#define PYR_BASE3 3
#define PYR_BASE4 4
#define PYRAMID_PTS 5
three_d_t c [PYRAMID_PTS];
scale_t c_phi, s_phi;
scale_t scale_y;
int i, line_style;
fg_line_t line;
fg_coord_t d, h, w;
i = PYRAMID_PTS - 1;
do
{
c[i].g_x0 = c[i].g_y0 = c[i].g_z0 = 0;
} while (--i >= 0);
w = fg.displaybox [FG_X2];
d = fg.displaybox [FG_X2];
h = fg.displaybox [FG_Y2];
c [PYR_POINT].g_z0 = h; /* Point is the height in the z direction. */
c [PYR_BASE1].g_y0 = d/2; /* Front corner of the base. */
c [PYR_BASE3].g_y0 = -d/2; /* Back corner of the base. */
c [PYR_BASE4].g_x0 = w/2; /* Right corner of the base. */
c [PYR_BASE2].g_x0 = -w/2; /* Left corner of the base. */
c_phi = int_cos (phi);
s_phi = int_sin (phi);
scale_y = fg.pixelx * scale_x;
scale_y /= fg.pixely;
/* Do the coordinate transformation. */
i = PYRAMID_PTS - 1;
do
{
c[i].g_y = loc.y +
UNSCALE (scale_y * (UNSCALE (c[i].g_y0 * c_phi) +
UNSCALE (c[i].g_z0 * s_phi)));
c[i].g_x = loc.x + UNSCALE (scale_x * c[i].g_x0);
c[i].g_z = UNSCALE (c[i].g_y0 * s_phi - c[i].g_z0 * c_phi);
} while (--i >= 0);
next_color_init ();
fg_drawellipse (FG_HIGHLIGHT, mode, ~0,
c[PYR_POINT].g_x, c[PYR_POINT].g_y, (int) (UNSCALE (scale_x * h/16)),
(int) (UNSCALE (scale_y * h/16)), 0, 3600, fg.displaybox);
#if 0 /* Too slow. */
fg_fillpattern(c[PYR_POINT].g_x,c[PYR_POINT].g_y,next_color(FG_BLACK),
FG_HIGHLIGHT,FG_FILL_WIDEDOT);
#endif
fg_make_line (line, c[PYR_BASE1].g_x, c[PYR_BASE1].g_y, c[PYR_BASE2].g_x,
c[PYR_BASE2].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, FG_LINE_SOLID, line,
fg.displaybox);
fg_make_line (line, c[PYR_BASE1].g_x, c[PYR_BASE1].g_y, c[PYR_BASE4].g_x,
c[PYR_BASE4].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, FG_LINE_SOLID, line,
fg.displaybox);
fg_make_line (line, c[PYR_BASE2].g_x, c[PYR_BASE2].g_y, c[PYR_BASE3].g_x,
c[PYR_BASE3].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, FG_LINE_SOLID, line,
fg.displaybox);
fg_make_line (line, c[PYR_BASE3].g_x, c[PYR_BASE3].g_y, c[PYR_BASE4].g_x,
c[PYR_BASE4].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, FG_LINE_SOLID, line,
fg.displaybox);
if (c[PYR_POINT].g_z <= 0 && c[PYR_BASE1].g_z <= 0)
line_style = FG_LINE_SPARSE_DOTTED;
else
line_style = FG_LINE_SOLID;
fg_make_line (line, c[PYR_POINT].g_x, c[PYR_POINT].g_y, c[PYR_BASE1].g_x,
c[PYR_BASE1].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, line_style, line,
fg.displaybox);
if (c[PYR_POINT].g_z <= 0 && c[PYR_BASE2].g_z <= 0)
line_style = FG_LINE_SPARSE_DOTTED;
else
line_style = FG_LINE_SOLID;
fg_make_line (line, c[PYR_POINT].g_x, c[PYR_POINT].g_y, c[PYR_BASE2].g_x,
c[PYR_BASE2].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, line_style, line,
fg.displaybox);
if (c[PYR_POINT].g_z <= 0 && c[PYR_BASE3].g_z <= 0)
line_style = FG_LINE_SPARSE_DOTTED;
else
line_style = FG_LINE_SOLID;
fg_make_line (line, c[PYR_POINT].g_x, c[PYR_POINT].g_y, c[PYR_BASE3].g_x,
c[PYR_BASE3].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, line_style, line,
fg.displaybox);
if (c[PYR_POINT].g_z <= 0 && c[PYR_BASE4].g_z <= 0)
line_style = FG_LINE_SPARSE_DOTTED;
else
line_style = FG_LINE_SOLID;
fg_make_line (line, c[PYR_POINT].g_x, c[PYR_POINT].g_y, c[PYR_BASE4].g_x,
c[PYR_BASE4].g_y);
fg_drawlineclip (next_color (FG_BLACK), mode, ~0, line_style, line,
fg.displaybox);
fg_flush ();
}
void fixed_stars (num, clipbox)
int num;
fg_box_t clipbox;
{
fg_coord_t temp1, temp2;
int star;
temp1 = clipbox [FG_X2] - clipbox [FG_X1];
temp2 = clipbox [FG_Y2] - clipbox [FG_Y1];
for (star = num; star; star--)
{
fg_coord_t x, y;
x = (rand () % temp1) + clipbox [FG_X1];
y = (rand () % temp2) + clipbox [FG_Y1];
fg_drawdot (next_color (FG_BLACK), FG_MODE_SET, ~0, x, y);
}
}
#define NUM_STARS 700
#define STAR_TIME 5
typedef struct star
{
fg_coord_t x, y, speed; fg_color_t color; struct star *next_star;
} star_t;
void stars (void)
{
clock_t t0, t1;
star_t *list_p, *s_p;
fg_coord_t mid_x, mid_y, temp1, temp2;
int num_stars;
mid_x = (fg.displaybox [FG_X2] + 1)/2;
mid_y = (fg.displaybox [FG_Y2] + 1)/2;
num_stars = NUM_STARS;
s_p = list_p = calloc (sizeof (star_t), 1);
while (1)
{
s_p->color = next_color (FG_BLACK); /* Pick a color, excluding black. */
s_p->x = mid_x;
s_p->y = mid_y;
s_p->speed = rand () % 8 + 1;
if (--num_stars)
{
s_p->next_star = calloc (sizeof (star_t), 1);
s_p = s_p->next_star;
}
else
{
s_p->next_star = (star_t *) NULL;
break;
}
}
t0 = clock ();
do
{
t1 = clock () - t0;
for (s_p = list_p; s_p != NULL; s_p = s_p->next_star)
{
fg_coord_t delta_x, delta_y;
/* Erase the star. */
fg_drawdot (s_p->color, FG_MODE_XOR, ~0, s_p->x, s_p->y);
/* Move the star. */
delta_x = star_delta (t1 * s_p->speed, s_p->x, mid_x);
delta_y = star_delta (t1 * s_p->speed, s_p->y, mid_y);
if (delta_x == 0 && delta_y == 0)
{ /* -4, -3, -2, -1, 0, 1, 2, 3, 4 */
delta_x = (4 - rand () % 9) * s_p->speed;
delta_y = (4 - rand () % 9) * s_p->speed;
}
s_p->x += delta_x;
s_p->y += delta_y;
/* Is it time to kill it? */
if (s_p->x < inner_box [FG_X1] || s_p->x > inner_box [FG_X2] ||
s_p->y < inner_box [FG_Y1] || s_p->y > inner_box [FG_Y2])
{
/* Kill the star (actually just move it to the center). */
s_p->x = mid_x;
s_p->y = mid_y;
}
else /* Draw the star again. */
fg_drawdot (s_p->color, FG_MODE_XOR, ~0, s_p->x, s_p->y);
}
/* Do this for a few seconds. */
} while (!key_waiting () && t1 >= 0 && t1 < STAR_TIME * CLK_TCK);
/* Free up the memory and give a "star burst". */
do
{
fg_line_t line;
s_p = list_p;
list_p = s_p->next_star;
line [FG_X1] = s_p->x;
line [FG_Y1] = s_p->y;
line [FG_X2] = s_p->x + star_delta (10 * t1, s_p->x, mid_x);
line [FG_Y2] = s_p->y + star_delta (10 * t1, s_p->y, mid_y);
fg_drawlineclip (s_p->color, FG_MODE_SET, ~0, FG_LINE_SOLID, line,
inner_box);
free (s_p);
} while (list_p != NULL);
while (key_waiting ())
{
if (key_input () == ESC)
terminate ();
}
}
/*******************************
Calculate the delta change in position for this coordinate.
*/
fg_coord_t star_delta (speed, p, mid)
long int speed;
fg_coord_t p, mid;
{
return (speed * (p - mid))/2000;
}
static int next_color_index = 0;
int next_colormap[32] =
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
/*******************************
Initialize the next color function.
*/
void next_color_init (void)
{
if (next_color_index == 0)
next_color_setcolormap ();
else
next_color_index = 0;
}
/****************************
Initialize the list of availiable colors.
****************************/
void next_color_setcolormap (void)
{ int i;
i = 0;
next_colormap[i++] = FG_BLACK;
next_colormap[i++] = FG_BLUE;
next_colormap[i++] = FG_GREEN;
next_colormap[i++] = FG_CYAN;
/* FG_BLUE_GREEN is the same as CYAN. */
/* next_colormap[i++] = FG_BLUE_GREEN; */
next_colormap[i++] = FG_RED;
next_colormap[i++] = FG_LIGHT_WHITE;
next_colormap[i++] = FG_MAGENTA;
/* Purple is the same as magenta. */
/* next_colormap[i++] = FG_PURPLE; */
next_colormap[i++] = FG_YELLOW;
next_colormap[i++] = FG_WHITE;
next_colormap[i++] = FG_GRAY;
next_colormap[i++] = FG_LIGHT_BLUE;
next_colormap[i++] = FG_LIGHT_RED;
next_colormap[i++] = FG_LIGHT_GREEN;
next_colormap[i++] = FG_LIGHT_CYAN;
/* Light BLUE_GREEN is the same as LIGHT_CYAN. */
/* next_colormap[i++] = FG_LIGHT_BLUE_GREEN; */
next_colormap[i++] = FG_LIGHT_MAGENTA;
next_colormap[i++] = FG_BROWN;
/* normally an intense white */
/* Same as LIGHT_WHITE */
/* next_colormap[i++] = FG_HIGHLIGHT; */
/* blinking white */
next_colormap[i++] = FG_BLINK;
}
/*******************************
Terminiate the next color package.
*/
void next_color_term (void)
{
return;
}
/*******************************
* Pick a color excluding this one color.
*/
fg_color_t next_color (fg_color_t ex_color)
{
do
{
next_color_index++;
next_color_index %= sizeof(next_colormap)/sizeof(next_colormap[0]);
} while (next_colormap[next_color_index] == -1 ||
next_colormap [next_color_index] == ex_color);
return next_colormap [next_color_index];
}
/**************************************
Bounce a line off the edges of the screen.
**************************************/
void bounce_line (clipbox, erase)
fg_box_t clipbox;
int erase;
{
static fg_line_t old_line, new_line;
static fg_color_t old_color, new_color;
static fg_coord_t vel_x1 = 10, vel_x2 = 15, vel_y1 = 10, vel_y2 = 16;
if (erase == BOUNCE_INIT)
{
new_line[FG_X1] = new_line[FG_Y1] = new_line[FG_X2] = new_line[FG_Y2] = 0;
new_color = FG_BLACK;
}
/* Save the last line. */
fg_line_cpy (old_line, new_line);
old_color = new_color;
/* Create the new line. */
new_color = next_color (FG_BLACK);
new_line[FG_X1] += vel_x1; new_line[FG_X2] += vel_x2;
new_line[FG_Y1] += vel_y1; new_line[FG_Y2] += vel_y2;
if ((unsigned)new_line[FG_X1] > clipbox[FG_X2])
{
fg_coord_t temp;
new_line[FG_X1] = new_line[FG_X1] > 0? clipbox[FG_X2]: 0;
vel_x1 = (vel_x1 > 0? -1: 1) * (rand () % 32);
temp = 32 + (vel_x1 > 0? -vel_x1: vel_x1);
vel_y1 = vel_y1 > 0? temp: -temp;
}
if ((unsigned)new_line[FG_Y1] > clipbox[FG_Y2])
{
fg_coord_t temp;
new_line[FG_Y1] = new_line[FG_Y1] > 0? clipbox[FG_Y2]: 0;
vel_y1 = (vel_y1 > 0? -1: 1) * (rand () % 32);
temp = 32 + (vel_y1 > 0? -vel_y1: vel_y1);
vel_x1 = vel_x1 > 0? temp: -temp;
}
if ((unsigned)new_line[FG_X2] > clipbox[FG_X2])
{
fg_coord_t temp;
new_line[FG_X2] = new_line[FG_X2] > 0? clipbox[FG_X2]: 0;
vel_x2 = (vel_x2 > 0? -1: 1) * (rand () % 32);
temp = 32 + (vel_x2 > 0? -vel_x2: vel_x2);
vel_y2 = vel_y2 > 0? temp: -temp;
}
if ((unsigned) new_line[FG_Y2] > clipbox [FG_Y2])
{
fg_coord_t temp;
new_line[FG_Y2] = new_line[FG_Y2] > 0? clipbox[FG_Y2]: 0;
vel_y2 = (vel_y2 > 0? -1: 1) * (rand () % 32);
temp = 32 + (vel_y2 > 0? -vel_y2: vel_y2);
vel_x2 = vel_x2 > 0? temp: -temp;
}
/* Erase the old line. */
if (erase != BOUNCE_INIT &&
(old_line[FG_X1] != old_line[FG_X2] || old_line[FG_Y1] != old_line[FG_Y2]))
{
fg_drawline (old_color, FG_MODE_XOR, ~0, FG_LINE_SOLID, old_line);
}
/* Draw the new line. */
if (erase != BOUNCE_ERASE &&
(new_line[FG_X1] != new_line[FG_X2] || new_line[FG_Y1] != new_line[FG_Y2]))
{
fg_drawline (new_color, FG_MODE_XOR, ~0, FG_LINE_SOLID, new_line);
}
fg_flush ();
}
/****************************
Terminate gracefully.
****************************/
void terminate (void)
{
fg_term ();
exit (0);
}
/****************************
Draw a fancy border around the screen to make the screen look like a view port
from a "space ship".
****************************/
void border (void)
{
unsigned int radius;
int x, y;
fg_drawbox (FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_LINE_SOLID, fg.displaybox,
fg.displaybox);
radius = (fg.displaybox[FG_X2] + 1)/128;
fg_box_cpy (inner_box, fg.displaybox);
inner_box [FG_X1] += radius;
inner_box [FG_X2] -= radius;
inner_box [FG_Y1] += radius;
inner_box [FG_Y2] -= radius;
y = fg.displaybox [FG_Y2];
for (x = fg.displaybox [FG_X2]; x >= 0; x -= 2 * radius)
{
fg_drawarc (next_color (FG_BLACK), FG_MODE_SET, ~0, x, 0, radius, 0, 1800,
fg.displaybox);
fg_drawarc(next_color(FG_BLACK), FG_MODE_SET, ~0, x, y, radius, 1800, 3600,
fg.displaybox);
}
x = fg.displaybox [FG_X2];
for (y = fg.displaybox [FG_Y2]; y >= 0; y -= 2 * radius)
{
fg_drawarc (next_color(FG_BLACK), FG_MODE_SET, ~0, 0, y, radius, 2700, 900,
fg.displaybox);
fg_drawarc (next_color(FG_BLACK), FG_MODE_SET, ~0, x, y, radius, 900, 2700,
fg.displaybox);
}
fg_drawbox (FG_HIGHLIGHT, FG_MODE_SET, ~0, FG_LINE_SOLID, inner_box,
fg.displaybox);
}
/*********************************
A black box that smoothly explodes.
*********************************/
void explode_box (fg_const_pbox_t box)
{
int step, x_mod, y_mod;
fg_box_t b1;
assert (fg_box_width (box));
assert (fg_box_height (box));
b1 [FG_X2] = b1 [FG_X1] = fg_coord_midpoint(box [FG_X1], box [FG_X2]);
b1 [FG_Y2] = b1 [FG_Y1] = fg_coord_midpoint(box [FG_Y1], box [FG_Y2]);
/* Increment both x and y such that both complete at about the same time. */
x_mod = (3 * fg_box_height (box))/fg_box_width (box);
if (x_mod == 0)
x_mod = 1;
y_mod = (3 * fg_box_width (box))/fg_box_height (box);
if (y_mod == 0)
y_mod = 1;
step = 0;
do
{
fg_drawbox (FG_BLACK, FG_MODE_SET, ~0, FG_LINE_SOLID, b1, fg.displaybox);
if (++step % y_mod == 0)
{
if (b1 [FG_Y1] > box [FG_Y1])
b1 [FG_Y1]--;
if (b1 [FG_Y2] < box [FG_Y2])
b1 [FG_Y2]++;
}
if (step % x_mod == 0)
{
if (b1 [FG_X1] > box [FG_X1])
b1 [FG_X1]--;
if (b1 [FG_X2] < box [FG_X2])
b1 [FG_X2]++;
}
} while (b1 [FG_Y1] != box [FG_Y1] || b1 [FG_Y2] != box [FG_Y2] ||
b1 [FG_X1] != box [FG_X1] || b1 [FG_X2] != box [FG_X2]);
fg_drawbox (FG_BLACK, FG_MODE_SET, ~0, FG_LINE_SOLID, b1, fg.displaybox);
}
/*********************************
A look-up table for cosine and sine.
*********************************/
scale_t cos_table [19] =
{ SCALE (1), /* 0 degrees. */
SCALE (.99619), /* 5 degrees. */
SCALE (.98481), /* 10 degrees. */
SCALE (.96592), /* 15 degrees. */
SCALE (.93969), /* 20 degrees. */
SCALE (.90631), /* 25 degrees. */
SCALE (.86603), /* 30 degrees. */
SCALE (.81915), /* 35 degrees. */
SCALE (.76604), /* 40 degrees. */
SCALE (.70711), /* 45 degrees. */
SCALE (.64278), /* 50 degrees. */
SCALE (.57358), /* 55 degrees. */
SCALE (.50000), /* 60 degrees. */
SCALE (.42262), /* 65 degrees. */
SCALE (.34202), /* 70 degrees. */
SCALE (.25882), /* 75 degrees. */
SCALE (.17365), /* 80 degrees. */
SCALE (.08716), /* 85 degrees. */
SCALE (0) /* 90 degrees. */
};
/*********************************
A look-up table version of cosine.
*********************************/
scale_t int_cos (angle)
int angle;
{
int quadrant, remainder;
scale_t answer;
if (angle < 0)
angle = - angle;
angle += 2; /* Round to the nearest 5 degrees. */
remainder = (angle % 90)/5;
quadrant = (angle % 360);
if (quadrant < 90)
{
answer = cos_table [remainder];
} else
if (quadrant < 180)
{
answer = -cos_table [18 - remainder];
} else
if (quadrant < 270)
{
answer = -cos_table [remainder];
} else
if (quadrant < 360)
answer = cos_table [18 - remainder];
else
assert (0);
return answer;
}
/*********************************
A look-up table version of sine.
*********************************/
scale_t int_sin (angle)
int angle;
{
return int_cos (angle - 90);
}
/*********************************
Find the arc tangent.
*********************************/
int int_arctan (slope)
scale_t slope;
{
int angle;
angle = 0;
do
{
scale_t cos_answer, test_slope;
cos_answer = int_cos (angle);
if (cos_answer == 0)
continue;
test_slope = SCALE (int_sin (angle));
test_slope /= cos_answer;
if (test_slope > slope &&
(test_slope >= 0 && slope >= 0 || test_slope < 0 && slope < 0))
{
break;
}
} while ((angle += 5) < 180);
return angle;
}
void _FAR _cdecl fg_assert (const char _FAR *e, const char _FAR *f, unsigned int line)
{
fg_term ();
printf ("FG ASSERT: '%s', %s line %u", (char *)e, (char *)f, line);
exit (1);
}