/* gltools.c
 *
 * OpenGL Tools
 *
 * notes: some function modify current color, just fyi
 *
 */

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "math3d.h"
#include "gltools.h"

GLint gltWriteTGA(const char *szFileName)
{
    FILE *pFile;              /* file pointer */
    TGAHEADER tgaHeader;      /* tga file header */
    unsigned long lImageSize; /* size in bytes of image */
    GLbyte *pBits = NULL;     /* pointer to bits */
    GLint iViewport[4];       /* viewport in pixels */
    GLenum lastBuffer;        /* storage for the current read buffer setting */

    /* get the viewport dimensions */
    glGetIntegerv(GL_VIEWPORT, iViewport);

    /* how big is the image going to be (targas are tightly packed) */
    lImageSize = iViewport[2] * 3 * iViewport[3];

    /* allocate block, if this doesn't work, go home */
    pBits = (GLbyte *) malloc(lImageSize);
    if (pBits == NULL)
    {
        perror("malloc");
        return 0;
    }

    /* read bits from color buffer */
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

    /* get the current read buffer setting and save it, switch to
     * the front buffer and do the read operation, finally, restore
     * the read buffer state
     */
    glGetIntegerv(GL_READ_BUFFER, (GLint *) &lastBuffer);
    glReadBuffer(GL_FRONT);
    glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT,
    GL_UNSIGNED_BYTE, pBits);
    glReadBuffer(lastBuffer);

    /* initialize the targa header */
    tgaHeader.identsize = 0;
    tgaHeader.colorMapType = 0;
    tgaHeader.imageType = 2;
    tgaHeader.colorMapStart = 0;
    tgaHeader.colorMapLength = 0;
    tgaHeader.colorMapBits = 0;
    tgaHeader.xstart = 0;
    tgaHeader.ystart = 0;
    tgaHeader.width = iViewport[2];
    tgaHeader.height = iViewport[3];
    tgaHeader.bits = 24;
    tgaHeader.descriptor = 0;

    /* attempt to open the file */
    pFile = fopen(szFileName, "wb");
    if (pFile == NULL)
    {
        perror("fopen");
        free(pBits); /* free buffer and return error */
        return 0;
    }

    /* write the header */
    fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile);

    /* write the image data */
    fwrite(pBits, lImageSize, 1, pFile);

    /* free temporary buffer and close the file */
    free(pBits);
    fclose(pFile);

    return 1;
}

GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, 
                   GLint *iComponents, GLenum *eFormat)
{
    FILE *pFile;              /* file pointer */
    TGAHEADER tgaHeader;      /* TGA file header */
    unsigned long lImageSize; /* size in bytes of image */
    short sDepth;             /* pixel depth; */
    GLbyte *pBits = NULL;     /* pointer to bits */

    /* default/failed values */
    *iWidth = 0;
    *iHeight = 0;
    *eFormat = GL_BGR_EXT;
    *iComponents = GL_RGB8;

    /* attempt to open the file */
    pFile = fopen(szFileName, "rb");
    if (pFile == NULL)
    {
        perror("fopen");
        return 0;
    }

    /* read in header (binary) */
    fread(&tgaHeader, 18 /* sizeof(TGAHEADER) */, 1, pFile);

    /* get width, height, and depth of texture */
    *iWidth = tgaHeader.width;
    *iHeight = tgaHeader.height;
    sDepth = tgaHeader.bits / 8;

    /* put some validity checks here, very simply, i only understand
     * or care about 8, 24, or 32 bit targas
     */
    if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
        return NULL;

    /* calculate size of image buffer */
    lImageSize = tgaHeader.width * tgaHeader.height * sDepth;

    /* allocate memory and check for success */
    pBits = (GLbyte *) malloc(lImageSize * sizeof(GLbyte));
    if (pBits == NULL)
    {
        perror("malloc");
        return NULL;
    }

    /* read in the bits */
    /* check for read error, this should catch rle or other  */
    /* weird formats that i don't want to recognize */
    if (fread(pBits, lImageSize, 1, pFile) != 1)
    {
        perror("fread");
        free(pBits);
        return NULL;
    }

    /* set opengl format expected */
    switch (sDepth)
    {
        case 3: /* most likely case */
            *eFormat = GL_BGR_EXT;
            *iComponents = GL_RGB8;
            break;
        case 4:
            *eFormat = GL_BGRA_EXT;
            *iComponents = GL_RGBA8;
            break;
        case 1:
            *eFormat = GL_LUMINANCE;
            *iComponents = GL_LUMINANCE8;
            break;
    }

    /* done with file */
    fclose(pFile);

    /* return pointer to image data */
    return pBits;
}

