/***************************************************************************
 *                                                                         *
 * Module  : basky.c                                                       *
 *                                                                         *
 * Purpose : Quick and dirty sky port                                      *
 *         : 99/05/25 Quick conversion to hardware			   *
 *                                                                         *
 **************************************************************************/

/***************************************************************************
 Includes
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

/* Sony lib includes. I can't believe I'm using them */
#include <eekernel.h>
#include <eetypes.h>
#include <eeregs.h>
#include <libgraph.h>
#include <libdma.h>
#include <libdev.h>
/* end Sony includes */

#include "batypes.h"
#include "badevice.h"
#include "balibtyp.h"
#include "barwtyp.h"
#include "baimmedi.h"
#include "bapiputl.h"
#include "bacamera.h"

#include "pipmodel.h"

/* String abstraction API for unicode support */
#include "rwstring.h"

/* Drag in the vertex format */
#include "drvmodel.h"

/* Other driver module includes */

/* Include profiler */
#include "devprofile.h"

/* This files header */
#include "basky.h"
#include "skyovrld.h"

static const char rcsid[] __RWUNUSED__ = "@@(#)$Id: skyovrld.c,v 1.7 2000/11/22 15:48:43 iestynb Exp $";


/****************************************************************************
 Local Types
 */

/****************************************************************************
 Local (Static) Prototypes
 */

/****************************************************************************
 Local Defines
 */

/****************************************************************************
 Globals (across program)
 */

/****************************************************************************
 Local (static) Globals
 */

/* Old set clip and cull */
static void (*skyOldSetClipCull)(RwCameraProjection);

/* Old set Overload function */
static _rwPipeSetOverloadsFn skyOldOverloadFn;

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                          Overload functions

 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

/* We have our own set as we want to conditional compile for VU1TRANS and
   to use SPR where appropriate */

/****************************************************************************
 SkyCamDevUVFromInst

 On entry   : Instanced data
 On exit    :
 */

static void
SkyCamDevUVFromInst(RwResEntry *repEntry)
{
    RwInt32            numVerts;
#ifndef VU1TRANS
    RwCameraVertex     *camVert;
#endif /* !VU1TRANS */
    RwIm2DVertex       *devVert;
    RWVERTEXINSTANCE   *instVert;

    RWFUNCTION(RWSTRING("SkyCamDevUVFromInst"));
    PFENTRY(PFSkyCamDevUVFromInst);
    RWASSERT(repEntry);

#ifndef VU1TRANS
    camVert = RwCameraVertexGet(0);
#endif /* !VU1TRANS */
    devVert = RwIm2DVertexGet(0);
    instVert = RWVERTEXINSTANCEGet(repEntry, 0);
    numVerts = RWVERTEXINSTANCEGetQuantity(repEntry);

#ifndef VU1TRANS
    if (_rwPipeState.currentContext->clipFlagsOr == 0)
    {
#endif /* !VU1TRANS */
        while (numVerts--)
        {
#ifndef VU1TRANS
            RwReal         recipZ = RwIm2DVertexGetRecipZ(devVert);

            RwCameraVertexSetU(camVert, RWVERTEXINSTANCEGetU(instVert));
            RwCameraVertexSetV(camVert, RWVERTEXINSTANCEGetV(instVert));
            RwIm2DVertexSetU(devVert, RwCameraVertexGetU(camVert), recipZ);
            RwIm2DVertexSetV(devVert, RwCameraVertexGetV(camVert), recipZ);

            camVert = RwCameraVertexGetNext(camVert);
#else /* !VU1TRANS */
            devVert->texU =  RWVERTEXINSTANCEGetU(instVert);
            devVert->texV =  RWVERTEXINSTANCEGetV(instVert);
            devVert->texS = devVert->texU;
            devVert->texT = devVert->texV;

#endif /* !VU1TRANS */
            devVert = RwIm2DVertexGetNext(devVert);
            instVert = RWVERTEXINSTANCEGetNext(repEntry, instVert);
        }
#ifndef VU1TRANS
    }
    else
    {
        while (numVerts--)
        {
            RwCameraVertexSetU(camVert, RWVERTEXINSTANCEGetU(instVert));
            RwCameraVertexSetV(camVert, RWVERTEXINSTANCEGetV(instVert));

            if (RwCameraVertexGetClipFlags(camVert) == 0)
            {
                RwReal         recipZ = RwIm2DVertexGetRecipZ(devVert);

                RwIm2DVertexSetU(devVert, RwCameraVertexGetU(camVert), recipZ);
                RwIm2DVertexSetV(devVert, RwCameraVertexGetV(camVert), recipZ);
            }

            camVert = RwCameraVertexGetNext(camVert);
            devVert = RwIm2DVertexGetNext(devVert);
            instVert = RWVERTEXINSTANCEGetNext(repEntry, instVert);
        }
    }
#endif /* !VU1TRANS */
    PFEXIT(PFSkyCamDevUVFromInst);
    RWRETURNVOID();
}

