/* 
 * cylinder drawing demo 
 *
 * FUNCTION:
 * Basic demo illustrating how to write code to draw
 * the most basic cylinder shape.
 *
 * HISTORY:
 * Linas Vepstas March 1995
 * Copyright (c) 1995 Linas Vepstas <linas@linas.org>
 *
 * Hacked quite a bit to draw borromean rings embedded
 * in an icosahedron
 *  Copyright (c) 2003 
 *  Kapil Hari Paranjape <kapil@imsc.res.in>
 *
 */

/* required include files */
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/gle.h>
#include <math.h>
#include "main.h"

/* the arrays in which we will store the rings */
#define RINGPTS 8
double ring1 [RINGPTS][3];
double ring2 [RINGPTS][3];
double ring3 [RINGPTS][3];
float coloring1 [RINGPTS][3];
float coloring2 [RINGPTS][3];
float coloring3 [RINGPTS][3];
/* The remaining 8 triangles of the icosahedron */
/* Each side is split to incorporate the twisted extrusion */
#define TSPLIT 34
#define TRIPTS 105 /* 3+3*TSPLIT */
double triangle [8] [TRIPTS][3];
float colortri [TRIPTS][3];
/* Contour business */
double twisttri [TRIPTS];
#define CONTPTS 69
double contour [CONTPTS][2];
double contnorm [CONTPTS][2];
double uptri [8] [3];

/* some utilities for filling that array */
#define PNT(points,x,y,z) { 			\
   points[idx][0] = x; 			\
   points[idx][1] = y; 			\
   points[idx][2] = z;			\
   idx ++;				\
}

#define COL(colors,r,g,b) { 			\
   colors[idx][0] = r; 			\
   colors[idx][1] = g; 			\
   colors[idx][2] = b;			\
}

#define PLN(cont,norm,x,y,xn,yn) {		\
	cont[idx][0] = x;		\
	cont[idx][1] = y;		\
	norm[idx][0] = xn;		\
	norm[idx][1] = yn;		\
	idx ++;				\
}

/* 
 * NOTE that neither the first, nor the last segment are drawn.
 * The first & last segment serve only to determine that angle 
 * at which the endcaps are drawn.
 */

