/*----------------------------------------------------------------------
 *			 TMS340 Graphics Library
 *          Copyright (c) 1990 Texas Instruments Incorporated.
 *                         All Rights Reserved
 *----------------------------------------------------------------------
 * Demonstration Program
 *
 *   This program uses the fill_convex function to draw a rotating 3D
 *   dodecahedron.  Back faces are automatically culled by the
 *   fill_convex function.  Double-buffered video animation is
 *   facilitated through the use of the page_flip and page_busy
 *   functions.  This demo is best run in a graphics mode supporting
 *   double buffering; in a mode with only a single buffer, the flicker
 *   can be annoying.
 *----------------------------------------------------------------------
 *   03/27/90...Original version written...................J.R. Van Aken
 *----------------------------------------------------------------------
 */
#include <gsptypes.h>
#include "colors.h"       /* for color displays */
#include "patterns.h"     /* for black-and-white displays */

/* If MODE not defined at preprocessor command line, set to default. */
#ifndef  MODE
#define  MODE	  0	  /* default graphics mode */
#endif

static CONFIG cfg;

#define NRECTS	  6	/* number of rectangles in background */
#define NVERTS	  20	/* number of vertices in dodecahedron */
#define NFACES	  12	/* number of faces in dodecahedron */
#define NSIDES	  5	/* number of sides per face */
#define N	  4	/* angular increment = 1>>N radians */

typedef long FIX;	       /* 32-bit fixed-pt with 16-bit fraction */
typedef struct { FIX x, y, z; } FIX3D;	/* 3D fixed-pt xyz coordinates */
typedef struct { short x, y; } SHORT2D;  /* 2D short xy coordinates */

/* The x, y and z coordinates for vertices 0 thru 19 of dodecahedron:
 * The coordinates are scaled for a 1024x1024 resolution screen.
 */
static FIX3D vert3D[NVERTS] = {
    {  -75, 196,   0 }, 	      /* vertex number	0 */
    {	75, 196,   0 }, 	      /* vertex number	1 */
    { -121, 121, 121 }, 	      /* vertex number	2 */
    {	 0,  75, 196 }, 	      /* vertex number	3 */

    {  121, 121, 121 }, 	      /* vertex number	4 */
    {  121, 121,-121 }, 	      /* vertex number	5 */
    {	 0,  75,-196 }, 	      /* vertex number	6 */
    { -121, 121,-121 }, 	      /* vertex number	7 */

    { -196,   0,  75 }, 	      /* vertex number	8 */
    {  196,   0,  75 }, 	      /* vertex number	9 */
    {  196,   0, -75 }, 	      /* vertex number 10 */
    { -196,   0, -75 }, 	      /* vertex number 11 */

    { -121,-121, 121 }, 	      /* vertex number 12 */
    {	 0, -75, 196 }, 	      /* vertex number 13 */
    {  121,-121, 121 }, 	      /* vertex number 14 */
    {  121,-121,-121 }, 	      /* vertex number 15 */

    {	 0, -75,-196 }, 	      /* vertex number 16 */
    { -121,-121,-121 }, 	      /* vertex number 17 */
    {  -75,-196,   0 }, 	      /* vertex number 18 */
    {	75,-196,   0 }, 	      /* vertex number 19 */
};

/* Define 12 faces of dodecahedron in terms of vertices 0 thru 19. */
static short face[NFACES][NSIDES] = {
    { 0,  1,  4,  3,  2},	      /* face number  0 */
    { 0,  7,  6,  5,  1},             /* face number  1 */
    { 0,  2,  8, 11,  7},             /* face number  2 */
    { 1,  5, 10,  9,  4},             /* face number  3 */
    { 2,  3, 13, 12,  8},             /* face number  4 */
    { 4,  9, 14, 13,  3},             /* face number  5 */
    { 5,  6, 16, 15, 10},             /* face number  6 */
    { 7, 11, 17, 16,  6},             /* face number  7 */
    { 8, 12, 18, 17, 11},             /* face number  8 */
    {10, 15, 19, 14,  9},             /* face number  9 */
    {18, 12, 13, 14, 19},             /* face number 10 */
    {19, 15, 16, 17, 18},	      /* face number 11 */
};

static SHORT2D rect[NRECTS];
static SHORT2D vert2D[NVERTS];
static SHORT2D pgon[NFACES][NSIDES];

