/* bzflag
 * Copyright (c) 1993-2025 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
// system headers
#include <assert.h>
#include <math.h>

// local implementation headers
#include "TankSceneNode.h"
#include "TankGeometryMgr.h"

using namespace TankGeometryUtils;


static int treadStyle = TankGeometryUtils::Covered;

// setup in setTreadStyle()
static int treadCount;
static float fullLength;
static float treadHeight;
static float treadInside;
static float treadOutside;
static float treadThickness;
static float treadWidth;
static float treadRadius;
static float treadYCenter;
static float treadLength;
static float treadTexCoordLen;
static float wheelRadius;
static float wheelWidth;
static float wheelSpacing;
static float wheelTexCoordLen;
static float casingWidth;
static float wheelInsideTexRad;
static float wheelOutsideTexRad;


void TankGeometryUtils::setTreadStyle(int style)
{
    if (style == TankGeometryUtils::Exposed)
    {
        fullLength = 6.0f;
        treadHeight = 1.2f;
        treadInside = 0.875f;
        treadOutside = 1.4f;
        treadStyle = TankGeometryUtils::Exposed;
    }
    else
    {
        fullLength = 5.4f;
        treadHeight = 1.1f;
        treadInside = 0.877f;
        treadOutside = 1.38f;
        treadStyle = TankGeometryUtils::Covered;
    }

    treadCount = 1;

    treadThickness = 0.15f;
    treadWidth = treadOutside - treadInside;
    treadRadius = 0.5f * treadHeight;
    treadYCenter = treadInside + (0.5f * treadWidth);
    treadLength = (float)(((fullLength - treadHeight) * 2.0) +
                          (M_PI * treadHeight));
    treadTexCoordLen = (float)treadCount;

    wheelRadius = treadRadius - (0.7f * treadThickness);
    wheelWidth = treadWidth * 0.9f;
    wheelSpacing = (fullLength - treadHeight) / 3.0f;
    wheelTexCoordLen = 1.0f;

    casingWidth = treadWidth * 0.6f;

    wheelInsideTexRad = 0.4f;
    wheelOutsideTexRad = 0.5f;

    return;
}


float TankGeometryUtils::getWheelScale()
{
    // degrees / meter
    return (float)(360.0 / (treadHeight * M_PI));
}

float TankGeometryUtils::getTreadScale()
{
    // texcoords / meter
    return treadTexCoordLen / treadLength;
}

float TankGeometryUtils::getTreadTexLen()
{
    // texcoords
    return treadTexCoordLen;
}


static int buildCasing(float Yoffset)
{
    const float yLeft = Yoffset + (0.5f * casingWidth);
    const float yRight = Yoffset - (0.5f * casingWidth);

    glShadeModel(GL_FLAT);
    {
        const float xc = wheelSpacing * 1.5f;
        const float zb = treadThickness;
        const float zt = treadHeight - treadThickness;
        const float ty = 0.25f; // effective, the texture scale factor
        const float tx = (2.0f * ty) * (xc / (zt - zb));

        // the left and right quad surface
        {
            // the right side
            glBegin(GL_TRIANGLE_STRIP);
            doNormal3f(0.0f, -1.0f, 0.0f);
            doTexCoord2f(-tx, -ty);
            doVertex3f(-xc, yRight, zb);
            doTexCoord2f(+tx, -ty);
            doVertex3f(+xc, yRight, zb);
            doTexCoord2f(-tx, +ty);
            doVertex3f(-xc, yRight, zt);
            doTexCoord2f(+tx, +ty);
            doVertex3f(+xc, yRight, zt);
            glEnd();
            // the left side
            glBegin(GL_TRIANGLE_STRIP);
            doNormal3f(0.0f, +1.0f, 0.0f);
            doTexCoord2f(-tx, -ty);
            doVertex3f(+xc, yLeft, zb);
            doTexCoord2f(+tx, -ty);
            doVertex3f(-xc, yLeft, zb);
            doTexCoord2f(-tx, +ty);
            doVertex3f(+xc, yLeft, zt);
            doTexCoord2f(+tx, +ty);
            doVertex3f(-xc, yLeft, zt);
            glEnd();
        }
    }
    glShadeModel(GL_SMOOTH);

    return 4;
}


static int buildTread(float Yoffset, int divisions)
{
    int i;
    const float divs = (float)((divisions / 2) * 2); // even number
    const float divScale = 2.0f / divs;
    const float astep = (float)((M_PI * 2.0) / divs);
    const float yLeft = Yoffset + (0.5f * treadWidth);
    const float yRight = Yoffset - (0.5f * treadWidth);
    float x, z;
    float tx;
    // setup some basic texture coordinates
    const float txScale = treadTexCoordLen / treadLength;
    const float tx0 = 0.0f;
    const float tx1 = (float)(txScale * (treadRadius * M_PI));
    const float tx2 = (float)(txScale * ((treadRadius * M_PI) + (fullLength - treadHeight)));
    const float tx3 = (float)(txScale * ((treadHeight * M_PI) + (fullLength - treadHeight)));
    const float tx4 = treadTexCoordLen;
    const float tyScale = 1.0f / (2.0f * (treadWidth + treadThickness));
    const float ty0 = 0.0f;
    const float ty1 = tyScale * treadWidth;
    const float ty2 = tyScale * (treadWidth + treadThickness);
    const float ty3 = tyScale * ((2.0f * treadWidth) + treadThickness);
    const float ty4 = 1.0f;

    // the outside of the tread
    glBegin(GL_TRIANGLE_STRIP);
    {
        // first curve
        for (i = 0; i < ((divisions / 2) + 1); i++)
        {
            const float ang = (float)((astep * (double)i) - (M_PI / 2.0));
            const float cos_val = cosf(ang);
            const float sin_val = sinf(ang);
            doNormal3f(cos_val, 0.0f, sin_val);
            tx = tx0 + ((tx1 - tx0) * ((float)i * divScale));
            doTexCoord2f(tx, ty1);
            x = (cos_val * treadRadius) + (wheelSpacing * 1.5f);
            z = (sin_val * treadRadius) + treadRadius;
            doVertex3f(x, yRight, z);
            doTexCoord2f(tx, ty0);
            doVertex3f(x, yLeft, z);
        }
        // top of the tread
        doNormal3f(0.0f, 0.0f, 1.0f);
        doTexCoord2f(tx2, ty1);
        x = -wheelSpacing * 1.5f;
        z = treadHeight;
        doVertex3f(x, yRight, z);
        doTexCoord2f(tx2, ty0);
        doVertex3f(x, yLeft, z);
        // second curve
        for (i = 0; i < ((divisions / 2) + 1); i++)
        {
            const float ang = (float)((astep * (double)i) + (M_PI / 2.0));
            const float cos_val = cosf(ang);
            const float sin_val = sinf(ang);
            doNormal3f(cos_val, 0.0f, sin_val);
            tx = tx2 + ((tx3 - tx2) * ((float)i * divScale));
            doTexCoord2f(tx, ty1);
            x = (cos_val * treadRadius) - (wheelSpacing * 1.5f);
            z = (sin_val * treadRadius) + treadRadius;
            doVertex3f(x, yRight, z);
            doTexCoord2f(tx, ty0);
            doVertex3f(x, yLeft, z);
        }
        // bottom of the tread
        doNormal3f(0.0f, 0.0f, -1.0f);
        doTexCoord2f(tx4, ty1);
        x = wheelSpacing * 1.5f;
        z = 0.0f;
        doVertex3f(x, yRight, z);
        doTexCoord2f(tx4, ty0);
        doVertex3f(x, yLeft, z);
    }
    glEnd();

    // the inside of the tread
    glBegin(GL_TRIANGLE_STRIP);
    {
        // first curve
        for (i = 0; i < ((divisions / 2) + 1); i++)
        {
            const float ang = (float)((astep * (double)i) - (M_PI / 2.0));
            const float cos_val = cosf(ang);
            const float sin_val = sinf(ang);
            doNormal3f(-cos_val, 0.0f, -sin_val);
            tx = tx0 + ((tx1 - tx0) * ((float)i * divScale));
            doTexCoord2f(tx, ty3);
            x = (cos_val * (treadRadius - treadThickness)) + (wheelSpacing * 1.5f);
            z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
            doVertex3f(x, yLeft, z);
            doTexCoord2f(tx, ty2);
            doVertex3f(x, yRight, z);
        }
        // top inside of the tread
        doNormal3f(0.0f, 0.0f, -1.0f);
        doTexCoord2f(tx2, ty3);
        x = -wheelSpacing * 1.5f;
        z = treadHeight - treadThickness;
        doVertex3f(x, yLeft, z);
        doTexCoord2f(tx2, ty2);
        doVertex3f(x, yRight, z);
        // second curve
        for (i = 0; i < ((divisions / 2) + 1); i++)
        {
            const float ang = (float)((astep * (double)i) + (M_PI / 2.0));
            const float cos_val = cosf(ang);
            const float sin_val = sinf(ang);
            doNormal3f(-cos_val, 0.0f, -sin_val);
            tx = tx2 + ((tx3 - tx2) * ((float)i * divScale));
            doTexCoord2f(tx, ty3);
            x = (cos_val * (treadRadius - treadThickness)) - (wheelSpacing * 1.5f);
            z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
            doVertex3f(x, yLeft, z);
            doTexCoord2f(tx, ty2);
            doVertex3f(x, yRight, z);
        }
        // bottom inside of the tread
        doNormal3f(0.0f, 0.0f, 1.0f);
        doTexCoord2f(tx4, ty3);
        x = wheelSpacing * 1.5f;
        z = treadThickness;
        doVertex3f(x, yLeft, z);
        doTexCoord2f(tx4, ty2);
        doVertex3f(x, yRight, z);
    }
    glEnd();

    glShadeModel(GL_FLAT);
    {
        // the right edge
        doNormal3f(0.0f, -1.0f, 0.0f);
        glBegin(GL_TRIANGLE_STRIP);
        {
            // first outside curve
            for (i = 0; i < ((divisions / 2) + 1); i++)
            {
                const float ang = (float)((astep * (double)i) - (M_PI / 2.0));
                const float cos_val = cosf(ang);
                const float sin_val = sinf(ang);
                tx = tx0 + ((tx1 - tx0) * ((float)i * divScale));
                doTexCoord2f(tx, ty2);
                x = (cos_val * (treadRadius - treadThickness)) + (wheelSpacing * 1.5f);
                z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
                doVertex3f(x, yRight, z);
                doTexCoord2f(tx, ty1);
                x = (cos_val * treadRadius) + (wheelSpacing * 1.5f);
                z = (sin_val * treadRadius) + treadRadius;
                doVertex3f(x, yRight, z);
            }
            // top edge
            doTexCoord2f(tx2, ty2);
            x = -wheelSpacing * 1.5f;
            z = treadHeight - treadThickness;
            doVertex3f(x, yRight, z);
            doTexCoord2f(tx2, ty1);
            z = treadHeight;
            doVertex3f(x, yRight, z);
            // second outside curve
            for (i = 0; i < ((divisions / 2) + 1); i++)
            {
                const float ang = (float)((astep * (double)i) + (M_PI / 2.0));
                const float cos_val = cosf(ang);
                const float sin_val = sinf(ang);
                tx = tx2 + ((tx3 - tx2) * ((float)i * divScale));
                doTexCoord2f(tx, ty2);
                x = (cos_val * (treadRadius - treadThickness)) - (wheelSpacing * 1.5f);
                z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
                doVertex3f(x, yRight, z);
                doTexCoord2f(tx, ty1);
                x = (cos_val * treadRadius) - (wheelSpacing * 1.5f);
                z = (sin_val * treadRadius) + treadRadius;
                doVertex3f(x, yRight, z);
            }
            // bottom edge
            doTexCoord2f(tx4, ty2);
            x = wheelSpacing * 1.5f;
            z = treadThickness;
            doVertex3f(x, yRight, z);
            doTexCoord2f(tx4, ty1);
            z = 0.0f;
            doVertex3f(x, yRight, z);
        }
        glEnd();

        // the left edge
        doNormal3f(0.0f, +1.0f, 0.0f);
        glBegin(GL_TRIANGLE_STRIP);
        {
            // first outside curve
            for (i = 0; i < ((divisions / 2) + 1); i++)
            {
                const float ang = (float)((astep * (double)i) - (M_PI / 2.0));
                const float cos_val = cosf(ang);
                const float sin_val = sinf(ang);
                tx = tx0 + ((tx1 - tx0) * ((float)i * divScale));
                doTexCoord2f(tx, ty4);
                x = (cos_val * treadRadius) + (wheelSpacing * 1.5f);
                z = (sin_val * treadRadius) + treadRadius;
                doVertex3f(x, yLeft, z);
                doTexCoord2f(tx, ty3);
                x = (cos_val * (treadRadius - treadThickness)) + (wheelSpacing * 1.5f);
                z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
                doVertex3f(x, yLeft, z);
            }
            // top edge
            doTexCoord2f(tx2, ty4);
            x = -wheelSpacing * 1.5f;
            z = treadHeight;
            doVertex3f(x, yLeft, z);
            doTexCoord2f(tx2, ty3);
            z = treadHeight - treadThickness;
            doVertex3f(x, yLeft, z);
            // second outside curve
            for (i = 0; i < ((divisions / 2) + 1); i++)
            {
                const float ang = (float)((astep * (double)i) + (M_PI / 2.0));
                const float cos_val = cosf(ang);
                const float sin_val = sinf(ang);
                tx = tx2 + ((tx3 - tx2) * ((float)i * divScale));
                doTexCoord2f(tx, ty4);
                x = (cos_val * treadRadius) - (wheelSpacing * 1.5f);
                z = (sin_val * treadRadius) + treadRadius;
                doVertex3f(x, yLeft, z);
                doTexCoord2f(tx, ty3);
                x = (cos_val * (treadRadius - treadThickness)) - (wheelSpacing * 1.5f);
                z = (sin_val * (treadRadius - treadThickness)) + treadRadius;
                doVertex3f(x, yLeft, z);
            }
            // bottom edge
            doTexCoord2f(tx4, ty4);
            x = wheelSpacing * 1.5f;
            z = 0.0f;
            doVertex3f(x, yLeft, z);
            doTexCoord2f(tx4, ty3);
            z = treadThickness;
            doVertex3f(x, yLeft, z);
        }
        glEnd();
    }
    glShadeModel(GL_SMOOTH);

    return (2 * 4 * (divisions + 2));
}


static int buildWheel(const float pos[3], float angle, int divisions)
{
    int i;
    int tris = 0;
    const float divs = (float)divisions;
    const float astep = (float)((M_PI * 2.0) / (double)divs);
    const float yLeft = pos[1] + (0.5f * wheelWidth);
    const float yRight = pos[1] - (0.5f * wheelWidth);
    float x, z;
    float tx, ty;

    // the edge loop
    doNormal3f(0.0f, +1.0f, 0.0f);
    glBegin(GL_TRIANGLE_STRIP);
    {
        for (i = 0; i < (divisions + 1); i++)
        {
            const float ang = astep * (float)i;
            const float cos_val = cosf(ang);
            const float sin_val = sinf(ang);
            doNormal3f(cos_val, 0.0f, sin_val);
            tx = 0.5f + (cosf(angle + ang) * wheelInsideTexRad);
            ty = 0.5f + (sinf(angle + ang) * wheelInsideTexRad);
            doTexCoord2f(tx, ty);
            x = (cos_val * wheelRadius) + pos[0];
            z = (sin_val * wheelRadius) + pos[2];
            doVertex3f(x, yRight, z);
            tx = 0.5f + (cosf(angle + ang) * wheelOutsideTexRad);
            ty = 0.5f + (sinf(angle + ang) * wheelOutsideTexRad);
            doTexCoord2f(tx, ty);
            doVertex3f(x, yLeft, z);
        }
    }
    glEnd();
    tris += (2 * divisions);

    glShadeModel(GL_FLAT);
    {
        // the left face
        doNormal3f(0.0f, +1.0f, 0.0f);
        glBegin(GL_TRIANGLE_FAN);
        {
            for (i = 0; i < divisions; i++)
            {
                const float ang = astep * (float)i;
                const float cos_val = cosf(-ang);
                const float sin_val = sinf(-ang);
                tx = 0.5f + (cosf(angle - ang) * wheelInsideTexRad);
                ty = 0.5f + (sinf(angle - ang) * wheelInsideTexRad);
                doTexCoord2f(tx, ty);
                x = (cos_val * wheelRadius) + pos[0];
                z = (sin_val * wheelRadius) + pos[2];
                doVertex3f(x, yLeft, z);

            }
        }
        glEnd();
        tris += (divisions - 2);

        // the right face
        doNormal3f(0.0f, -1.0f, 0.0f);
        glBegin(GL_TRIANGLE_FAN);
        {
            for (i = 0; i < divisions; i++)
            {
                const float ang = astep * (float)i;
                const float cos_val = cosf(+ang);
                const float sin_val = sinf(+ang);
                tx = 0.5f + (cosf(angle + ang) * 0.4f);
                ty = 0.5f + (sinf(angle + ang) * 0.4f);
                doTexCoord2f(tx, ty);
                x = (cos_val * wheelRadius) + pos[0];
                z = (sin_val * wheelRadius) + pos[2];
                doVertex3f(x, yRight, z);
            }
        }
        glEnd();
        tris += (divisions - 2);
    }
    glShadeModel(GL_SMOOTH);

    return tris;
}


int TankGeometryUtils::buildHighLCasingAnim()
{
    int tris = 0;

    tris += buildCasing(+treadYCenter);

    if (treadStyle == TankGeometryUtils::Covered)
    {
        glShadeModel(GL_FLAT);
        {
            //draw the left tread cover
            glBegin(GL_TRIANGLE_STRIP);
            doNormal3f(0.984696f, 0.000000f, 0.174282f);
            doTexCoord2f(-0.193f, 0.727f);
            doVertex3f(3.000f, 0.875f, 0.770f);
            doTexCoord2f(0.009f, 0.356f);
            doVertex3f(3.000f, 1.400f, 0.770f);
            doTexCoord2f(-0.164f, 0.679f);
            doVertex3f(2.980f, 0.875f, 0.883f);
            doTexCoord2f(-0.015f, 0.407f);
            doVertex3f(2.980f, 1.400f, 0.883f);
            doNormal3f(0.519720f, 0.000000f, 0.854336f);
            doTexCoord2f(-0.134f, 0.666f);
            doVertex3f(2.860f, 0.875f, 0.956f);
            doTexCoord2f(-0.010f, 0.439f);
            doVertex3f(2.860f, 1.400f, 0.956f);
            doNormal3f(0.748075f, 0.000000f, 0.663614f);
            doTexCoord2f(-0.102f, 0.647f);
            doVertex3f(2.750f, 0.875f, 1.080f);
            doTexCoord2f(-0.009f, 0.477f);
            doVertex3f(2.750f, 1.400f, 1.080f);
            doNormal3f(0.049938f, 0.000000f, 0.998752f);
            doTexCoord2f(-0.041f, 0.675f);
            doVertex3f(2.350f, 0.875f, 1.100f);
            doTexCoord2f(0.048f, 0.512f);
            doVertex3f(2.350f, 1.400f, 1.100f);
            doNormal3f(0.455876f, 0.000000f, 0.890043f);
            doTexCoord2f(0.033f, 0.684f);
            doVertex3f(1.940f, 0.875f, 1.310f);
            doTexCoord2f(0.095f, 0.570f);
            doVertex3f(1.940f, 1.400f, 1.310f);
            doNormal3f(0.003378f, 0.000000f, 0.999994f);
            doTexCoord2f(0.468f, 0.920f);
            doVertex3f(-1.020f, 0.875f, 1.320f);
            doTexCoord2f(0.529f, 0.808f);
            doVertex3f(-1.020f, 1.400f, 1.320f);
            doNormal3f(0.178885f, 0.000000f, 0.983870f);
            doTexCoord2f(0.536f, 0.949f);
            doVertex3f(-1.460f, 0.875f, 1.400f);
            doTexCoord2f(0.591f, 0.849f);
            doVertex3f(-1.460f, 1.400f, 1.400f);
            doNormal3f(0.006622f, 0.000000f, 0.999978f);
            doTexCoord2f(0.759f, 1.070f);
            doVertex3f(-2.970f, 0.875f, 1.410f);
            doTexCoord2f(0.813f, 0.970f);
            doVertex3f(-2.970f, 1.400f, 1.410f);
            doNormal3f(-0.967641f, 0.000000f, -0.252333f);
            doTexCoord2f(0.587f, 1.300f);
            doVertex3f(-2.740f, 0.875f, 0.628f);
            doTexCoord2f(0.917f, 0.700f);
            doVertex3f(-2.740f, 1.400f, 0.628f);
            doNormal3f(-0.426419f, 0.000000f, -0.904526f);
            doTexCoord2f(0.375f, 1.300f);
            doVertex3f(-1.620f, 0.875f, 0.500f);
            doTexCoord2f(0.800f, 0.523f);
            doVertex3f(-1.620f, 1.400f, 0.500f);
            doNormal3f(0.000000f, 0.000000f, -1.000000f);
            doTexCoord2f(-0.156f, 1.010f);
            doVertex3f(1.990f, 0.875f, 0.500f);
            doTexCoord2f(0.268f, 0.233f);
            doVertex3f(1.990f, 1.400f, 0.500f);
            doNormal3f(0.454326f, 0.000000f, -0.890835f);
            doTexCoord2f(-0.246f, 0.896f);
            doVertex3f(2.790f, 0.875f,0.608f);
            doTexCoord2f(0.123f, 0.220f);
            doVertex3f(2.790f, 1.400f,0.608f);
            doNormal3f(0.978361f, 0.000000f, -0.206904f);
            doTexCoord2f(-0.182f, 0.754f);
            doVertex3f(2.860f, 0.875f, 0.739f);
            doTexCoord2f(0.038f, 0.352f);
            doVertex3f(2.860f, 1.400f, 0.739f);
            doNormal3f(0.216192f, 0.000000f, -0.976351f);
            doTexCoord2f(-0.193f, 0.727f);
            doVertex3f(3.000f, 0.875f, 0.770f);
            doTexCoord2f(0.009f, 0.356f);
            doVertex3f(3.000f, 1.400f, 0.770f);
            glEnd(); // 30 verts -> 28 tris
            tris += 28;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(0.587f, 1.300f);
            doVertex3f(-2.740f, 0.875f, 0.628f);
            doTexCoord2f(0.375f, 1.300f);
            doVertex3f(-1.620f, 0.875f, 0.500f);
            doTexCoord2f(0.468f, 0.920f);
            doVertex3f(-1.020f, 0.875f, 1.320f);
            doTexCoord2f(0.536f, 0.949f);
            doVertex3f(-1.460f, 0.875f, 1.400f);
            doTexCoord2f(0.759f, 1.070f);
            doVertex3f(-2.970f, 0.875f, 1.410f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(-0.156f, 1.010f);
            doVertex3f(1.990f, 0.875f, 0.500f);
            doTexCoord2f(-0.246f, 0.896f);
            doVertex3f(2.790f, 0.875f,0.608f);
            doTexCoord2f(-0.182f, 0.754f);
            doVertex3f(2.860f, 0.875f, 0.739f);
            doTexCoord2f(-0.102f, 0.647f);
            doVertex3f(2.750f, 0.875f, 1.080f);
            doTexCoord2f(-0.041f, 0.675f);
            doVertex3f(2.350f, 0.875f, 1.100f);
            doTexCoord2f(0.033f, 0.684f);
            doVertex3f(1.940f, 0.875f, 1.310f);
            doTexCoord2f(0.468f, 0.920f);
            doVertex3f(-1.020f, 0.875f, 1.320f);
            doTexCoord2f(0.375f, 1.300f);
            doVertex3f(-1.620f, 0.875f, 0.500f);
            glEnd(); // 8 verts -> 6 tris
            tris += 6;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(-0.182f, 0.754f);
            doVertex3f(2.860f, 0.875f, 0.739f);
            doTexCoord2f(-0.193f, 0.727f);
            doVertex3f(3.000f, 0.875f, 0.770f);
            doTexCoord2f(-0.164f, 0.679f);
            doVertex3f(2.980f, 0.875f, 0.883f);
            doTexCoord2f(-0.134f, 0.666f);
            doVertex3f(2.860f, 0.875f, 0.956f);
            doTexCoord2f(-0.102f, 0.647f);
            doVertex3f(2.750f, 0.875f, 1.080f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.917f, 0.700f);
            doVertex3f(-2.740f, 1.400f, 0.628f);
            doTexCoord2f(0.813f, 0.970f);
            doVertex3f(-2.970f, 1.400f, 1.410f);
            doTexCoord2f(0.591f, 0.849f);
            doVertex3f(-1.460f, 1.400f, 1.400f);
            doTexCoord2f(0.529f, 0.808f);
            doVertex3f(-1.020f, 1.400f, 1.320f);
            doTexCoord2f(0.800f, 0.523f);
            doVertex3f(-1.620f, 1.400f, 0.500f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.268f, 0.233f);
            doVertex3f(1.990f, 1.400f, 0.500f);
            doTexCoord2f(0.800f, 0.523f);
            doVertex3f(-1.620f, 1.400f, 0.500f);
            doTexCoord2f(0.529f, 0.808f);
            doVertex3f(-1.020f, 1.400f, 1.320f);
            doTexCoord2f(0.095f, 0.570f);
            doVertex3f(1.940f, 1.400f, 1.310f);
            doTexCoord2f(0.048f, 0.512f);
            doVertex3f(2.350f, 1.400f, 1.100f);
            doTexCoord2f(-0.009f, 0.477f);
            doVertex3f(2.750f, 1.400f, 1.080f);
            doTexCoord2f(0.038f, 0.352f);
            doVertex3f(2.860f, 1.400f, 0.739f);
            doTexCoord2f(0.123f, 0.220f);
            doVertex3f(2.790f, 1.400f,0.608f);
            glEnd(); // 8 verts -> 6 tris
            tris += 6;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.038f, 0.352f);
            doVertex3f(2.860f, 1.400f, 0.739f);
            doTexCoord2f(-0.009f, 0.477f);
            doVertex3f(2.750f, 1.400f, 1.080f);
            doTexCoord2f(-0.010f, 0.439f);
            doVertex3f(2.860f, 1.400f, 0.956f);
            doTexCoord2f(-0.015f, 0.407f);
            doVertex3f(2.980f, 1.400f, 0.883f);
            doTexCoord2f(0.009f, 0.356f);
            doVertex3f(3.000f, 1.400f, 0.770f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;
        }
        glShadeModel(GL_SMOOTH);
    }

    return tris;
}

int TankGeometryUtils::buildHighRCasingAnim()
{
    int tris = 0;

    tris += buildCasing(-treadYCenter);

    if (treadStyle == TankGeometryUtils::Covered)
    {
        glShadeModel(GL_FLAT);
        {
            //draw the right tread cover
            glBegin(GL_TRIANGLE_STRIP);
            doNormal3f(0.984696f, 0.000000f, 0.174282f);
            doTexCoord2f(-0.295f, 0.041f);
            doVertex3f(3.000f, -1.400f, 0.770f);
            doTexCoord2f(0.045f, -0.208f);
            doVertex3f(3.000f, -0.875f, 0.770f);
            doTexCoord2f(-0.248f, 0.010f);
            doVertex3f(2.980f, -1.400f, 0.883f);
            doTexCoord2f(0.002f, -0.173f);
            doVertex3f(2.980f, -0.875f, 0.883f);
            doNormal3f(0.519720f, 0.000000f, 0.854336f);
            doTexCoord2f(-0.216f, 0.011f);
            doVertex3f(2.860f, -1.400f, 0.956f);
            doTexCoord2f(-0.007f, -0.141f);
            doVertex3f(2.860f, -0.875f, 0.956f);
            doNormal3f(0.748075f, 0.000000f, 0.663614f);
            doTexCoord2f(-0.179f, 0.008f);
            doVertex3f(2.750f, -1.400f, 1.080f);
            doTexCoord2f(-0.022f, -0.107f);
            doVertex3f(2.750f, -0.875f, 1.080f);
            doNormal3f(0.049938f, 0.000000f, 0.998752f);
            doTexCoord2f(-0.136f, 0.059f);
            doVertex3f(2.350f, -1.400f, 1.100f);
            doTexCoord2f(0.014f, -0.050f);
            doVertex3f(2.350f, -0.875f, 1.100f);
            doNormal3f(0.455876f, 0.000000f, 0.890043f);
            doTexCoord2f(-0.072f, 0.099f);
            doVertex3f(1.940f, -1.400f, 1.310f);
            doTexCoord2f(0.032f, 0.022f);
            doVertex3f(1.940f, -0.875f, 1.310f);
            doNormal3f(0.003378f, 0.000000f, 0.999994f);
            doTexCoord2f(0.221f, 0.497f);
            doVertex3f(-1.020f, -1.400f, 1.320f);
            doTexCoord2f(0.324f, 0.422f);
            doVertex3f(-1.020f, -0.875f, 1.320f);
            doNormal3f(0.178885f, 0.000000f, 0.983870f);
            doTexCoord2f(0.270f, 0.553f);
            doVertex3f(-1.460f, -1.400f, 1.400f);
            doTexCoord2f(0.362f, 0.486f);
            doVertex3f(-1.460f, -0.875f, 1.400f);
            doNormal3f(0.006622f, 0.000000f, 0.999978f);
            doTexCoord2f(0.419f, 0.757f);
            doVertex3f(-2.970f, -1.400f, 1.410f);
            doTexCoord2f(0.511f, 0.690f);
            doVertex3f(-2.970f, -0.875f, 1.410f);
            doNormal3f(-0.967641f, 0.000000f, -0.252333f);
            doTexCoord2f(0.165f, 0.896f);
            doVertex3f(-2.740f, -1.400f, 0.628f);
            doTexCoord2f(0.720f, 0.489f);
            doVertex3f(-2.740f, -0.875f, 0.628f);
            doNormal3f(-0.426419f, 0.000000f, -0.904526f);
            doTexCoord2f(-0.026f, 0.803f);
            doVertex3f(-1.620f, -1.400f, 0.500f);
            doTexCoord2f(0.690f, 0.279f);
            doVertex3f(-1.620f, -0.875f, 0.500f);
            doNormal3f(0.000000f, 0.000000f, -1.000000f);
            doTexCoord2f(-0.383f, 0.314f);
            doVertex3f(1.990f, -1.400f, 0.500f);
            doTexCoord2f(0.332f, -0.209f);
            doVertex3f(1.990f, -0.875f, 0.500f);
            doNormal3f(0.454326f, 0.000000f, -0.890835f);
            doTexCoord2f(-0.415f, 0.172f);
            doVertex3f(2.790f, -1.400f,0.608f);
            doTexCoord2f(0.206f, -0.283f);
            doVertex3f(2.790f, -0.875f,0.608f);
            doNormal3f(0.978361f, 0.000000f, -0.206904f);
            doTexCoord2f(-0.296f, 0.070f);
            doVertex3f(2.860f, -1.400f, 0.739f);
            doTexCoord2f(0.073f, -0.200f);
            doVertex3f(2.860f, -0.875f, 0.739f);
            doNormal3f(0.216192f, 0.000000f, -0.976351f);
            doTexCoord2f(-0.295f, 0.041f);
            doVertex3f(3.000f, -1.400f, 0.770f);
            doTexCoord2f(0.045f, -0.208f);
            doVertex3f(3.000f, -0.875f, 0.770f);
            glEnd(); // 30 verts -> 28 tris
            tris += 28;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(0.165f, 0.896f);
            doVertex3f(-2.740f, -1.400f, 0.628f);
            doTexCoord2f(-0.026f, 0.803f);
            doVertex3f(-1.620f, -1.400f, 0.500f);
            doTexCoord2f(0.221f, 0.497f);
            doVertex3f(-1.020f, -1.400f, 1.320f);
            doTexCoord2f(0.270f, 0.553f);
            doVertex3f(-1.460f, -1.400f, 1.400f);
            doTexCoord2f(0.419f, 0.757f);
            doVertex3f(-2.970f, -1.400f, 1.410f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(-0.383f, 0.314f);
            doVertex3f(1.990f, -1.400f, 0.500f);
            doTexCoord2f(-0.415f, 0.172f);
            doVertex3f(2.790f, -1.400f,0.608f);
            doTexCoord2f(-0.296f, 0.070f);
            doVertex3f(2.860f, -1.400f, 0.739f);
            doTexCoord2f(-0.179f, 0.008f);
            doVertex3f(2.750f, -1.400f, 1.080f);
            doTexCoord2f(-0.136f, 0.059f);
            doVertex3f(2.350f, -1.400f, 1.100f);
            doTexCoord2f(-0.072f, 0.099f);
            doVertex3f(1.940f, -1.400f, 1.310f);
            doTexCoord2f(0.221f, 0.497f);
            doVertex3f(-1.020f, -1.400f, 1.320f);
            doTexCoord2f(-0.026f, 0.803f);
            doVertex3f(-1.620f, -1.400f, 0.500f);
            glEnd(); // 8 verts -> 6 tris
            tris += 6;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, -1.000000f, 0.000000f);
            doTexCoord2f(-0.296f, 0.070f);
            doVertex3f(2.860f, -1.400f, 0.739f);
            doTexCoord2f(-0.295f, 0.041f);
            doVertex3f(3.000f, -1.400f, 0.770f);
            doTexCoord2f(-0.248f, 0.010f);
            doVertex3f(2.980f, -1.400f, 0.883f);
            doTexCoord2f(-0.216f, 0.011f);
            doVertex3f(2.860f, -1.400f, 0.956f);
            doTexCoord2f(-0.179f, 0.008f);
            doVertex3f(2.750f, -1.400f, 1.080f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.720f, 0.489f);
            doVertex3f(-2.740f, -0.875f, 0.628f);
            doTexCoord2f(0.511f, 0.690f);
            doVertex3f(-2.970f, -0.875f, 1.410f);
            doTexCoord2f(0.362f, 0.486f);
            doVertex3f(-1.460f, -0.875f, 1.400f);
            doTexCoord2f(0.324f, 0.422f);
            doVertex3f(-1.020f, -0.875f, 1.320f);
            doTexCoord2f(0.690f, 0.279f);
            doVertex3f(-1.620f, -0.875f, 0.500f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.332f, -0.209f);
            doVertex3f(1.990f, -0.875f, 0.500f);
            doTexCoord2f(0.690f, 0.279f);
            doVertex3f(-1.620f, -0.875f, 0.500f);
            doTexCoord2f(0.324f, 0.422f);
            doVertex3f(-1.020f, -0.875f, 1.320f);
            doTexCoord2f(0.032f, 0.022f);
            doVertex3f(1.940f, -0.875f, 1.310f);
            doTexCoord2f(0.014f, -0.050f);
            doVertex3f(2.350f, -0.875f, 1.100f);
            doTexCoord2f(-0.022f, -0.107f);
            doVertex3f(2.750f, -0.875f, 1.080f);
            doTexCoord2f(0.073f, -0.200f);
            doVertex3f(2.860f, -0.875f, 0.739f);
            doTexCoord2f(0.206f, -0.283f);
            doVertex3f(2.790f, -0.875f,0.608f);
            glEnd(); // 8 verts -> 6 tris
            tris += 6;

            glBegin(GL_TRIANGLE_FAN);
            doNormal3f(0.000000f, 1.000000f, 0.000000f);
            doTexCoord2f(0.073f, -0.200f);
            doVertex3f(2.860f, -0.875f, 0.739f);
            doTexCoord2f(-0.022f, -0.107f);
            doVertex3f(2.750f, -0.875f, 1.080f);
            doTexCoord2f(-0.007f, -0.141f);
            doVertex3f(2.860f, -0.875f, 0.956f);
            doTexCoord2f(0.002f, -0.173f);
            doVertex3f(2.980f, -0.875f, 0.883f);
            doTexCoord2f(0.045f, -0.208f);
            doVertex3f(3.000f, -0.875f, 0.770f);
            glEnd(); // 5 verts -> 3 tris
            tris += 3;
        }
        glShadeModel(GL_SMOOTH);
    }

    return tris;
}


int TankGeometryUtils::buildHighLTread(int divs)
{
    return buildTread(+treadYCenter, divs);
}

int TankGeometryUtils::buildHighRTread(int divs)
{
    return buildTread(-treadYCenter, divs);
}


int TankGeometryUtils::buildHighLWheel(int number, float angle, int divs)
{
    assert ((number >= 0) && (number < 4));
    float pos[3];
    pos[0] = wheelSpacing * (-1.5f + (float)number);
    pos[1] = +treadYCenter;
    pos[2] = treadRadius;
    return buildWheel(pos, angle, divs);
}

int TankGeometryUtils::buildHighRWheel(int number, float angle, int divs)
{
    assert ((number >= 0) && (number < 4));
    float pos[3];
    pos[0] = wheelSpacing * (-1.5f + (float)number);
    pos[1] = -treadYCenter;
    pos[2] = treadRadius;
    return buildWheel(pos, angle, divs);
}


// Local Variables: ***
// mode: C++ ***
// tab-width: 4 ***
// c-basic-offset: 4 ***
// indent-tabs-mode: nil ***
// End: ***
// ex: shiftwidth=4 tabstop=4