/****************************************************************************/
static void
SkyDupeVertex( RwCameraVertex **cv, RwIm2DVertex **dv, RwInt32 **vert)
{
    RwInt32         newVertIndex;
#ifndef VU1TRANS
    RwCameraVertex  *newCamVert;
    long temp1, temp2, temp3, temp4, temp5, temp6;
#endif /* !VU1TRANS */
    RwIm2DVertex    *newDevVert;
    u_long128 temp7, temp8, temp9;

    RWFUNCTION(RWSTRING("SkyDupeVertex"));

    PFENTRY(PFSkyDupeVertex);

    newVertIndex = _rwGenerateNewVertex();
#ifndef VU1TRANS
    newCamVert = RwCameraVertexGet(newVertIndex);
#endif /* !VU1TRANS */
    newDevVert = RwIm2DVertexGet(newVertIndex);

    /* Dupe the verts */
#ifndef VU1TRANS
    /* We know we can copy camera vertices using 8 byte copies because:
     * 1) They are 16 byte aligned.
     * 2) They are 40 bytes large - (multiple of 8 bytes).
     */
    temp1 = ((long *)(*cv))[0];
    temp2 = ((long *)(*cv))[1];
    temp3 = ((long *)(*cv))[2];
    temp4 = ((long *)(*cv))[3];
    temp5 = ((long *)(*cv))[4];
    temp6 = ((long *)(*cv))[5];
    ((long *)newCamVert)[0] = temp1;
    ((long *)newCamVert)[1] = temp2;
    ((long *)newCamVert)[2] = temp3;
    ((long *)newCamVert)[3] = temp4;
    ((long *)newCamVert)[4] = temp5;
    ((long *)newCamVert)[5] = temp6;
#endif /* !VU1TRANS */
    /* We know we can copy device vertices using 16 byte copies because:
     * 1) They are 16 byte aligned.
     * 2) They are 48 bytes large - (multiple of 16 bytes).
     */
    temp7 = ((u_long128 *)(*dv))[0];
    temp8 = ((u_long128 *)(*dv))[1];
    temp9 = ((u_long128 *)(*dv))[2];
    ((u_long128 *)newDevVert)[0] = temp7;
    ((u_long128 *)newDevVert)[1] = temp8;
    ((u_long128 *)newDevVert)[2] = temp9;

    **vert = newVertIndex;
#ifndef VU1TRANS
    *cv = newCamVert;
#endif /* !VU1TRANS */
    *dv = newDevVert;
    PFEXIT(PFSkyDupeVertex);

    RWRETURNVOID();
}

/****************************************************************************
 SkyCamDevUVFromInstPolygon

 On entry   : Instanced polygon, vertex indices
 On exit    :
 */

