/*
*     ___                       ____ ___
*    / _ \___ _    _____ ____  |_  // _ \
*   / ___/ _ \ |/|/ / -_) __/ _/_ </ // /
*  /_/   \___/__,__/\__/_/   /____/____/
*
*
*   Original Code by John Garrison
*   Written September 1-11, 1999
*
*   To be released under the LGPL
*
*   Basic drawing of 3d solid objects
*
*   See LICENSE.TXT for more LGPL info
*/

#ifdef USE_P3D

#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "power3d.h"
#include "objects3d.h"

static mat_t matstack[STACKDEPTH] = {
    {{{1.0, 0.0, 0.0, 0.0},
    {0.0, 1.0, 0.0, 0.0},
    {0.0, 0.0, 1.0, 0.0},
    {0.0, 0.0, 0.0, 1.0}},
    {{1.0, 0.0, 0.0},
    {0.0, 1.0, 0.0},
    {0.0, 0.0, 1.0}}}
};

static int identitymat = 1;

static int mattop = 0;


/////////////////////////////////////////
//          INTERNAL ROUTINES          //
/////////////////////////////////////////

P3D_Vertex3P Normalize(P3D_Vertex3P Vertex)
{
   P3D_Vertex3P vertex;
   float Length;

   Length = (float)sqrt((Vertex.x * Vertex.x) + (Vertex.y * Vertex.y) + (Vertex.z * Vertex.z));

   if (Length == 0.0f) Length = 1.0f;

   vertex.x = Vertex.x / Length;
   vertex.y = Vertex.y / Length;
   vertex.z = Vertex.z / Length;

   return vertex;
}



void normalize(GLdouble v[3])
{
    GLdouble d;

    d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
    if (d == 0.0) {
        v[0] = d = 1.0;
    }
    d = 1/d;
    v[0] *= d; v[1] *= d; v[2] *= d;
}



void m_xformpt(GLdouble pin[3], GLdouble pout[3],
    GLdouble nin[3], GLdouble nout[3])
{
    int i;
    GLdouble    ptemp[3], ntemp[3];
    mat_t       *m = &matstack[mattop];

    if (identitymat) {
        for (i = 0; i < 3; i++) {
            pout[i] = pin[i];
            nout[i] = nin[i];
        }
        return;
    }
    for (i = 0; i < 3; i++) {
        ptemp[i] = pin[0]*m->mat[0][i] +
                   pin[1]*m->mat[1][i] +
                   pin[2]*m->mat[2][i] +
                   m->mat[3][i];
        ntemp[i] = nin[0]*m->norm[0][i] +
                   nin[1]*m->norm[1][i] +
                   nin[2]*m->norm[2][i];
    }
    for (i = 0; i < 3; i++) {
        pout[i] = ptemp[i];
        nout[i] = ntemp[i];
    }
    normalize(nout);
}



void Drawbox(int listIndex, P3D_Vertex3P v1, P3D_Vertex3P v2, P3D_Vertex3P v3, P3D_Vertex3P v4, P3D_Vertex3P v5, P3D_Vertex3P v6, P3D_Vertex3P v7, P3D_Vertex3P v8, GLenum type)
{
   P3D_Vertex3P n1,n2,n3,n4,n5,n6,n7,n8;

   n1 = Normalize(v1);
   n2 = Normalize(v2);
   n3 = Normalize(v3);
   n4 = Normalize(v4);
   n5 = Normalize(v5);
   n6 = Normalize(v6);
   n7 = Normalize(v7);
   n8 = Normalize(v8);

   glNewList(listIndex,GL_COMPILE);
      glBegin(type);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
      glEnd();
      glBegin(type);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n7.x, n7.y, n7.z);
         glVertex3f(v7.x, v7.y, v7.z);
         glNormal3f(n8.x, n8.y, n8.z);
         glVertex3f(v8.x, v8.y, v8.z);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
      glEnd();
      glBegin(type);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
      glEnd();
      glBegin(type);
         glNormal3f(n8.x, n8.y, n8.z);
         glVertex3f(v8.x, v8.y, v8.z);
         glNormal3f(n7.x, n7.y, n7.z);
         glVertex3f(v7.x, v7.y, v7.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
      glEnd();
      glBegin(type);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
         glNormal3f(n8.x, n8.y, n8.z);
         glVertex3f(v8.x, v8.y, v8.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
      glEnd();
      glBegin(type);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n7.x, n7.y, n7.z);
         glVertex3f(v7.x, v7.y, v7.z);
      glEnd();
   glEndList();
}