void gltDrawSnowman(void)
{
    GLUquadricObj *pObj; /* quadric object */

    /* main body */
    glPushMatrix();
        pObj = gluNewQuadric();
        gluQuadricNormals(pObj, GLU_SMOOTH);

        glPushMatrix();
            glColor3f(1.0f, 1.0f, 1.0f);
            gluSphere(pObj, .40f, 26, 13); /* bottom */

            /* mid section */
            glTranslatef(0.0f, .550f, 0.0f);
            gluSphere(pObj, .3f, 26, 13);
        
            /* head */
            glTranslatef(0.0f, 0.45f, 0.0f);
            gluSphere(pObj, 0.24f, 26, 13);
        
            /* eyes */
            glColor3f(0.0f, 0.0f, 0.0f);
            glTranslatef(0.1f, 0.1f, 0.21f);
            gluSphere(pObj, 0.02f, 26, 13);
        
            glTranslatef(-0.2f, 0.0f, 0.0f);
            gluSphere(pObj, 0.02f, 26, 13);
        
            /* nose */
            glColor3f(1.0f, 0.3f, 0.3f);
            glTranslatef(0.1f, -0.12f, 0.0f);
            gluCylinder(pObj, 0.04f, 0.0f, 0.3f, 26, 13);
        glPopMatrix();
        
        /* hat */
        glPushMatrix();
            glColor3f(0.0f, 0.0f, 0.0f);
            glTranslatef(0.0f, 1.17f, 0.0f);
            glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
            gluCylinder(pObj, 0.17f, 0.17f, 0.4f, 26, 13);
            
            /* hat brim */
            glDisable(GL_CULL_FACE);
            gluDisk(pObj, 0.17f, 0.28f, 26, 13);
            glEnable(GL_CULL_FACE);
            
            glTranslatef(0.0f, 0.0f, 0.40f);
            gluDisk(pObj, 0.0f, 0.17f, 26, 13);
        glPopMatrix();
    glPopMatrix();

    /* delete the quadric */
    gluDeleteQuadric(pObj);
}

/* this screws up the rendering, possibly becasue it's glut? */
void gltDrawFigures(void)
{
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_LIGHTING);
    glPushMatrix();
        /* scale the figures */
        glScalef(0.02f, 0.02f, 0.02f);

        /* draw red cube */
        glColor3f(1.0f, 0.0f, 0.0f);
        glPushMatrix();
        glutSolidCube(48.0f);
        glPopMatrix();

        /* draw green sphere */
        glColor3f(0.0f, 1.0f, 0.0f);
        glPushMatrix();
        glTranslatef(-60.0f, 0.0f, 0.0f);
        glutSolidSphere(25.0f, 50, 50);
        glPopMatrix();

        /* draw magenta torus */
        glColor3f(1.0f, 0.0f, 1.0f);
        glPushMatrix();
        glTranslatef(0.0f, 0.0f, 60.0f);
        glutSolidTorus(8.0f, 16.0f, 50, 50);
        glPopMatrix();

        /* draw yellow cone */
        glColor3f(1.0f, 1.0f, 0.0f);
        glPushMatrix();
        glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
        glTranslatef(60.0f, 0.0f, -24.0f);
        glutSolidCone(25.0f, 50.0f, 50, 50);
        glPopMatrix();

        /* draw cyan teapot */
        glColor3f(0.0f, 1.0f, 1.0f);
        glPushMatrix();
        glTranslatef(0.0f, 0.0f, -60.0f);
        glutSolidTeapot(25.0f);
        glPopMatrix();
    glPopMatrix();
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
}