static void
SkyCamDevUVFromInstPolygon(RWPOLYGONINSTANCE *instPoly,
                              RwInt32 *vert1, RwInt32 *vert2, RwInt32 *vert3)
{
    RwUInt8           currentFrame = _rwPipeState.currentContext->overLoadFrame;
#ifndef VU1TRANS
    RwCameraVertex    *cv1, *cv2, *cv3;
#endif /* !VU1TRANS */
    RwIm2DVertex      *dv1, *dv2, *dv3;
#ifndef VU1TRANS
    RwReal            nRecipZ, tempU, tempV;
#endif /* !VU1TRANS */

    RWFUNCTION(RWSTRING("SkyCamDevUVFromInstPolygon"));
    PFENTRY(PFSkyCamDevUVFromInstPolygon);
    RWASSERT(instPoly);
    RWASSERT(vert1);
    RWASSERT(vert2);
    RWASSERT(vert3);

#ifndef VU1TRANS
    cv1 = RwCameraVertexGet(*vert1);
    cv2 = RwCameraVertexGet(*vert2);
    cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */

#ifdef RWPIPELINEFLUSHPIPE
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Check if we can overload vertices, if we can't then flush */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        /* Flush what we've got, since we're re-using an overloaded vertex */
        _rwPipeState.fpDrawIndexBuffer();
        _rwPipeState.fpResetIndexBuffer();
        currentFrame = _rwPipeState.currentContext->overLoadFrame;
    }
#else /* RWPIPELINEFLUSHPIPE */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        if ((_rwPipeState.currentContext->baseVertexIndex +
             _rwPipeState.currentContext->clippedVertexIndex + 20) > _rwPipeState.currentPipeSize)
        {
            _rwResizePipe(_rwPipeState.currentContext->clippedVertexIndex + 50);
        }

#ifndef VU1TRANS
        /* They have moved */
        cv1 = RwCameraVertexGet(*vert1);
        cv2 = RwCameraVertexGet(*vert2);
        cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */
    }

    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Duplicate vertices which are already overloaded */
#ifndef VU1TRANS
    if (cv1->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv1->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv1,&dv1,&vert1);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv1,&vert1);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv2->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv2->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv2,&dv2,&vert2);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv2,&vert2);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv3->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv3->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv3,&dv3,&vert3);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv3,&vert3);
#endif /* !VU1TRANS */
    }
#endif /* RWPIPELINEFLUSHPIPE */

#ifndef VU1TRANS
    nRecipZ = RwIm2DVertexGetRecipZ(dv1);
    tempU = RWPOLYGONINSTANCEGetU1(instPoly);
    tempV = RWPOLYGONINSTANCEGetV1(instPoly);
    RwIm2DCameraVertexSetU(dv1, cv1, tempU, nRecipZ);
    RwIm2DCameraVertexSetV(dv1, cv1, tempV, nRecipZ);

    nRecipZ = RwIm2DVertexGetRecipZ(dv2);
    tempU = RWPOLYGONINSTANCEGetU2(instPoly);
    tempV = RWPOLYGONINSTANCEGetV2(instPoly);
    RwIm2DCameraVertexSetU(dv2, cv2, tempU, nRecipZ);
    RwIm2DCameraVertexSetV(dv2, cv2, tempV, nRecipZ);

    nRecipZ = RwIm2DVertexGetRecipZ(dv3);
    tempU = RWPOLYGONINSTANCEGetU3(instPoly);
    tempV = RWPOLYGONINSTANCEGetV3(instPoly);
    RwIm2DCameraVertexSetU(dv3, cv3, tempU, nRecipZ);
    RwIm2DCameraVertexSetV(dv3, cv3, tempV, nRecipZ);
#else /* !VU1TRANS */
    dv1->texU = RWPOLYGONINSTANCEGetU1(instPoly);
    dv1->texV = RWPOLYGONINSTANCEGetV1(instPoly);
    dv1->texS = dv1->texU;
    dv1->texT = dv1->texV;

    dv2->texU = RWPOLYGONINSTANCEGetU2(instPoly);
    dv2->texV = RWPOLYGONINSTANCEGetV2(instPoly);
    dv2->texS = dv2->texU;
    dv2->texT = dv2->texV;

    dv3->texU = RWPOLYGONINSTANCEGetU3(instPoly);
    dv3->texV = RWPOLYGONINSTANCEGetV3(instPoly);
    dv3->texS = dv3->texU;
    dv3->texT = dv3->texV;
#endif /* !VU1TRANS */

#ifndef VU1TRANS
    cv1->overLoad = currentFrame;
    cv2->overLoad = currentFrame;
    cv3->overLoad = currentFrame;
#else /* !VU1TRANS */
    dv1->overLoad = currentFrame;
    dv2->overLoad = currentFrame;
    dv3->overLoad = currentFrame;