void Drawpyramid(int listIndex, P3D_Vertex3P v1, P3D_Vertex3P v2, P3D_Vertex3P v3, P3D_Vertex3P v4, P3D_Vertex3P v5, GLenum type1, GLenum type2)
{
   P3D_Vertex3P n1,n2,n3,n4,n5;

   n1 = Normalize(v1);
   n2 = Normalize(v2);
   n3 = Normalize(v3);
   n4 = Normalize(v4);
   n5 = Normalize(v5);

   glNewList(listIndex,GL_COMPILE);
      glBegin(type1);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
      glEnd();
      glBegin(type1);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
      glEnd();
      glBegin(type1);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
      glEnd();
      glBegin(type1);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
      glEnd();
    glBegin(type2);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
      glEnd();
   glEndList();
}



void Drawprizm(int listIndex, P3D_Vertex3P v1, P3D_Vertex3P v2, P3D_Vertex3P v3, P3D_Vertex3P v4, P3D_Vertex3P v5, P3D_Vertex3P v6, GLenum type1, GLenum type2)
{
   P3D_Vertex3P n1,n2,n3,n4,n5,n6;

   n1 = Normalize(v1);
   n2 = Normalize(v2);
   n3 = Normalize(v3);
   n4 = Normalize(v4);
   n5 = Normalize(v5);
   n6 = Normalize(v6);

   glNewList(listIndex,GL_COMPILE);
      glBegin(type1);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
      glEnd();
      glBegin(type1);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
      glEnd();
      glBegin(type2);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
      glEnd();
      glBegin(type2);
         glNormal3f(n1.x, n1.y, n1.z);
         glVertex3f(v1.x, v1.y, v1.z);
         glNormal3f(n4.x, n4.y, n4.z);
         glVertex3f(v4.x, v4.y, v4.z);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
      glEnd();
      glBegin(type2);
         glNormal3f(n6.x, n6.y, n6.z);
         glVertex3f(v6.x, v6.y, v6.z);
         glNormal3f(n3.x, n3.y, n3.z);
         glVertex3f(v3.x, v3.y, v3.z);
         glNormal3f(n2.x, n2.y, n2.z);
         glVertex3f(v2.x, v2.y, v2.z);
         glNormal3f(n5.x, n5.y, n5.z);
         glVertex3f(v5.x, v5.y, v5.z);
      glEnd();
   glEndList();
}

/* doughnut:
 *
 * draws a doughnut, centered at (0, 0, 0) whose axis is aligned with
 * the z-axis.  The doughnut's major radius is R, and minor radius is r.
 */