void gltDrawTriangle(void)
{
    M3DVector3f vNormal;
    M3DVector3f vCorners[5] = {
        { 0.0f, 0.6f, 0.0f },       /* top           0 */
        { -0.5f, -0.2f, -.50f },    /* back left     1 */
        { 0.5f, -0.2f, -0.50f },    /* back right    2 */
        { 0.5f, -0.2f, 0.5f },      /* front right   3 */
        { -0.5f, -0.2f, 0.5f }      /* front left    4 */
    };

    glBegin(GL_TRIANGLES);
        /* bottom section - two triangles */
        glNormal3f(0.0f, -1.0f, 0.0f);

        /* map texture to geometry */
        glTexCoord2f(1.0f, 1.0f);
        glVertex3fv(vCorners[2]);
        glTexCoord2f(0.0f, 1.0f);
        glVertex3fv(vCorners[4]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[1]);
        glTexCoord2f(1.0f, 1.0f);
        glVertex3fv(vCorners[2]);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3fv(vCorners[3]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[4]);
        
        /* front face */
        m3dFindNormalf(vNormal, vCorners[0], vCorners[4], vCorners[3]);
        glNormal3fv(vNormal);
        glTexCoord2f(0.5f, 1.0f);
        glVertex3fv(vCorners[0]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[4]);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3fv(vCorners[3]);
        
        /* left face */
        m3dFindNormalf(vNormal, vCorners[0], vCorners[1], vCorners[4]);
        glNormal3fv(vNormal);
        glTexCoord2f(0.5f, 1.0f);
        glVertex3fv(vCorners[0]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[1]);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3fv(vCorners[4]);

        /* back face */
        m3dFindNormalf(vNormal, vCorners[0], vCorners[2], vCorners[1]);
        glNormal3fv(vNormal);
        glTexCoord2f(0.5f, 1.0f);
        glVertex3fv(vCorners[0]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[2]);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3fv(vCorners[1]);
        
        /* right face */
        m3dFindNormalf(vNormal, vCorners[0], vCorners[3], vCorners[2]);
        glNormal3fv(vNormal);
        glTexCoord2f(0.5f, 1.0f);
        glVertex3fv(vCorners[0]);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv(vCorners[3]);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3fv(vCorners[2]);
    glEnd();
}

void gltDrawGround(void)
{
    GLfloat fExtent = 20.0f;
    GLfloat fStep = 0.5f;
    GLfloat y = -0.4f;
    GLfloat iLine;

    glLineWidth(1.0f);
    glBegin(GL_LINES);
    for (iLine = -fExtent; iLine <= fExtent; iLine += fStep)
    {
        glVertex3f(iLine, y, fExtent);
        glVertex3f(iLine, y, -fExtent);
        glVertex3f(fExtent, y, iLine);
        glVertex3f(-fExtent, y, iLine);
    }
    glEnd();
}

void gltDrawUnitAxes(void)
{
    GLUquadricObj *pObj; /* temporary, used for quadrics */

    /* measurements */
    float fAxisRadius = 0.025f;
    float fAxisHeight = 1.0f;
    float fArrowRadius = 0.06f;
    float fArrowHeight = 0.1f;

    /* setup the quadric object */
    pObj = gluNewQuadric();
    gluQuadricDrawStyle(pObj, GLU_FILL);
    gluQuadricNormals(pObj, GLU_SMOOTH);
    gluQuadricOrientation(pObj, GLU_OUTSIDE);
    gluQuadricTexture(pObj, GLU_FALSE);

    /* draw the blue z axis first with arrowed head */
    glColor3f(0.0f, 0.0f, 1.0f);
    gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
    glPushMatrix();
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
    glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
    gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
    glPopMatrix();

    /* draw the red x axis 2nd with arrowed head */
    glColor3f(1.0f, 0.0f, 0.0f);
    glPushMatrix();
    glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
    gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
    glPushMatrix();
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
    glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
    gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
    glPopMatrix();
    glPopMatrix();

    /* draw the green y axis 3rd with arrowed head */
    glColor3f(0.0f, 1.0f, 0.0f);
    glPushMatrix();
    glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
    gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
    glPushMatrix();
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
    glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
    gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
    glPopMatrix();
    glPopMatrix();

    /* white sphere at origin */
    glColor3f(1.0f, 1.0f, 1.0f);
    gluSphere(pObj, 0.05f, 15, 15);

    /* delete the quadric */
    gluDeleteQuadric(pObj);
}

/* draw a torus (doughnut), using the current 1d texture for light shading */
/* this funct accepts 4x4 trans matrix to be applied to the vertices */
void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, 
                  GLint numMinor)
{
    M3DVector3f vNormal;
    double majorStep = 2.0f * M3D_PI / numMajor;
    double minorStep = 2.0f * M3D_PI / numMinor;
    int i, j;

    for (i = 0; i < numMajor; ++i)
    {
        double a0 = i * majorStep;
        double a1 = a0 + majorStep;
        GLfloat x0 = (GLfloat) cos(a0);
        GLfloat y0 = (GLfloat) sin(a0);
        GLfloat x1 = (GLfloat) cos(a1);
        GLfloat y1 = (GLfloat) sin(a1);

        glBegin(GL_TRIANGLE_STRIP);
        for (j = 0; j <= numMinor; ++j)
        {
            double b = j * minorStep;
            GLfloat c = (GLfloat) cos(b);
            GLfloat r = minorRadius * c + majorRadius;
            GLfloat z = minorRadius * (GLfloat) sin(b);

            glTexCoord2f((float) (i) / (float) (numMajor), (float) (j) \
                         / (float) (numMinor));
            vNormal[0] = x0 * c;
            vNormal[1] = y0 * c;
            vNormal[2] = z / minorRadius;
            m3dNormalizeVectorf(vNormal);
            glNormal3fv(vNormal);
            glVertex3f(x0 * r, y0 * r, z);

            glTexCoord2f((float) (i + 1) / (float) (numMajor), (float) (j) \
                         / (float) (numMinor));
            vNormal[0] = x1 * c;
            vNormal[1] = y1 * c;
            vNormal[2] = z / minorRadius;
            m3dNormalizeVectorf(vNormal);
            glNormal3fv(vNormal);
            glVertex3f(x1 * r, y1 * r, z);
        }
        glEnd();
    }
}