#endif /* !VU1TRANS */

    PFEXIT(PFSkyCamDevUVFromInstPolygon);
    RWRETURNVOID();
}

/****************************************************************************
 SkyCamDevColorFromInstPolygon

 On entry   : Instanced polygon, vertex indices
 On exit    :
 */

static void
SkyCamDevColorFromInstPolygon(RWPOLYGONINSTANCE *instPoly,
                                 RwInt32 *vert1, RwInt32 *vert2, RwInt32 *vert3)
{
    RwUInt8           currentFrame = _rwPipeState.currentContext->overLoadFrame;
#ifndef VU1TRANS
    RwCameraVertex    *cv1, *cv2, *cv3;
#endif /* !VU1TRANS */
    RwIm2DVertex      *dv1, *dv2, *dv3;
    RwRGBAReal        *lightCol, scaledCol;
    RwRGBA            *vertCol;
#ifdef VU1TRANS
    RwRGBAReal        lightColStruct;
#endif /* VU1TRANS */

    RWFUNCTION(RWSTRING("SkyCamDevColorFromInstPolygon"));
    PFENTRY(PFSkyCamDevColorFromInstPolygon);
    RWASSERT(instPoly);
    RWASSERT(vert1);
    RWASSERT(vert2);
    RWASSERT(vert3);

#ifdef VU1TRANS
    lightCol = &lightColStruct;
#endif /* VU1TRANS */

#ifndef VU1TRANS
    cv1 = RwCameraVertexGet(*vert1);
    cv2 = RwCameraVertexGet(*vert2);
    cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */

#ifdef RWPIPELINEFLUSHPIPE
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Check if we can overload vertices, if we can't then flush */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        /* Flush what we've got, since we're re-using an overloaded vertex */
        _rwPipeState.fpDrawIndexBuffer();
        _rwPipeState.fpResetIndexBuffer();
        currentFrame = _rwPipeState.currentContext->overLoadFrame;
    }
#else /* RWPIPELINEFLUSHPIPE */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        if ((_rwPipeState.currentContext->baseVertexIndex +
             _rwPipeState.currentContext->clippedVertexIndex + 20) > _rwPipeState.currentPipeSize)
        {
            _rwResizePipe(_rwPipeState.currentContext->clippedVertexIndex + 50);
        }

#ifndef VU1TRANS
        /* They have moved */
        cv1 = RwCameraVertexGet(*vert1);
        cv2 = RwCameraVertexGet(*vert2);
        cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */
    }

    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Duplicate vertices which are already overloaded */
#ifndef VU1TRANS
    if (cv1->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv1->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv1,&dv1,&vert1);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv1,&vert1);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv2->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv2->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv2,&dv2,&vert2);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv2,&vert2);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv3->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv3->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv3,&dv3,&vert3);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv3,&vert3);
#endif /* !VU1TRANS */
    }
#endif /* RWPIPELINEFLUSHPIPE */