void _doughnut(GLdouble r, GLdouble R, GLint nsides, GLint rings, GLenum type)
{
    int i, j;
    GLdouble    theta, phi, theta1, phi1;
    GLdouble    p0[03], p1[3], p2[3], p3[3];
    GLdouble    n0[3], n1[3], n2[3], n3[3];

    for (i = 0; i < rings; i++) {
        theta = (GLdouble)i*2.0*PI/rings;
        theta1 = (GLdouble)(i+1)*2.0*PI/rings;
        for (j = 0; j < nsides; j++) {
            phi = (GLdouble)j*2.0*PI/nsides;
            phi1 = (GLdouble)(j+1)*2.0*PI/nsides;

            p0[0] = cos(theta)*(R + r*cos(phi));
            p0[1] = -sin(theta)*(R + r*cos(phi));
            p0[2] = r*sin(phi);

            p1[0] = cos(theta1)*(R + r*cos(phi));
            p1[1] = -sin(theta1)*(R + r*cos(phi));
            p1[2] = r*sin(phi);

            p2[0] = cos(theta1)*(R + r*cos(phi1));
            p2[1] = -sin(theta1)*(R + r*cos(phi1));
            p2[2] = r*sin(phi1);

            p3[0] = cos(theta)*(R + r*cos(phi1));
            p3[1] = -sin(theta)*(R + r*cos(phi1));
            p3[2] = r*sin(phi1);

            n0[0] = cos(theta)*(cos(phi));
            n0[1] = -sin(theta)*(cos(phi));
            n0[2] = sin(phi);

            n1[0] = cos(theta1)*(cos(phi));
            n1[1] = -sin(theta1)*(cos(phi));
            n1[2] = sin(phi);

            n2[0] = cos(theta1)*(cos(phi1));
            n2[1] = -sin(theta1)*(cos(phi1));
            n2[2] = sin(phi1);

            n3[0] = cos(theta)*(cos(phi1));
            n3[1] = -sin(theta)*(cos(phi1));
            n3[2] = sin(phi1);

            m_xformpt(p0, p0, n0, n0);
            m_xformpt(p1, p1, n1, n1);
            m_xformpt(p2, p2, n2, n2);
            m_xformpt(p3, p3, n3, n3);

            glBegin(type);
                glNormal3dv(n3);
                glVertex3dv(p3);
                glNormal3dv(n2);
                glVertex3dv(p2);
                glNormal3dv(n1);
                glVertex3dv(p1);
                glNormal3dv(n0);
                glVertex3dv(p0);
            glEnd();
        }
    }
}



///////////////////////////////////////
//          SPHERE ROUTINES          //
///////////////////////////////////////

P3D_Object P3D_CreateWireSphere (float Radius, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
           quadObj = gluNewQuadric ();
           gluQuadricDrawStyle (quadObj, GLU_LINE);
           gluQuadricNormals (quadObj, GLU_SMOOTH);
           gluSphere (quadObj, Radius, 16, 16);
         glEndList();
   }

   return temp;
}



P3D_Object P3D_CreateSolidSphere (float Radius, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            quadObj = gluNewQuadric ();
            gluQuadricDrawStyle (quadObj, GLU_FILL);
            gluQuadricNormals (quadObj, GLU_SMOOTH);
            gluSphere (quadObj, Radius, 16, 16);
         glEndList();
   }

   return temp;
}



//////////////////////////////////////////
//          RECTANGLE ROUTINES          //
//////////////////////////////////////////

P3D_Object P3D_CreateWireCube (float Size, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6,v7,v8;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Size/2, -Size/2, Size/2);
         v2 = P3D_FillVertex3P(Size/2, -Size/2, Size/2);
         v3 = P3D_FillVertex3P(-Size/2, Size/2, Size/2);
         v4 = P3D_FillVertex3P(Size/2, Size/2, Size/2);
         v5 = P3D_FillVertex3P(-Size/2, -Size/2, -Size/2);
         v6 = P3D_FillVertex3P(Size/2, -Size/2, -Size/2);
         v7 = P3D_FillVertex3P(-Size/2, Size/2, -Size/2);
         v8 = P3D_FillVertex3P(Size/2, Size/2, -Size/2);

         Drawbox(listIndex, v1, v2, v3, v4, v5, v6, v7, v8, GL_LINE_LOOP);
      }

   return temp;
}



P3D_Object P3D_CreateSolidCube (float Size, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6,v7,v8;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Size/2, -Size/2, Size/2);
         v2 = P3D_FillVertex3P(Size/2, -Size/2, Size/2);
         v3 = P3D_FillVertex3P(-Size/2, Size/2, Size/2);
         v4 = P3D_FillVertex3P(Size/2, Size/2, Size/2);
         v5 = P3D_FillVertex3P(-Size/2, -Size/2, -Size/2);
         v6 = P3D_FillVertex3P(Size/2, -Size/2, -Size/2);
         v7 = P3D_FillVertex3P(-Size/2, Size/2, -Size/2);
         v8 = P3D_FillVertex3P(Size/2, Size/2, -Size/2);

         Drawbox(listIndex, v1, v2, v3, v4, v5, v6, v7, v8, GL_QUADS);
      }

   return temp;
}