void InitStuff (void) {

   int i, j, sgnx, sgny, sgnz;
   int idx = 0;

   /* The important lengths */
   double short_side; /* Short side of Golden rectangle */
   double long_side; /* Long side of Golden rectangle */

   /* Initialize lengths */
   long_side = 6.0*(sqrt(5.0)+1.0)/2.0;
   short_side = 6.0;

   /* initialize the join style here */
   gleSetJoinStyle (TUBE_NORM_EDGE | TUBE_JN_ROUND | TUBE_JN_CAP);

   /* Ring one */
   idx=0;
   PNT (ring1, -short_side,  long_side, 0.0);
   PNT (ring1,  short_side,  long_side, 0.0);
   PNT (ring1,  short_side, -long_side, 0.0);
   PNT (ring1, -short_side, -long_side, 0.0);
   PNT (ring1, -short_side,  long_side, 0.0);
   PNT (ring1,  short_side,  long_side, 0.0);
   PNT (ring1,  short_side, -long_side, 0.0);
   PNT (ring1, -short_side, -long_side, 0.0);
   /* Ring Colors */
   for(idx=0;idx < RINGPTS;++idx){
	   COL (coloring1, 0.2, 0.2, 0.8);
   }
   /* First and last edge are not drawn and are
    * used only to fix the capping shapes */ 
   idx=0; COL (coloring1, 0.0, 0.0, 0.0);
   idx=RINGPTS-1; COL (coloring1, 0.0, 0.0, 0.0);


   /* Ring two */
   idx=0;
   PNT (ring2, 0.0, -short_side,  long_side);
   PNT (ring2, 0.0,  short_side,  long_side);
   PNT (ring2, 0.0,  short_side, -long_side);
   PNT (ring2, 0.0, -short_side, -long_side);
   PNT (ring2, 0.0, -short_side,  long_side);
   PNT (ring2, 0.0,  short_side,  long_side);
   PNT (ring2, 0.0,  short_side, -long_side);
   PNT (ring2, 0.0, -short_side, -long_side);
   /* Ring Colors */
   for(idx=0;idx < RINGPTS;++idx){
	   COL (coloring2, 0.8, 0.2, 0.2);
   }
   /* First and last edge are not drawn and are
    * used only to fix the capping shapes */ 
   idx=0; COL (coloring2, 0.0, 0.0, 0.0);
   idx=RINGPTS-1; COL (coloring2, 0.0, 0.0, 0.0);


   /* Ring three */
   idx=0;
   PNT (ring3,  long_side, 0.0, -short_side);
   PNT (ring3,  long_side, 0.0,  short_side);
   PNT (ring3, -long_side, 0.0,  short_side);
   PNT (ring3, -long_side, 0.0, -short_side);
   PNT (ring3,  long_side, 0.0, -short_side);
   PNT (ring3,  long_side, 0.0,  short_side);
   PNT (ring3, -long_side, 0.0,  short_side);
   PNT (ring3, -long_side, 0.0, -short_side);
   /* Ring Colors */
   for(idx=0;idx < RINGPTS;++idx){
	   COL (coloring3, 0.2, 0.8, 0.2);
   }
   /* First and last edge are not drawn and are
    * used only to fix the capping shapes */ 
   idx=0; COL (coloring3, 0.0, 0.0, 0.0);
   idx=RINGPTS-1; COL (coloring3, 0.0, 0.0, 0.0);


   /* Triangles */
   for(idx=0;idx < TRIPTS;++idx){
/*	   COL (colortri, 0.5, 0.2, 0.2); */
/*	   COL (colortri, 1.0, 0.4, 0.4); */
	   COL (colortri, 0.4, 0.4, 0.4);
   }
   /* First and last edge are not drawn and are
    * used only to fix the capping shapes */ 
   idx=0; COL (colortri, 0.0, 0.0, 0.0);
   idx=TRIPTS-1; COL (colortri, 0.0, 0.0, 0.0);

   for( i=0; i < 8 ; ++i){
	   /* One triangle in each quadrant
	    * so we us the binary bits of the
	    * index to decide the quadrant */
	   sgnx = (i & 1) ? 1 : -1;
	   sgny = (i & 2) ? 1 : -1;
	   sgnz = (i & 4) ? 1 : -1;

	   idx=0;
	   /* Start with dummy side */
	   PNT (triangle[i], sgnx*short_side, sgnz*long_side, sgny*0.0);

	   for(j=0; j<TSPLIT; ++j){
	   	PNT (triangle[i], sgnx*j*long_side/TSPLIT, sgny*(TSPLIT-j)*short_side/TSPLIT, 
				sgnz*((TSPLIT-j)*long_side+j*short_side)/TSPLIT);
	   }

	   for(j=0; j<TSPLIT; ++j){
	   PNT (triangle[i], sgnx*((TSPLIT-j)*long_side+j*short_side)/TSPLIT, sgny*j*long_side/TSPLIT,
			   sgnz*(TSPLIT-j)*short_side/TSPLIT);
	   }

	   for(j=0; j<TSPLIT; ++j){
	   PNT (triangle[i], sgnx*(TSPLIT-j)*short_side/TSPLIT, sgny*((TSPLIT-j)*long_side+j*short_side)/TSPLIT, 
			   sgnz*j*long_side/TSPLIT);
	   }

	   PNT (triangle[i], sgnx*0.0, sgny*short_side, sgnz*long_side);

	   /* End with dummy side */
	   PNT (triangle[i], sgnx*long_side, sgny*0.0, sgnz*short_side);

	   /* This gives the "up" direction for the countour business.
	    * Is it required ? 
	    */
   	   uptri[i][0]=sgnx*1.0; uptri[i][1]=sgny*1.0; uptri[i][2]=sgnz*1.0;
   }

/* Contour business. The twisted extrusion of this contour
 * is supposed to produce a rope made of four strands.
 * These are parameters for the contour
 * A is the separation of the "circles"
 * B is the radius of the "circles"
 */
#define A 0.10
#define B 0.07
/* The "circles" are actually 16-gons */
#define ANGLE (M_PI_4/2)
   
   /* The angles we twist the contour by 
    * per segment of the triangle */
   for (idx=0; idx<TRIPTS; ++idx)
	   twisttri[idx] = 45.0*idx;

   idx=0;
   /* "circle" centred at (A,0) 
    * starts at -pi */
   for (i=-8; i<9; ++i) {
	PLN( contour, contnorm,
			A+B*cos(i*ANGLE), B*sin(i*ANGLE),
			cos(i*ANGLE), sin(i*ANGLE));
   }
   /* "circle" centred at (0,A) 
    * starts at -pi/2 */
   for (i=-4; i<13; ++i) {
	PLN( contour, contnorm,
			B*cos(i*ANGLE), A+B*sin(i*ANGLE),
			cos(i*ANGLE), sin(i*ANGLE));
   }
   /* "circle" centred at (-A,0) 
    * starts at 0 */
   for (i=0; i<17; ++i) {
	PLN( contour, contnorm,
			-A+B*cos(i*ANGLE), B*sin(i*ANGLE),
			cos(i*ANGLE), sin(i*ANGLE));
   }
   /* "circle" centred at (0,-A) 
    * starts at pi/2 = -3*pi/2*/
   for (i=-12; i<5; ++i) {
	PLN( contour, contnorm,
			B*cos(i*ANGLE), -A+B*sin(i*ANGLE),
			cos(i*ANGLE), sin(i*ANGLE));
   }
   /* Close the contour
    * Go back to the start */
   PLN(contour,contnorm, A-B*1.0, 0.0, -1.0, 0.0);

}

/* draw the shape */
void DrawStuff (void) {

   int i;

   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   /* set up some matrices so that the object spins with the mouse */
   glPushMatrix ();
   glTranslatef (0.0, 0.0, -80.0);
   glRotatef (lastx, 0.0, 1.0, 0.0);
   glRotatef (lasty, 1.0, 0.0, 0.0);

   /* An initial rotation to get the 3-D look
    * right away --- xwd can be done without drawing! */
   glRotatef (36.0, 0.0, 1.0, 0.0);
   glRotatef (45.0, 1.0, 0.0, 0.0);

   /* Phew. FINALLY, Draw the rings  -- */
   glePolyCylinder (RINGPTS, ring1, coloring1, 0.5);
   glePolyCylinder (RINGPTS, ring2, coloring2, 0.5);
   glePolyCylinder (RINGPTS, ring3, coloring3, 0.5);
   
   /* Draw the triangles "made" of rope */
   for(i=0;i< 8; ++i) {
	gleTwistExtrusion (CONTPTS, contour, contnorm, uptri[i], TRIPTS, triangle[i], colortri, twisttri);
	/* gleTwistExtrusion (CONTPTS, contour, contnorm, NULL, TRIPTS, triangle[i], colortri, twisttri); */
	/* glePolyCylinder (TRIPTS, triangle[i], colortri, 0.2); */
   }

   glPopMatrix ();

   glutSwapBuffers ();
}

/* ------------------------ end of file ------------------- */