#ifndef VU1TRANS
    lightCol = RwCameraVertexGetRGBA(cv1);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv1);
    lightCol->green = RwIm2DVertexGetGreen(dv1);
    lightCol->blue = RwIm2DVertexGetBlue(dv1);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv1);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA1(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
    RwIm2DVertexSetRealRGBA(dv1, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    lightCol = RwCameraVertexGetRGBA(cv2);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv2);
    lightCol->green = RwIm2DVertexGetGreen(dv2);
    lightCol->blue = RwIm2DVertexGetBlue(dv2);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv2);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA2(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
    RwIm2DVertexSetRealRGBA(dv2, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    lightCol = RwCameraVertexGetRGBA(cv3);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv3);
    lightCol->green = RwIm2DVertexGetGreen(dv3);
    lightCol->blue = RwIm2DVertexGetBlue(dv3);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv3);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA3(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
    RwIm2DVertexSetRealRGBA(dv3, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    cv1->overLoad = currentFrame;
    cv2->overLoad = currentFrame;
    cv3->overLoad = currentFrame;
#else /* !VU1TRANS */
    dv1->overLoad = currentFrame;
    dv2->overLoad = currentFrame;
    dv3->overLoad = currentFrame;
#endif /* !VU1TRANS */

    PFEXIT(PFSkyCamDevColorFromInstPolygon);
    RWRETURNVOID();
}

/****************************************************************************
 SkyCamDevUVColorFromInstPolygon

 On entry   : Instanced polygon, vertex indices
 On exit    :
 */

static void
SkyCamDevUVColorFromInstPolygon(RWPOLYGONINSTANCE *instPoly,
                                   RwInt32 *vert1, RwInt32 *vert2,
                                   RwInt32 *vert3)
{
    RwUInt8           currentFrame = _rwPipeState.currentContext->overLoadFrame;
#ifndef VU1TRANS
    RwCameraVertex    *cv1, *cv2, *cv3;
#endif /* !VU1TRANS */
    RwIm2DVertex      *dv1, *dv2, *dv3;
#ifndef VU1TRANS
    RwReal            nRecipZ;
#endif /* !VU1TRANS */
    RwRGBAReal        *lightCol, scaledCol;
    RwRGBA            *vertCol;
#ifdef VU1TRANS
    RwRGBAReal        lightColStruct;
#endif /* VU1TRANS */

    RWFUNCTION(RWSTRING("SkyCamDevUVColorFromInstPolygon"));
    PFENTRY(PFSkyCamDevUVColorFromInstPolygon);
    RWASSERT(instPoly);
    RWASSERT(vert1);
    RWASSERT(vert2);
    RWASSERT(vert3);

#ifdef VU1TRANS
    lightCol = &lightColStruct;
#endif /* VU1TRANS */

#ifndef VU1TRANS
    cv1 = RwCameraVertexGet(*vert1);
    cv2 = RwCameraVertexGet(*vert2);
    cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */

#ifdef RWPIPELINEFLUSHPIPE
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Check if we can overload vertices, if we can't then flush */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        /* Flush what we've got, since we're re-using an overloaded vertex */
        _rwPipeState.fpDrawIndexBuffer();
        _rwPipeState.fpResetIndexBuffer();
        currentFrame = _rwPipeState.currentContext->overLoadFrame;
    }
#else /* RWPIPELINEFLUSHPIPE */
#ifndef VU1TRANS
    if ((cv1->overLoad == currentFrame) || (cv2->overLoad == currentFrame) ||
        (cv3->overLoad == currentFrame))
#else /* !VU1TRANS */
    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);
    if ((dv1->overLoad == currentFrame) || (dv2->overLoad == currentFrame) ||
        (dv3->overLoad == currentFrame))
#endif /* !VU1TRANS */
    {
        if ((_rwPipeState.currentContext->baseVertexIndex +
             _rwPipeState.currentContext->clippedVertexIndex + 20) > _rwPipeState.currentPipeSize)
        {
            _rwResizePipe(_rwPipeState.currentContext->clippedVertexIndex + 50);
        }

#ifndef VU1TRANS
        /* They have moved */
        cv1 = RwCameraVertexGet(*vert1);
        cv2 = RwCameraVertexGet(*vert2);
        cv3 = RwCameraVertexGet(*vert3);
#endif /* !VU1TRANS */
    }

    dv1 = RwIm2DVertexGet(*vert1);
    dv2 = RwIm2DVertexGet(*vert2);
    dv3 = RwIm2DVertexGet(*vert3);

    /* Duplicate vertices which are already overloaded */
#ifndef VU1TRANS
    if (cv1->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv1->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv1,&dv1,&vert1);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv1,&vert1);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv2->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv2->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv2,&dv2,&vert2);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv2,&vert2);
#endif /* !VU1TRANS */
    }

#ifndef VU1TRANS
    if (cv3->overLoad == currentFrame)
#else /* !VU1TRANS */
    if (dv3->overLoad == currentFrame)
#endif /* !VU1TRANS */
    {
#ifndef VU1TRANS
        SkyDupeVertex(&cv3,&dv3,&vert3);
#else /* !VU1TRANS */
        SkyDupeVertex(NULL,&dv3,&vert3);
#endif /* !VU1TRANS */
    }
#endif /* RWPIPELINEFLUSHPIPE */

