Beispiel #1
0
/*-----------------------------------------------------------------------------
    Name        : primRectShaded2
    Description : Draw a shaded 2d rectangle.
    Inputs      : rect - pointer to rectangle structure containing coordinates.
                  c - pointer to 4 color values to draw it in.
    Outputs     : ..
    Return      : void
----------------------------------------------------------------------------*/
void primRectShaded2(rectangle *rect, color *c)
{
    if (glcActive())
    {
        glcRectShaded2(rect, c);
        return;
    }

    glShadeModel(GL_SMOOTH);

    glBegin(GL_QUADS);

    glColor3ub(colRed(c[0]), colGreen(c[0]), colBlue(c[0]));
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0));

    glColor3ub(colRed(c[1]), colGreen(c[1]), colBlue(c[1]));
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1));

    glColor3ub(colRed(c[2]), colGreen(c[2]), colBlue(c[2]));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1));

    glColor3ub(colRed(c[3]), colGreen(c[3]), colBlue(c[3]));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0));

    glEnd();
}
Beispiel #2
0
/*-----------------------------------------------------------------------------
    Name        : primLine2
    Description : Draw a line 1 pixel wide
    Inputs      : c - attributes of line to be drawn
                  x0, y0, x1, y1 - start/end of line segment
    Outputs     : Sets GL_COLOR
    Return      : void
----------------------------------------------------------------------------*/
void primLine2(sdword x0, sdword y0, sdword x1, sdword y1, color c)
{
    bool blendon;

    if (glcActive())
    {
        glcLine2(x0, y0, x1, y1, 1, c);
        return;
    }

    if (!glCapFeatureExists(GL_LINE_SMOOTH))
    {
        primNonAALine2(x0, y0, x1, y1, c);
        return;
    }

    blendon = glIsEnabled(GL_BLEND);
    if (!blendon) glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);
    glColor3ub(colRed(c), colGreen(c), colBlue(c));
    glBegin(GL_LINES);
    glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0));
    glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1));
    glEnd();
    glDisable(GL_LINE_SMOOTH);
    if (!blendon) glDisable(GL_BLEND);
}
Beispiel #3
0
/*-----------------------------------------------------------------------------
    Name        : primRectTranslucent2
    Description : Draw a translucent 2d rectangle.
    Inputs      : rect - pointer to rectangle structure containing coordinates.
                  c - color to draw it in.
    Outputs     : ..
    Return      : void
----------------------------------------------------------------------------*/
void primRectTranslucent2(rectangle* rect, color c)
{
    GLboolean blendOn;

    if (RGL && RGLtype == SWtype)
    {
        primRectTranslucentRGL2(rect, c);
        return;
    }

    blendOn = glIsEnabled(GL_BLEND);
    if (!blendOn) glEnable(GL_BLEND);
    if (glcActive())
    {
        glcRectTranslucent2(rect, c);
    }
    else
    {
        glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c));
        glBegin(GL_QUADS);
        glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0));
        glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1));
        glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1));
        glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0));
        glEnd();
    }
    if (!blendOn) glDisable(GL_BLEND);
}
Beispiel #4
0
/*-----------------------------------------------------------------------------
    Name        : primRectOutline2
    Description : Draw an outline 2d rectangle.
    Inputs      : rect - pointer to rectangle structure containing coordinates.
                  thickness - thickness of the lines
                  c - color to draw it in.
    Outputs     : ..
    Return      : void
----------------------------------------------------------------------------*/
void primRectOutline2(rectangle *rect, sdword thickness, color c)
{
    sdword bottom;

    if (glcActive())
    {
        glcRectOutline2(rect, thickness, c);
        return;
    }

    bottom = rect->y1 - 1;

    glColor3ub(colRed(c), colGreen(c), colBlue(c));
    glPushAttrib(GL_LINE_BIT);
    glLineWidth((GLfloat)thickness);

    glBegin(GL_LINE_LOOP);
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(bottom));
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(bottom));
    glEnd();

    glPopAttrib();
}
Beispiel #5
0
/*-----------------------------------------------------------------------------
    Name        : primNonAALine2
    Description : Draw a non-antialiased line 1 pixel wide
    Inputs      : c - attributes of line to be drawn
                  x0, y0, x1, y1 - start/end of line segment
    Outputs     : sets GL_COLOR
    Return      :
----------------------------------------------------------------------------*/
void primNonAALine2(sdword x0, sdword y0, sdword x1, sdword y1, color c)
{
    glColor3ub(colRed(c), colGreen(c), colBlue(c));
    glBegin(GL_LINES);
    glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0));
    glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1));
    glEnd();
}
Beispiel #6
0
/*-----------------------------------------------------------------------------
    Name        : primLineThick2
    Description : Draw a line "thickness" pixels wide
    Inputs      : c - attributes of line to be drawn
                  x0, y0, y1, y1 - start/end of line segment
                  thickness - width of line
    Outputs     : Sets GL_COLOR
    Return      : void
----------------------------------------------------------------------------*/
void primLineThick2(sdword x0, sdword y0, sdword x1, sdword y1, sdword thickness, color c)
{
    glPushAttrib(GL_LINE_BIT);
    glLineWidth((GLfloat)thickness);
    glColor3ub(colRed(c), colGreen(c), colBlue(c));
    glBegin(GL_LINES);
    glVertex2f(primScreenToGLX(x0), primScreenToGLY(y0));
    glVertex2f(primScreenToGLX(x1), primScreenToGLY(y1));
    glEnd();
    glPopAttrib();
}
void hrDrawBackground(void)
{
    rndClearToBlack();

    if (hrBackgroundTexture)
    {
        real32 x = -((real32)hrBackXSize / (real32)MAIN_WindowWidth);
        real32 y = -((real32)hrBackYSize / (real32)MAIN_WindowHeight);
        GLfloat v[8], t[8];

        sdword oldTex = rndTextureEnable(TRUE);
        udword oldMode = rndTextureEnvironment(RTE_Replace);
        bool cull = glIsEnabled(GL_CULL_FACE) ? TRUE : FALSE;
        bool blend = glIsEnabled(GL_BLEND) ? TRUE : FALSE;
        glDisable(GL_CULL_FACE);
        glEnable(GL_BLEND);

        trClearCurrent();
        glBindTexture(GL_TEXTURE_2D, hrBackgroundTexture);

        t[0] = 0.0f;        t[1] = 0.0f;
        t[2] = hrBackXFrac; t[3] = 0.0f;
        t[4] = 0.0f;        t[5] = hrBackYFrac;
        t[6] = hrBackXFrac; t[7] = hrBackYFrac;

        v[0] = primScreenToGLX(hrScaleMissionLoadingScreens ? feResRepositionScaledX(0) : feResRepositionCentredX(0));
        v[1] = primScreenToGLY(hrScaleMissionLoadingScreens ? feResRepositionScaledY(0) : feResRepositionCentredY(0));
        v[2] = primScreenToGLX(hrScaleMissionLoadingScreens ? feResRepositionScaledX(640) : feResRepositionCentredX(640));
        v[3] = primScreenToGLY(hrScaleMissionLoadingScreens ? feResRepositionScaledY(0) : feResRepositionCentredY(0));
        v[4] = primScreenToGLX(hrScaleMissionLoadingScreens ? feResRepositionScaledX(0) : feResRepositionCentredX(0));
        v[5] = primScreenToGLY(hrScaleMissionLoadingScreens ? feResRepositionScaledY(480) : feResRepositionCentredY(480));
        v[6] = primScreenToGLX(hrScaleMissionLoadingScreens ? feResRepositionScaledX(640) : feResRepositionCentredX(640));
        v[7] = primScreenToGLY(hrScaleMissionLoadingScreens ? feResRepositionScaledY(480) : feResRepositionCentredY(480));

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glTexCoordPointer(2, GL_FLOAT, 0, t);
        glVertexPointer(2, GL_FLOAT, 0, v);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

        rndTextureEnvironment(oldMode);
        rndTextureEnable(oldTex);
        if (cull) glEnable(GL_CULL_FACE);
        if (!blend) glDisable(GL_BLEND);
    }
}
Beispiel #8
0
/*-----------------------------------------------------------------------------
    Name        : primTriSolid2
    Description : Draw a solid 2D triangle
    Inputs      : tri - pointer to triangle structure containing coordinates of corners
                  c - color to draw it in
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
void primTriSolid2(triangle *tri, color c)
{
    if (glcActive())
    {
        glcTriSolid2(tri, c);
    }
    else
    {
        glColor3ub(colRed(c), colGreen(c), colBlue(c));
        glBegin(GL_TRIANGLES);
        glVertex2f(primScreenToGLX(tri->x0), primScreenToGLY(tri->y0));
        glVertex2f(primScreenToGLX(tri->x1), primScreenToGLY(tri->y1));
        glVertex2f(primScreenToGLX(tri->x2), primScreenToGLY(tri->y2));
        glEnd();
    }
}
Beispiel #9
0
void primCircleBorder(sdword x, sdword y, sdword radInner, sdword radOuter, sdword nSlices, color colInner)
{
    sdword index;
    real32 centreX, centreY;
    double theta, addAmount;
    real32 radXInner, radXOuter, radYInner, radYOuter;
    real32 x0, y0, x1, y1, x2, y2;
    real32 sinTheta, cosTheta;
    ubyte red = colRed(colInner);
    ubyte green = colGreen(colInner);
    ubyte blue = colBlue(colInner);

    dbgAssert(nSlices >= 3);

    centreX = primScreenToGLX(x);                           //make floating-point versions of parameters
    centreY = primScreenToGLY(y);
    radXInner = primScreenToGLScaleX(radInner);
    radYInner = primScreenToGLScaleY(radInner);
    radXOuter = primScreenToGLScaleX(radOuter);
    radYOuter = primScreenToGLScaleY(radOuter);
    addAmount = (double)(2.0f * PI / (real32)(nSlices - 1));
    theta = addAmount;

    x0 = x2 = centreX;
    y0 = centreY - radYInner;
    y2 = centreY - radYOuter;

    glShadeModel(GL_SMOOTH);
    glEnable(GL_BLEND);
    for (index = 0; index < nSlices; index++)
    {
        glBegin(GL_TRIANGLE_FAN);
        glColor4ub(red, green, blue, 255);

        glVertex2f(x0, y0);                                 //2 common points
        glVertex2f(centreX, centreY);

        sinTheta = (real32)sin(theta);
        cosTheta = (real32)cos(theta);

        x0 = centreX + sinTheta * radXInner;
        y0 = centreY + cosTheta * radYInner;
        glVertex2f(x0, y0);                                 //complete
        glColor4ub(red, green, blue, 0);

        x1 = centreX + sinTheta * radXOuter;
        y1 = centreY + cosTheta * radYOuter;

        glVertex2f(x1, y1);                                 //complete
        glVertex2f(x2, y2);
        x2 = x1;
        y2 = y1;

        glEnd();
        theta += addAmount;
    }
    glDisable(GL_BLEND);
    glShadeModel(GL_FLAT);
}
Beispiel #10
0
/*-----------------------------------------------------------------------------
    Name        : primRectSolid2
    Description : Draw a solid 2d rectangle.
    Inputs      : rect - pointer to rectangle structure containing coordinates.
                  c - color to draw it in.
    Outputs     : ..
    Return      : void
----------------------------------------------------------------------------*/
void primRectSolid2(rectangle *rect, color c)
{
    if (glcActive())
    {
        glcRectSolid2(rect, c);
    }
    else
    {
        glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c));
        glBegin(GL_QUADS);
        glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0));
        glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1));
        glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1));
        glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0));
        glEnd();
    }
}
Beispiel #11
0
/*-----------------------------------------------------------------------------
    Name        : primTriOutline2
    Description : Draw a 2D triangle outline
    Inputs      : tri - pointer to triangle structure containing coordinates of corners
                  thickness - thickness of the lines
                  c - color to draw it in
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
void primTriOutline2(triangle *tri, sdword thickness, color c)
{
    if (glcActive())
    {
        glcTriOutline2(tri, thickness, c);
    }
    else
    {
        glColor3ub(colRed(c), colGreen(c), colBlue(c));
        glPushAttrib(GL_LINE_BIT);
        glLineWidth((GLfloat)thickness);
        glBegin(GL_LINE_LOOP);
        glVertex2f(primScreenToGLX(tri->x0), primScreenToGLY(tri->y0));
        glVertex2f(primScreenToGLX(tri->x1), primScreenToGLY(tri->y1));
        glVertex2f(primScreenToGLX(tri->x2), primScreenToGLY(tri->y2));
        glEnd();
        glPopAttrib();
    }
}
Beispiel #12
0
/*-----------------------------------------------------------------------------
    Name        : primRectTranslucentRGL2
    Description : helper for primRectTranslucent2, rGL(sw) only (will temporarily
                  disable stippling)
    Inputs      : rect - rectangle structure containing coordinates
                  c - color of the rectangle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void primRectTranslucentRGL2(rectangle* rect, color c)
{
    GLboolean blendOn;
    GLboolean stippleOn;

    blendOn = glIsEnabled(GL_BLEND);
    stippleOn = glIsEnabled(GL_POLYGON_STIPPLE);
    if (!blendOn) glEnable(GL_BLEND);
    if (stippleOn) glDisable(GL_POLYGON_STIPPLE);
    glColor4ub(colRed(c), colGreen(c), colBlue(c), colAlpha(c));
    glBegin(GL_QUADS);
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y0));
    glVertex2f(primScreenToGLX(rect->x0), primScreenToGLY(rect->y1));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y1));
    glVertex2f(primScreenToGLX(rect->x1), primScreenToGLY(rect->y0));
    glEnd();
    if (!blendOn) glDisable(GL_BLEND);
    if (stippleOn) glEnable(GL_POLYGON_STIPPLE);
}
Beispiel #13
0
void tutDrawLinePulse(sdword x0, sdword y0, sdword x1, sdword y1, ubyte pulsevalue, sdword segsize)
{
    real32 x0f = (real32)x0;
    real32 y0f = (real32)y0;
    real32 x1f = (real32)x1;
    real32 y1f = (real32)y1;

    real32 diffx = (x1f - x0f);
    real32 diffy = (y1f - y0f);
    sdword segment;
    real32 segments;
    bool blendon;

    segments = fsqrt(diffx*diffx + diffy*diffy) / (real32)segsize;

    diffx /= segments;
    diffy /= segments;

    if (glCapFeatureExists(GL_LINE_SMOOTH))
    {
        blendon = (bool)glIsEnabled(GL_BLEND);
        if (!blendon) glEnable(GL_BLEND);
        glEnable(GL_LINE_SMOOTH);
    }
    glBegin(GL_LINES);
    for(segment = 0; segment <= segments; segment++)
    {
        glColor3ub(pulsevalue, pulsevalue, pulsevalue);
        glVertex2f(primScreenToGLX((sdword)x0f), primScreenToGLY((sdword)y0f));
        x0f += diffx;
        y0f += diffy;
        glVertex2f(primScreenToGLX((sdword)x0f), primScreenToGLY((sdword)y0f));
        pulsevalue += 25;
    }
    glEnd();
    if (glCapFeatureExists(GL_LINE_SMOOTH))
    {
        glDisable(GL_LINE_SMOOTH);
        if (!blendon) glDisable(GL_BLEND);
    }
}
Beispiel #14
0
/*-----------------------------------------------------------------------------
    Name        : partCircleSolid2
    Description : Render a 2d circle, like the 3D one.
    Inputs      :
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void primCircleSolid2(sdword x, sdword y, sdword rad, sdword nSlices, color c)
{
    sdword index;
    GLfloat v[3];
    double theta;
    vector centre;
    real32 radiusX, radiusY;
    bool cull;

    if (glcActive())
    {
        rectangle r;
        r.x0 = x - rad;
        r.y0 = y - rad;
        r.x1 = x + rad;
        r.y1 = y + rad;
        glcRectSolid2(&r, c);
        return;
    }

    cull = glIsEnabled(GL_CULL_FACE) ? TRUE : FALSE;

    centre.x = primScreenToGLX(x);
    centre.y = primScreenToGLY(y);
    radiusX = primScreenToGLScaleX(rad);
    radiusY = primScreenToGLScaleY(rad);

    glColor4ub(colRed(c), colGreen(c),
               colBlue(c), colAlpha(c));
    v[0] = centre.x;
    v[1] = centre.y;
    glDisable(GL_CULL_FACE);
    glBegin(GL_TRIANGLE_FAN);
    glVertex2f(v[0], v[1]);
    for (index = 0, theta = 0.0; index < nSlices; index++)
    {
        v[0] = centre.x + (real32)(sin(theta)) * radiusX;
        v[1] = centre.y + (real32)(cos(theta)) * radiusY;
        theta += 2.0 * PI / (double)nSlices;
        glVertex2f(v[0], v[1]);
    }
    v[0] = centre.x;
    v[1] = centre.y + radiusY;
    glVertex2f(v[0], v[1]);
    glEnd();
    if (cull)
    {
        glEnable(GL_CULL_FACE);
    }
}
void hrRectSolidTextured2(rectangle *rect)
{
    GLfloat t[8] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
    GLfloat v[8] = { primScreenToGLX(rect->x0), primScreenToGLY(rect->y1 - 1),
                     primScreenToGLX(rect->x1), primScreenToGLY(rect->y1 - 1),
                     primScreenToGLX(rect->x0), primScreenToGLY(rect->y0),
                     primScreenToGLX(rect->x1), primScreenToGLY(rect->y0) };

    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

    rndTextureEnvironment(RTE_Replace);
    rndTextureEnable(TRUE);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, v);
    glTexCoordPointer(2, GL_FLOAT, 0, t);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    rndTextureEnable(FALSE);
    rndTextureEnvironment(RTE_Modulate);
}
Beispiel #16
0
void primBlurryPoint22(sdword x, sdword y, color c)
{
    sdword iX, iY;
    ubyte *alpha, red = colRed(c), green = colGreen(c), blue = colBlue(c);

    glEnable(GL_BLEND);
    glBegin(GL_POINTS);
    alpha = &p2dAlphaArray2[0][0];
    for (iY = PD2_FuzzyPointYStart; iY <= PD2_FuzzyPointYEnd; iY++)
    {
        for (iX = PD2_FuzzyPointXStart; iX <= PD2_FuzzyPointXEnd; iX++, alpha++)
        {
            glColor4ub(red, green, blue, *alpha);
            glVertex2f(primScreenToGLX((x + iX)), primScreenToGLY((y + iY)));
        }
    }
    glEnd();
    glColor4ub(0, 0, 0, 0xff);
    glDisable(GL_BLEND);
}
Beispiel #17
0
/*-----------------------------------------------------------------------------
    Name        : primOvalArcOutline2
    Description : Draw an outline section of an oval.
    Inputs      : o - oval structure describing location and size on-screen
                  degStarts, degEnd - degree stations of start and end of line
                  thickness - thickness of lines
                  segments - number of line segments for a complete oval
                  c - color to draw outline in
    Outputs     : ..
    Return      : void
    Note        : The coordinate system used will be the engineering system
                    where up (x = 0, y = -1) is 0 rad.
----------------------------------------------------------------------------*/
void primOvalArcOutline2(oval *o, real32 radStart, real32 radEnd, sdword thickness, sdword segments, color c)
{
    sdword segment, endSegment;
    real32 angle, angleInc;
    real32 centreX, centreY, width, height;
    real32 x, y, lastX, lastY;

    if (glcActive())
    {
        centreX = (real32)o->centreX;
        centreY = (real32)o->centreY;
        width  = (real32)o->radiusX;
        height = (real32)o->radiusY;
    }
    else
    {
        centreX = primScreenToGLX(o->centreX);                  //get floating-point version of oval attributes
        centreY = primScreenToGLY(o->centreY);
        width  = primScreenToGLScaleX(o->radiusX);
        height = primScreenToGLScaleY(o->radiusY);
    }

    segment = (sdword)(radStart * (real32)segments / (2.0f * PI));//get starting segment
    endSegment = (sdword)(radEnd * (real32)segments / (2.0f * PI) - 0.01f);//get ending segment

    glColor3ub(colRed(c), colGreen(c), colBlue(c));
    glPushAttrib(GL_LINE_BIT);
    glLineWidth((GLfloat)thickness);
    glBegin(GL_LINE_STRIP);

    x = centreX + (real32)sin((double)radStart) * width;    //first vertex
    y = centreY + (real32)cos((double)radStart) * height;
    if (glcActive())
    {
        lastX = x;
        lastY = y;
    }
    else
    {
        glVertex2f(x, y);
    }
    segment++;
    angle = (real32)segment * (2.0f * PI / (real32)segments);
    angleInc = (2.0f * PI / (real32)segments);

    for (; segment <= endSegment; segment++)
    {                                                       //for start and all complete segments
        x = centreX + (real32)sin((double)angle) * width;
        y = centreY + (real32)cos((double)angle) * height;
        if (glcActive())
        {
            glcLine2((sdword)lastX, (sdword)lastY,
                     (sdword)x, (sdword)y,
                     thickness, c);
            lastX = x;
            lastY = y;
        }
        else
        {
            glVertex2f(x, y);
        }
        angle += angleInc;                                  //update angle
    }
    x = centreX + (real32)sin((double)radEnd) * width;
    y = centreY + (real32)cos((double)radEnd) * height;
    if (glcActive())
    {
        glcLine2((sdword)lastX, (sdword)lastY,
                 (sdword)x, (sdword)y,
                 thickness, c);
    }
    else
    {
        glVertex2f(x, y);                                       //draw last vertex
    }

    glEnd();
    glPopAttrib();
}
Beispiel #18
0
/*-----------------------------------------------------------------------------
    Name        : pingListDraw
    Description : Draw all pings from farthest to nearest.
    Inputs      : camera - the camera we're rendering from
                  modelView, projection - current matrices
                  viewPort - rectangle we're rending in, for the TO legend
    Outputs     :
    Return      :
    Note        : The renderer should be in 2D mode at this point.
----------------------------------------------------------------------------*/
void pingListDraw(Camera *camera, hmatrix *modelView, hmatrix *projection, rectangle *viewPort)
{
    real32 pingAge, pingCycle, pingMod, pingSize;
    real32 x, y, radius;
    Node *thisNode, *nextNode;
    ping *thisPing;
    vector distSquared;
    sdword nSegments, index, rowHeight, xScreen, yScreen;
    oval o;
    udword TOFlags = 0;
    fonthandle fhSave;
    toicon *icon;
    color col;
    real32 realMargin;
    ShipClass shipClass;
    static real32 lastProximityPing = REALlyBig;
    static real32 lastAnomolyPing = REALlyBig;
    static real32 lastBattlePing = REALlyBig;
    static real32 lastHyperspacePing = REALlyBig;
    static real32 lastNewshipPing = REALlyBig;
    bool pingset;

    //start by sorting the ping list from farthest to nearest
    thisNode = pingList.head;

    while (thisNode != NULL)
    {                                                       //scan all pings
        nextNode = thisNode->next;
        thisPing = listGetStructOfNode(thisNode);

        if (thisPing->owner != NULL)
        {
            thisPing->centre = thisPing->owner->posinfo.position;
        }
        vecSub(distSquared, camera->eyeposition, thisPing->centre);
        thisPing->cameraDistanceSquared = vecMagnitudeSquared(distSquared);
        TOFlags |= thisPing->TOMask;

        thisNode = nextNode;
    }
    listMergeSortGeneral(&pingList, pingListSortCallback);

    //now the list is sorted; proceed to draw all the pings
    thisNode = pingList.head;

    pingset = FALSE;

    while (thisNode != NULL)
    {                                                       //scan all pings
        nextNode = thisNode->next;
        thisPing = listGetStructOfNode(thisNode);

        pingCycle = thisPing->pingDuration + thisPing->interPingPause;
        pingAge = universe.totaltimeelapsed - thisPing->creationTime;
        pingMod = (real32)fmod((double)pingAge, (double)pingCycle);
        if (pingMod <= thisPing->pingDuration)
        {
            pingSize = (thisPing->size - thisPing->minSize) * pingMod / thisPing->pingDuration + thisPing->minSize;
            selCircleComputeGeneral(modelView, projection, &thisPing->centre, max(thisPing->size,thisPing->minSize), &x, &y, &radius);
            if (radius > 0.0f)
            {
                radius = max(radius, thisPing->minScreenSize);
                radius *= pingSize / max(thisPing->size,thisPing->minSize);
                o.centreX = primGLToScreenX(x);
                o.centreY = primGLToScreenY(y);
                o.radiusX = o.radiusY = primGLToScreenScaleX(radius);
                nSegments = pieCircleSegmentsCompute(radius);
                primOvalArcOutline2(&o, 0.0f, 2*PI, 1, nSegments, thisPing->c);

                /* starting to draw a new ping so play the sound */
                if (!smZoomingIn && !smZoomingOut && !pingset)
                {
                    switch (thisPing->TOMask)
                    {
                        case PTOM_Anomaly:
                            if (pingSize <=lastAnomolyPing)
                            {
                                soundEvent(NULL, UI_SensorsPing);
                                pingset = TRUE;
                                lastAnomolyPing = pingSize;
                            }
                            break;
                        case PTOM_Battle:
                            if (pingSize <= lastBattlePing)
                            {
                                soundEvent(NULL, UI_PingBattle);
                                pingset = TRUE;
                                lastBattlePing = pingSize;
                            }
                            break;
                        case PTOM_Hyperspace:
                            if (pingSize <=  lastHyperspacePing)
                            {
                                soundEvent(NULL, UI_PingHyperspace);
                                pingset = TRUE;
                                lastHyperspacePing = pingSize;
                            }
                            break;
                        case PTOM_Proximity:
                            if (pingSize <= lastProximityPing)
                            {
                                soundEvent(NULL, UI_PingProximity);
                                pingset = TRUE;
                                lastProximityPing = pingSize;
                            }
                            break;
                        case PTOM_NewShips:
                            if (pingSize <= lastNewshipPing)
                            {
                                soundEvent(NULL, UI_PingNewShips);
                                pingset = TRUE;
                                lastNewshipPing = pingSize;
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        thisNode = nextNode;
    }

    //draw the blip TO
    if (smTacticalOverlay)
    {
        realMargin = primScreenToGLScaleX(viewPort->x0);
        fhSave = fontCurrentGet();                          //save the current font
        fontMakeCurrent(selGroupFont2);                     // use a common, fairly small font
        rowHeight = fontHeight("M");                        // used to space the legend
        yScreen = viewPort->y0 + rowHeight;                 //leave some space at the top to start
        radius = primScreenToGLScaleX(rowHeight)/2;
        xScreen = viewPort->x0 + (sdword)(rowHeight * 2.5);

        for (index = 0; index < PTO_NumberTOs; index++)
        {
            if ((TOFlags & pingTOList[index].bitMask))
            {
    //            fontPrint(xScreen, yScreen, *pingTOList[index].c, "O");
                pingTOList[index].lastTimeDrawn = universe.totaltimeelapsed;
            }
            if (universe.totaltimeelapsed - pingTOList[index].lastTimeDrawn <= pingTOLingerTime)
            {
                o.centreX = viewPort->x0 + rowHeight * 3 / 2;
                o.centreY = yScreen + rowHeight / 2;
                o.radiusX = o.radiusY = rowHeight / 2;
                primOvalArcOutline2(&o, 0.0f, TWOPI, 1, pingTONSegments, *pingTOList[index].c);
                fontPrint(xScreen, yScreen, TO_TextColor, strGetString(pingTOList[index].stringEnum));
                yScreen += rowHeight + 1;
            }
        }
        for (shipClass = 0; shipClass < NUM_CLASSES; shipClass++)
        {
            if (!toClassUsed[shipClass][0])
            {
                continue;
            }
            icon = toClassIcon[shipClass];
            fontPrint(xScreen, yScreen + (rowHeight>>2), TO_TextColor, ShipClassToNiceStr(shipClass));
#if TO_STANDARD_COLORS
            col = teFriendlyColor;
#else
            col = teColorSchemes[universe.curPlayerIndex].tacticalColor;
#endif
            col = colRGB(colRed(col)/TO_IconColorFade, colGreen(col)/TO_IconColorFade, colBlue(col)/TO_IconColorFade);
            primLineLoopStart2(1, col);

            for (index = icon->nPoints - 1; index >= 0; index--)
            {
               primLineLoopPoint3F(realMargin + primScreenToGLX(rowHeight*1.5) + icon->loc[index].x * radius,
                                          primScreenToGLY(yScreen + rowHeight/2) + icon->loc[index].y * radius);
            }
            primLineLoopEnd2();
            yScreen += rowHeight + 1;
        }

        fontMakeCurrent(fhSave);
    }
}