/* Define colors of faces 0 thru 11 of dodecahedron. */
static long color[] = {
    RED,	    GREEN,	    YELLOW,	    BLUE,
    MAGENTA,	    CYAN,	    WHITE,	    LIGHT_RED,
    LIGHT_GREEN,    BROWN,	    LIGHT_MAGENTA,  LIGHT_BLUE,
};


main()
{
    FIX3D *v;
    SHORT2D *p;
    short *f;
    FIX z, scale;
    int hres, vres, dist, i, j, disppage, drawpage;
    int xc, yc, zc, dx, dy, dz, spin, radius;

    /* Initialize graphics environment. */
    if (!set_config(MODE, 1))
	exit(1);		 /* invalid graphics mode number */
    clear_frame_buffer(0);
    get_config(&cfg);
    hres = cfg.mode.disp_hres;	 /* horizontal resolution */
    vres = cfg.mode.disp_vres;	 /* vertical resolution */
    set_draw_origin(hres/2, vres/2);

    /* Scale vertex coordinates to screen, and convert to fixed-point. */
    scale = (hres < vres) ? hres : vres;
    dist = scale;	 /* assumed distance from eye to screen */
    radius = scale*209/1024;  /* approx. radius of dodecahedron */
    for (i = 0; i < NVERTS; i++) {
	vert3D[i].x = scale*vert3D[i].x << 16-10;
	vert3D[i].y = scale*vert3D[i].y << 16-10;
	vert3D[i].z = scale*vert3D[i].z << 16-10;
    }
    dx = 1 + hres/142;
    dy = 1 + vres/137;
    dz = 1 + dist/74;

    /* Scale background rectangles to screen dimensions. */
    for (i = 0, zc = -dist; i < NRECTS; i++, zc += dist/2) {
	z = 256*(zc + 2*dist);
	rect[i].x = dist*(256*hres)/z;
	rect[i].y = dist*(256*vres)/z;
    }
    xc = yc = zc = 0;	 /* initial position of center of dodecahedron */

    /* Each loop below draws one frame of the rotating dodecahedron. */
    disppage = 0;
    drawpage = 1;
    for (;;) {
	page_flip(disppage ^= 1, drawpage ^= 1);

	/* Incrementally move the object in 3 dimensions. */
	if (radius + abs(xc += dx) > hres/2)
	    dx = -dx;
	if (radius + abs(yc += dy) > vres/2)
	    dy = -dy;
	if (abs(zc += dz) > dist)
	    spin = dz = -dz;

	/* Rotate the 20 vertices in the zx plane by 1>>N radians. */
	for (i = 0; i < NVERTS; i++) {
	    v = &vert3D[i];
	    if (spin > 0) {
		v->x += v->z >> N;
		v->z -= v->x >> N;
	    } else {
		v->z += v->x >> N;
		v->x -= v->z >> N;
	    }
	}

	/* Perspective project the 20 vertices onto the screen. */
	for (i = 0; i < NVERTS; i++) {
	    z = 256*(zc + 2*dist) + vert3D[i].z/256;
	    vert2D[i].x = dist*(256*xc + vert3D[i].x/256)/z;
	    vert2D[i].y = dist*(256*yc + vert3D[i].y/256)/z;
	}

	/* Construct the 12 faces. */
	for (i = 0; i < NFACES; i++) {
	    f = face[i];
	    p = pgon[i];
	    for (j = 0; j < NSIDES; j++)
		p[j] = vert2D[f[j]];
	}
	while (page_busy())
	    ;

	/* Draw the background rectangles and the dodecahedron. */
	clear_screen(0);
	set_fcolor(WHITE);
	for (i = 0; i < NRECTS; i++)
	    draw_rect(-1+rect[i].x, -1+rect[i].y,
					     -rect[i].x/2, -rect[i].y/2);
	if (cfg.mode.disp_psize >= 4)
	    for (i = 0; i < NFACES; i++) {	 /* color display */
		set_fcolor(color[i]);
		fill_convex(NSIDES, pgon[i]);
	    }
	else
	    for (i = 0; i < NFACES; i++) {	 /* black and white */
		current_patn.data = (PTR)&patnbits[(i&7)+15];
		set_patn(&current_patn);
		patnfill_convex(NSIDES, pgon[i]);
	    }
    }
}