P3D_Object P3D_CreateWireBox(float Width, float Height, float Depth, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6,v7,v8;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Width/2, -Height/2, Depth/2);
         v2 = P3D_FillVertex3P(Width/2, -Height/2, Depth/2);
         v3 = P3D_FillVertex3P(-Width/2, Height/2, Depth/2);
         v4 = P3D_FillVertex3P(Width/2, Height/2, Depth/2);
         v5 = P3D_FillVertex3P(-Width/2, -Height/2, -Depth/2);
         v6 = P3D_FillVertex3P(Width/2, -Height/2, -Depth/2);
         v7 = P3D_FillVertex3P(-Width/2, Height/2, -Depth/2);
         v8 = P3D_FillVertex3P(Width/2, Height/2, -Depth/2);

         Drawbox(listIndex, v1, v2, v3, v4, v5, v6, v7, v8, GL_LINE_LOOP);
   }

   return temp;
}



P3D_Object P3D_CreateSolidBox(float Width, float Height, float Depth, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6,v7,v8;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Width/2, -Height/2, Depth/2);
         v2 = P3D_FillVertex3P(Width/2, -Height/2, Depth/2);
         v3 = P3D_FillVertex3P(-Width/2, Height/2, Depth/2);
         v4 = P3D_FillVertex3P(Width/2, Height/2, Depth/2);
         v5 = P3D_FillVertex3P(-Width/2, -Height/2, -Depth/2);
         v6 = P3D_FillVertex3P(Width/2, -Height/2, -Depth/2);
         v7 = P3D_FillVertex3P(-Width/2, Height/2, -Depth/2);
         v8 = P3D_FillVertex3P(Width/2, Height/2, -Depth/2);

         Drawbox(listIndex, v1, v2, v3, v4, v5, v6, v7, v8, GL_QUADS);
   }

   return temp;
}



//////////////////////////////////////
//          TORUS ROUTINES          //
//////////////////////////////////////

P3D_Object P3D_CreateWireTorus (float InnerRadius, float OuterRadius, P3D_Color Color)
{
   P3D_Object temp;

   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            _doughnut(InnerRadius, OuterRadius, 5, 10, GL_LINE_LOOP);
         glEndList();
   }

   return temp;
}



P3D_Object P3D_CreateSolidTorus (float InnerRadius, float OuterRadius, P3D_Color Color)
{
   P3D_Object temp;

   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            _doughnut(InnerRadius, OuterRadius, 8, 15, GL_QUADS);
         glEndList();
   }

   return temp;
}



/////////////////////////////////////////
//          CYLINDER ROUTINES          //
/////////////////////////////////////////

P3D_Object P3D_CreateWireCylinder (float Radius, float Height, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            glPushMatrix ();
            glRotatef (90.0, 1.0, 0.0, 0.0);
            glTranslatef (0.0, 0.0, -1.0);
            quadObj = gluNewQuadric ();
            gluQuadricDrawStyle (quadObj, GLU_LINE);
            gluQuadricNormals (quadObj, GLU_SMOOTH);
            gluCylinder (quadObj, Radius, Radius, Height, 12, 2);
            glPopMatrix ();
         glEndList();
   }

   return temp;
}



P3D_Object P3D_CreateSolidCylinder (float Radius, float Height, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            glPushMatrix ();
            glRotatef (90.0, 1.0, 0.0, 0.0);
            glTranslatef (0.0, 0.0, -1.0);
            quadObj = gluNewQuadric ();
            gluQuadricDrawStyle (quadObj, GLU_FILL);
            gluQuadricNormals (quadObj, GLU_SMOOTH);
            gluCylinder (quadObj, Radius, Radius, Height, 12, 2);
            glPopMatrix ();
         glEndList();
   }

   return temp;
}



P3D_Object P3D_CreateWireCone (float Base, float Height, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            quadObj = gluNewQuadric ();
            gluQuadricDrawStyle (quadObj, GLU_LINE);
            gluQuadricNormals (quadObj, GLU_SMOOTH);
            gluCylinder (quadObj, Base, 0.0, Height, 15, 10);
         glEndList();
   }

   return temp;
}