#ifndef VU1TRANS
    nRecipZ = RwIm2DVertexGetRecipZ(dv1);
    lightCol = RwCameraVertexGetRGBA(cv1);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv1);
    lightCol->green = RwIm2DVertexGetGreen(dv1);
    lightCol->blue = RwIm2DVertexGetBlue(dv1);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv1);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA1(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
#ifndef VU1TRANS
    RwIm2DCameraVertexSetU(dv1, cv1, RWPOLYGONINSTANCEGetU1(instPoly), nRecipZ);
    RwIm2DCameraVertexSetV(dv1, cv1, RWPOLYGONINSTANCEGetV1(instPoly), nRecipZ);
#else /* !VU1TRANS */
    dv1->texU = RWPOLYGONINSTANCEGetU1(instPoly);
    dv1->texV = RWPOLYGONINSTANCEGetV1(instPoly);
    dv1->texS = dv1->texU;
    dv1->texT = dv1->texV;
#endif /* !VU1TRANS */
    RwIm2DVertexSetRealRGBA(dv1, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    nRecipZ = RwIm2DVertexGetRecipZ(dv2);
    lightCol = RwCameraVertexGetRGBA(cv2);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv2);
    lightCol->green = RwIm2DVertexGetGreen(dv2);
    lightCol->blue = RwIm2DVertexGetBlue(dv2);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv2);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA2(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
#ifndef VU1TRANS
    RwIm2DCameraVertexSetU(dv2, cv2, RWPOLYGONINSTANCEGetU2(instPoly), nRecipZ);
    RwIm2DCameraVertexSetV(dv2, cv2, RWPOLYGONINSTANCEGetV2(instPoly), nRecipZ);
#else /* !VU1TRANS */
    dv2->texU = RWPOLYGONINSTANCEGetU1(instPoly);
    dv2->texV = RWPOLYGONINSTANCEGetV1(instPoly);
    dv2->texS = dv2->texU;
    dv2->texT = dv2->texV;
#endif /* !VU1TRANS */
    RwIm2DVertexSetRealRGBA(dv2, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    nRecipZ = RwIm2DVertexGetRecipZ(dv3);
    lightCol = RwCameraVertexGetRGBA(cv3);
#else /* !VU1TRANS */
    lightCol->red = RwIm2DVertexGetRed(dv3);
    lightCol->green = RwIm2DVertexGetGreen(dv3);
    lightCol->blue = RwIm2DVertexGetBlue(dv3);
    lightCol->alpha = RwIm2DVertexGetAlpha(dv3);
#endif /* !VU1TRANS */
    vertCol = RWPOLYGONINSTANCEGetRGBA3(instPoly);
    RwRGBARealScale3(&scaledCol, lightCol, (1.0f/255.0f));
#ifndef VU1TRANS
    RwIm2DCameraVertexSetU(dv3, cv3, RWPOLYGONINSTANCEGetU3(instPoly), nRecipZ);
    RwIm2DCameraVertexSetV(dv3, cv3, RWPOLYGONINSTANCEGetV3(instPoly), nRecipZ);
#else /* !VU1TRANS */
    dv3->texU = RWPOLYGONINSTANCEGetU1(instPoly);
    dv3->texV = RWPOLYGONINSTANCEGetV1(instPoly);
    dv3->texS = dv3->texU;
    dv3->texT = dv3->texV;
#endif /* !VU1TRANS */
    RwIm2DVertexSetRealRGBA(dv3, (scaledCol.red * (vertCol->red)),
                                 (scaledCol.green * (vertCol->green)),
                                 (scaledCol.blue * (vertCol->blue)),
                                 (scaledCol.alpha * (vertCol->alpha)));

#ifndef VU1TRANS
    cv1->overLoad = currentFrame;
    cv2->overLoad = currentFrame;
    cv3->overLoad = currentFrame;
#else /* !VU1TRANS */
    dv1->overLoad = currentFrame;
    dv2->overLoad = currentFrame;
    dv3->overLoad = currentFrame;
#endif /* !VU1TRANS */

    PFEXIT(PFSkyCamDevUVColorFromInstPolygon);
    RWRETURNVOID();
}

/****************************************************************************
 SkyPipeSetOverload

 On entry   : flags to set
 On exit    :
 */

static void
SkyPipeSetOverload(RwInt32 type)
{
    RwPipeContext   *thisContext = _rwPipeState.currentContext;

    RWFUNCTION(RWSTRING("SkyPipeSetOverload"));
    PFENTRY(PFSkyPipeSetOverload);

    /* Set up defaults */
    skyOldOverloadFn(type);

    switch (type)
    {
        case (rwPOLYGONSUPPLIESUV):
        case (rwVERTEXSUPPLIESCOLOR | rwPOLYGONSUPPLIESUV):
        {
            thisContext->fpSetOverloadedFieldsInCamAndDevVerts
                                         = SkyCamDevUVFromInstPolygon;
            thisContext->fpSetOverloadedFieldsInDevVerts
                                         = SkyCamDevUVFromInstPolygon;
            break;
        }
        case (rwVERTEXSUPPLIESUV):
        case (rwVERTEXSUPPLIESCOLOR | rwVERTEXSUPPLIESUV):
        {
            thisContext->fpSetNonOverloadedFieldsInCamAndDevVert
                                         = SkyCamDevUVFromInst;
            break;
        }

        case (rwPOLYGONSUPPLIESCOLOR):
        {
            thisContext->fpSetOverloadedFieldsInCamAndDevVerts
                                         = SkyCamDevColorFromInstPolygon;
            thisContext->fpSetOverloadedFieldsInDevVerts
                                         = SkyCamDevColorFromInstPolygon;
            break;
        }

        case (rwPOLYGONSUPPLIESCOLOR | rwPOLYGONSUPPLIESUV):
        {
            thisContext->fpSetOverloadedFieldsInCamAndDevVerts
                                         = SkyCamDevUVColorFromInstPolygon;
            thisContext->fpSetOverloadedFieldsInDevVerts
                                         = SkyCamDevUVColorFromInstPolygon;
            break;
        }
        case (rwPOLYGONSUPPLIESCOLOR | rwVERTEXSUPPLIESUV):
        {
            thisContext->fpSetNonOverloadedFieldsInCamAndDevVert
                                         = SkyCamDevUVFromInst;
            thisContext->fpSetOverloadedFieldsInCamAndDevVerts
                                         = SkyCamDevColorFromInstPolygon;
            thisContext->fpSetOverloadedFieldsInDevVerts
                                         = SkyCamDevColorFromInstPolygon;
            break;
        }

        default:
        {
            /* Do nothing here. Caught in old version */
            break;
        }
    }

    PFEXIT(PFSkyPipeSetOverload);
    RWRETURNVOID();
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                        Replace 2d cull

 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

/****************************************************************************
 SkyCull2DPerspTriangle
 Culls perspective polygon in screen space (if all vertices have been projected,
 eg)

 On entry   : vertices of polygon to cull
 On exit    : status culling either rwNOTCULLEDNOTDRAWN or rwCULLED
 */

static RwTriangleCullState
SkyCull2DPerspTriangle(RwInt32 vert1, RwInt32 vert2, RwInt32 vert3)
{
    /* Perspective back face cull it before we expend energy on the rendering */
    RwIm2DVertex    *vertex1 = RwIm2DVertexGet(vert1);
    RwIm2DVertex    *vertex2 = RwIm2DVertexGet(vert2);
    RwIm2DVertex    *vertex3 = RwIm2DVertexGet(vert3);
    long temp1, temp2, temp3, temp4, temp5, temp6;
    RWFUNCTION(RWSTRING("SkyCull2DPerspTriangle"));
    PFENTRY(PFSkyCull2DPerspTriangle);

#ifdef VU1TRANS
    if (*((RwUInt8*)(vertex1)+11) != 0xff)
    {
        PFEXIT(PFSkyCull2DPerspTriangle);
        RWRETURN(rwNOTCULLEDNOTDRAWN);
    }
#endif /* VU1TRANS */

    __asm__ volatile ("
.include \"baequate.i\"
                       lhu %0, im2dvertex_screen(%6)     # Load vertex1.x
                       lhu %2, im2dvertex_screen(%7)     # Load vertex2.x
                       lhu %3, im2dvertex_screen+2(%7)   # Load vertex2.y
                       lhu %5, im2dvertex_screen+2(%8)   # Load vertex3.y
                       lhu %4, im2dvertex_screen(%8)     # Load vertex3.x
                       lhu %1, im2dvertex_screen+2(%6)   # Load vertex1.y

                       dsub %0, %0, %2        # %0 = vertex1.x - vertex2.x
                       dsub %5, %5, %3        # %5 = vertex3.y - vertex2.y

                       mult %0, %5

                       dsub %1, %1, %3        # %1 = vertex1.y - vertex2.y
                       dsub %4, %4, %2        # %4 = vertex3.x - vertex2.x

                       mflo %0
                       mfhi %5

                       mult1 %1, %4

                       dsll32 %0, %0, 0
                       dsll32 %5, %5, 0
                       dsrl32 %0, %0, 0
                       or %0, %0, %5          # %0 = (vertex1.x - vertex2.x) *
                                              #      (vertex3.y - vertex2.y);

                       mflo1 %1
                       mfhi1 %4

                       dsll32 %1, %1, 0
                       dsll32 %4, %4, 0
                       dsrl32 %1, %1, 0
                       or %1, %1, %4          # %1 = (vertex1.y - vertex2.y) *
                                              #      (vertex3.x - vertex2.x);

                       dsub %0, %0, %1
                      ": "=r&" (temp1),
                         "=r&" (temp2),
                         "=r&" (temp3),
                         "=r&" (temp4),
                         "=r&" (temp5),
                         "=r&" (temp6)
                       : "r" (vertex1),
                         "r" (vertex2),
                         "r" (vertex3)
                       : "cc", "memory");
    if (temp1 > 0)
    {
        /* Not back facing */
        PFEXIT(PFSkyCull2DPerspTriangle);
        RWRETURN(rwNOTCULLEDNOTDRAWN);
    }

    /* Culled it */
    PFEXIT(PFSkyCull2DPerspTriangle);
    RWRETURN(rwCULLED);
}

/****************************************************************************
 SkySetClipAndCull

 On entry   : Camer type
 On exit    :
 */
static void
SkySetClipAndCull(RwCameraProjection camType)
{
    RWFUNCTION(RWSTRING("SkySetClipAndCull"));
    PFENTRY(PFSkySetClipAndCull);

    switch (camType)
    {
        case rwPARALLEL:
        {
            skyOldSetClipCull(camType);
            break;
        }
        default:
            /* Should never happen, but do the perspective thing if it does */
        case (rwPERSPECTIVE):
        {
            skyOldSetClipCull(camType);
            _rwPipeState.fpCull2DTriangle = SkyCull2DPerspTriangle;
            break;
        }
    }
    PFEXIT(PFSkySetClipAndCull);
    RWRETURNVOID();
}

/****************************************************************************
 _rwSkyInstallNewPipeOverloads

 On entry   : None
 On exit    : None
 */

void
_rwSkyInstallNewPipeOverloads(void)
{
    RWFUNCTION(RWSTRING("_rwSkyInstallNewPipeOverloads"));

    if (!skyOldSetClipCull)
    {
        skyOldSetClipCull = _rwPipeState.fpPipeSetClipAndCull;
        _rwPipeState.fpPipeSetClipAndCull = SkySetClipAndCull;
        skyOldOverloadFn = _rwPipeState.fpSetPipeOverloads;
        _rwPipeState.fpSetPipeOverloads = SkyPipeSetOverload;
    }

    RWRETURNVOID();
}

/****************************************************************************
 _rwSkyRemoveNewPipeOverloads

 On entry   : None
 On exit    : None
 */
void
_rwSkyRemoveNewPipeOverloads(void)
{
    RWFUNCTION(RWSTRING("_rwSkyRemoveNewPipeOverloads"));

    if (skyOldSetClipCull)
    {
        _rwPipeState.fpPipeSetClipAndCull = skyOldSetClipCull;
        skyOldSetClipCull = NULL;
        _rwPipeState.fpSetPipeOverloads = skyOldOverloadFn;
        skyOldOverloadFn = NULL;
    }

    RWRETURNVOID();
}