void gltDrawJet(void)
{
    M3DVector3f vNormal;

    /* nose cone, points straight down, set material color */
    /* follow few lines use manual approach */
    glBegin(GL_TRIANGLES);
    glNormal3f(0.0f, -1.0f, 0.0f);
    glNormal3f(0.0f, -1.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 60.0f);
    glVertex3f(-15.0f, 0.0f, 30.0f);
    glVertex3f(15.0f, 0.0f, 30.0f);

    /* verticies for this panel */
    {
    M3DVector3f vPoints[3] = { { 15.0f, 0.0f, 30.0f },
                               { 0.0f, 15.0f, 30.0f },
                               { 0.0f, 0.0f, 60.0f  } };

    /* calculate the normal for the plane */
    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 0.0f, 60.0f   },
                               { 0.0f, 15.0f, 30.0f  },
                               { -15.0f, 0.0f, 30.0f } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    /* body of the plane */
    {
    M3DVector3f vPoints[3] = { { -15.0f, 0.0f, 30.0f },
                               { 0.0f, 15.0f, 30.0f  },
                               { 0.0f, 0.0f, -56.0f  }};

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 0.0f, -56.0f },
                               { 0.0f, 15.0f, 30.0f },
                               { 15.0f, 0.0f, 30.0f } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    glNormal3f(0.0f, -1.0f, 0.0f);
    glVertex3f(15.0f, 0.0f, 30.0f);
    glVertex3f(-15.0f, 0.0f, 30.0f);
    glVertex3f(0.0f, 0.0f, -56.0f);

    /* left wing, large triangle for bottom of wing */
    {
    M3DVector3f vPoints[3] = { { 0.0f, 2.0f, 27.0f   },
                               { -60.0f, 2.0f, -8.0f },
                               { 60.0f, 2.0f, -8.0f  } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 60.0f, 2.0f, -8.0f },
                               { 0.0f, 7.0f, -8.0f  },
                               { 0.0f, 2.0f, 27.0f  } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 60.0f, 2.0f, -8.0f  },
                               { -60.0f, 2.0f, -8.0f },
                               { 0.0f, 7.0f, -8.0f   } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 2.0f, 27.0f   },
                               { 0.0f, 7.0f, -8.0f   },
                               { -60.0f, 2.0f, -8.0f } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    /* tail section */
    /* bottom of back fin */
    glNormal3f(0.0f, -1.0f, 0.0f);
    glVertex3f(-30.0f, -0.50f, -57.0f);
    glVertex3f(30.0f, -0.50f, -57.0f);
    glVertex3f(0.0f, -0.50f, -40.0f);

    {
    M3DVector3f vPoints[3] = { { 0.0f, -0.5f, -40.0f  },
                               { 30.0f, -0.5f, -57.0f },
                               { 0.0f, 4.0f, -57.0f   } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 4.0f, -57.0f    },
                               { -30.0f, -0.5f, -57.0f },
                               { 0.0f, -0.5f, -40.0f   } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 30.0f, -0.5f, -57.0f  },
                               { -30.0f, -0.5f, -57.0f },
                               { 0.0f, 4.0f, -57.0f    } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 0.5f, -40.0f  },
                               { 3.0f, 0.5f, -57.0f  },
                               { 0.0f, 25.0f, -65.0f } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 0.0f, 25.0f, -65.0f },
                               { -3.0f, 0.5f, -57.0f },
                               { 0.0f, 0.5f, -40.0f  } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    {
    M3DVector3f vPoints[3] = { { 3.0f, 0.5f, -57.0f  },
                               { -3.0f, 0.5f, -57.0f },
                               { 0.0f, 25.0f, -65.0f } };

    m3dFindNormalf(vNormal, vPoints[0], vPoints[1], vPoints[2]);
    glNormal3fv(vNormal);
    glVertex3fv(vPoints[0]);
    glVertex3fv(vPoints[1]);
    glVertex3fv(vPoints[2]);
    }

    glEnd();
}