P3D_Object P3D_CreateSolidCone (float Base, float Height, P3D_Color Color)
{
   P3D_Object temp;

   GLUquadricObj *quadObj;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         glNewList(listIndex,GL_COMPILE);
            quadObj = gluNewQuadric ();
            gluQuadricDrawStyle (quadObj, GLU_FILL);
            gluQuadricNormals (quadObj, GLU_SMOOTH);
            gluCylinder (quadObj, Base, 0.0, Height, 15, 10);
         glEndList();
   }

   return temp;
}



/////////////////////////////////////////
//          TRIANGLE ROUTINES          //
/////////////////////////////////////////

/* All of the below triangle routines are orininal functions by me.
Don't expect the same quality of lighting with these as I am just
learning about normals */

/* Draws a wireframe priszm */
P3D_Object P3D_CreateWirePrizm (float Width, float Length, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Length/2.0, -Width/2.0, 0.0);
         v2 = P3D_FillVertex3P(-Length/2.0, Width/2.0, -Width/2.0);
         v3 = P3D_FillVertex3P(-Length/2.0, Width/2.0, Width/2.0);
         v4 = P3D_FillVertex3P(Length/2.0, -Width/2.0, 0.0);
         v5 = P3D_FillVertex3P(Length/2.0, Width/2.0, -Width/2.0);
         v6 = P3D_FillVertex3P(Length/2.0, Width/2.0, Width/2.0);

         Drawprizm(listIndex, v1, v2, v3, v4, v5, v6, GL_LINE_LOOP, GL_LINE_LOOP);
   }

   return temp;
}



/* Draws a solid prizm */
P3D_Object P3D_CreateSolidPrizm (float Width, float Length, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5,v6;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Length/2.0, -Width/2.0, 0.0);
         v2 = P3D_FillVertex3P(-Length/2.0, Width/2.0, -Width/2.0);
         v3 = P3D_FillVertex3P(-Length/2.0, Width/2.0, Width/2.0);
         v4 = P3D_FillVertex3P(Length/2.0, -Width/2.0, 0.0);
         v5 = P3D_FillVertex3P(Length/2.0, Width/2.0, -Width/2.0);
         v6 = P3D_FillVertex3P(Length/2.0, Width/2.0, Width/2.0);

         Drawprizm(listIndex, v1, v2, v3, v4, v5, v6, GL_TRIANGLES, GL_QUADS);
   }

   return temp;
}



P3D_Object P3D_CreateWirePyramid (float Base, float Height, P3D_Color Color)
{
   P3D_Vertex3P v1,v2,v3,v4,v5;
   P3D_Object temp;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Base/2.0, Height/2.0, -Base/2.0);
         v2 = P3D_FillVertex3P(Base/2.0, Height/2.0, -Base/2.0);
         v3 = P3D_FillVertex3P(-Base/2.0, Height/2.0, Base/2.0);
         v4 = P3D_FillVertex3P(Base/2.0, Height/2.0, Base/2.0);
         v5 = P3D_FillVertex3P(0.0, -Height/2.0, 0.0);

         Drawpyramid(listIndex, v1, v2, v3 ,v4, v5, GL_LINE_LOOP, GL_LINE_LOOP);
   }

   return temp;
}



P3D_Object P3D_CreateSolidPyramid (float Base, float Height, P3D_Color Color)
{
   P3D_Object temp;
   P3D_Vertex3P v1,v2,v3,v4,v5;
   int listIndex;

   listIndex=glGenLists(1);
      if(listIndex!=0) {
         temp.list = listIndex;
         temp.color = Color;
         temp.posx = 0;
         temp.posy = 0;
         temp.posz = 0;
         temp.rotx = 0;
         temp.roty = 0;
         temp.rotz = 0;

         v1 = P3D_FillVertex3P(-Base/2.0, Height/2.0, -Base/2.0);
         v2 = P3D_FillVertex3P(Base/2.0, Height/2.0, -Base/2.0);
         v3 = P3D_FillVertex3P(-Base/2.0, Height/2.0, Base/2.0);
         v4 = P3D_FillVertex3P(Base/2.0, Height/2.0, Base/2.0);
         v5 = P3D_FillVertex3P(0.0, -Height/2.0, 0.0);

         Drawpyramid(listIndex, v1, v2, v3 ,v4, v5, GL_TRIANGLES, GL_QUADS);
   }

   return temp;
}


#endif