/***************************************************************************
 *                                                                         *
 * Module  : banull.c                                                      *
 *                                                                         *
 * Purpose : Null driver device layer                                      *
 *                                                                         *
 **************************************************************************/

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

#define BETTERPACK
#define HIDEPALETTE

#if defined (BETTERPACK)
#ifndef HIDEPALETTE
#define HIDEPALETTE
#endif /* !HIDEPALETTE */
#endif /* defined (BETTERPACK) */

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

#include "batypes.h"
#include "badevice.h"
#include "balibtyp.h"
#include "baraster.h"
#include "baimage.h"
#include "batextur.h"
#include "bacamera.h"
#include "baraster.h"
#include "bamemory.h"
#include "barwtyp.h"
#include "baim3d.h"

#include "babinary.h"
#include "babintex.h"
#include "rpcriter.h"

#include "skyconv.h"

#include "baresour.h"
#include "p2core.h"

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

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

/* This files header */

#include "banull.h"

static const char __RWUNUSED__ rcsid[] =
    "@@(#)$Id: banull.c,v 1.21 2001/09/18 12:25:50 Rabin Exp $";

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

#if (!defined(_eetypes_h_))
typedef struct u_long128 u_long128;
struct u_long128
{
    __int64             a, b;
};

#define MAKE128(R, B, A) do { (R).a = (A); (R).b = (B); } while (0)
#endif /* (!defined(_eetypes_h_)) */

#if (!defined(MAKE128))
# if (!defined(__MWERKS__))
/* The following assembler burst let me build a 128 bit from 2x 64 bit */
#   define MAKE128(RES, MSB, LSB) \
    __asm__ volatile ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" (MSB), "r" (LSB))
# else /* (!defined(__MWERKS__)) */
#   define MAKE128(RES, MSB, LSB)                               \
    do                                                          \
    {                                                           \
        unsigned long * const tptr = (unsigned long*)&(RES);    \
                                                                \
        *tptr = (LSB);                                          \
        *(tptr+1) = (MSB);                                      \
    } while (0)
# endif /*  (!defined(__MWERKS__)) */
#endif /* (!defined(MAKE128)) */

typedef RwUInt32    _SkyMemBlock;

typedef struct __rwSkyNativeTexture _rwSkyNativeTexture;
struct __rwSkyNativeTexture
{
    RwUInt8             id[4];  /* Yes, these are RwUInt8s, not RwChars */
    RwInt32             filterAndAddress; /* Same as in babintex.c */
};

typedef struct __rwSkyNativeRaster _rwSkyNativeRaster;
struct __rwSkyNativeRaster
{
    RwInt32             width, height, depth;
    RwUInt16            format;
    RwUInt16            version;
    RwUInt32            lsb, msb;
    RwUInt32            palOffset;
    RwUInt32            maxMipLevel;
    RwUInt32            miptbp1Lsb, miptbp1Msb;
    RwUInt32            miptbp2Lsb, miptbp2Msb;
    RwUInt32            sysMemSize;
    RwUInt32            sysMemPalSize;
    RwUInt32            texCacheSize;
    RwUInt32            mipmapKL; /* Was mipmapK. This should be compatible */
};

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

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

/* This is rather messey, but we need to include the Sony headers somehow */

#define SCE_GS_PSMCT32			0
#define SCE_GS_PSMCT24			1
#define SCE_GS_PSMCT16			2
#define SCE_GS_PSMCT16S			10
#define SCE_GS_PSMT8			19
#define SCE_GS_PSMT4			20
#define SCE_GS_PSMT8H			27
#define SCE_GS_PSMT4HL			36
#define SCE_GS_PSMT4HH			44
#define SCE_GS_PSMZ32			48
#define SCE_GS_PSMZ24			49
#define SCE_GS_PSMZ16			50
#define SCE_GS_PSMZ16S			58

#define PSMCT32     0x00
#define PSMCT24     0x01
#define PSMCT16     0x02
#define PSMCT16S    0x0a
#define PSMT8       0x13
#define PSMT4       0x14
#define PSMT8H      0x1b
#define PSMT4HL     0x24
#define PSMT4HH     0x2c
#define PSMZ32      0x30
#define PSMZ24      0x31
#define PSMZ16      0x32
#define PSMZ16S     0x3a

#define GS_BITBLTBUF    0x50
#define GS_TRXPOS   0x51
#define GS_TRXREG   0x52
#define GS_TRXDIR   0x53

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

RwInt32             skyRasterExt;
RwInt32             skyTextureExt;

/****************************************************************************
 Local (static) Globals
 */
#ifdef ALTTEXFORM
static RwBool       skyNoNewStyleRasters = FALSE;
#endif /* ALTTEXFORM */

static RwVideoMode  videoModes[] = {

    /*
     * These are the PAL modes 50Hz
     *   16 bit color depth
     */
    {256, 256, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {320, 256, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {384, 256, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {512, 256, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {640, 256, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    /*     FSAA0 Supersample */
    {512, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    {640, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    /*      Interlaced */
    {256, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {320, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {384, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {512, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {640, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    /*     Interlaced FSAA1 Dual read-circuit */
    {256, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {320, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {384, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {512, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {640, 512, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    /*      Flicker free */
    {256, 256, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {320, 256, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {384, 256, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {512, 256, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {640, 256, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},

    /*
     * These are the PAL modes 50Hz
     *   32 bit color
     */
    {256, 256, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {320, 256, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {384, 256, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {512, 256, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {640, 256, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    /*     Interlaced FSAA0 Supersample */
    {512, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    {640, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    /*     Interlaced */
    {256, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {320, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {384, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {512, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {640, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    /*     Interlaced FSAA1 Dual read-circuit */
    {256, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {320, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {384, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {512, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {640, 512, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    /*     Flicker free */
    {256, 256, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {320, 256, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {384, 256, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {512, 256, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {640, 256, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},

    /*
     * These are the NTSC modes 60 Hz
     *   16 bit color depth
     */
    {256, 224, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {320, 224, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {384, 224, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {512, 224, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {640, 224, 16, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    /*     Interlaced FSAA0 Supersample */
    {512, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    {640, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    /*     Interlaced */
    {256, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {320, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {384, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {512, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {640, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    /*     Interlaced FSAA1 Dual read-circuit */
    {256, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {320, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {384, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {512, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {640, 448, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    /*     Flicker free */
    {256, 224, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {320, 224, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {384, 224, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {512, 224, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {640, 224, 16,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},

    /*
     * These are the NTSC modes 60 Hz
     *   32 bit color depth
     */
    {256, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {320, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {384, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {512, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    {640, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE)},
    /*     Interlaced FSAA0 Supersample */
    {512, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    {640, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFSAA0)},
    /*     Interlaced */
    {256, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {320, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {384, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {512, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    {640, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE)},
    /*     Interlaced FSAA1 Dual read-circuit */
    {256, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {320, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {384, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {512, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    {640, 448, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEINTERLACE |
                        rwVIDEOMODEFSAA1)},
    /*     Flicker free */
    {256, 224, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {320, 224, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {384, 224, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {512, 224, 32,
     (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)},
    {640, 224, 32, (RwVideoModeFlag) (rwVIDEOMODEEXCLUSIVE | rwVIDEOMODEFFINTERLACE)} /* Default mode */
};

static RwUInt32     zBufferDepth = 16;
static RwInt32      currentMode;
static RwInt32      currentCameraFormat;
static RwUInt32     skyDefaultMipmapKL = 0xfc0;

/* This can be changed by RpSkyRenderStateSet/rwRENDERSTATEMAXMIPLEVELS */
RwInt32             skyMaxMipLevels = 4;

/* The device globals */
RwRwDeviceGlobals   dgGGlobals;


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

                          General hardware stuff

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

/****************************************************************************
 _rwSkyFindMSB

 On entry   : RwUInt32
 On exit    : Bit number of MSB (-1 if 0)
 */

RwInt32
_rwSkyFindMSB(RwUInt32 nInt)
{
    RwInt32             nPos = -1;

    RWFUNCTION(RWSTRING("_rwSkyFindMSB"));

    while (nInt)
    {
        nPos++;
        nInt >>= 1;
    }

    RWRETURN(nPos);
}

static char        *
alignedMalloc(int size)
{
    char               *ptr, *ptr1;

    RWFUNCTION(RWSTRING("alignedMalloc"));

    ptr = RwMalloc(size + 64 + sizeof(ptr));
    ptr1 = (char *) (((int) ptr + sizeof(ptr) + 64) & ~0x3f);

    *(((char **) ptr1) - 1) = ptr;

    RWRETURN(ptr1);
}

static void
alignedFree(char *ptr)
{
    RWFUNCTION(RWSTRING("alignedFree"));
    RWASSERT(ptr);

    RwFree(((char **) ptr)[-1]);

    RWRETURNVOID();

}

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

                          Dummy render functions

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

/****************************************************************************
 NullSkySetRenderState

 On entry   : State
            : pParam
 On exit    :
 */

static              RwBool
NullSkySetRenderState(RwRenderState nState __RWUNUSED__,
                      void *pParam __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkySetRenderState"));
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyGetRenderState

 On entry   : State
            : Param
 On exit    : TRUE
 */

static              RwBool
NullSkyGetRenderState(RwRenderState nState __RWUNUSED__,
                      void *pParam __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyGetRenderState"));
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyIm2DRenderLine

 On entry   : verts
 On exit    :
 */

static              RwBool
NullSkyIm2DRenderLine(RwIm2DVertex * verts __RWUNUSED__,
                      RwInt32 numVerts __RWUNUSED__,
                      RwInt32 v1 __RWUNUSED__, RwInt32 v2 __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyIm2DRenderLine"));

#ifdef etimap1000
    /* Cheesy and hacky for now, but the libs get so big with RWDEBUG and MAP that it fails to link! */
    rwprintf(RWSTRING("Draw line from %d,%d to %d,%d\n"),
             (RwInt32) (verts[v1].screen.x),
             (RwInt32) (verts[v1].screen.y),
             (RwInt32) (verts[v2].screen.x),
             (RwInt32) (verts[v2].screen.y));
#endif /* etimap1000 */

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyIm2DRenderTriangle

 On entry   : verts
 On exit    :
 */

static              RwBool
NullSkyIm2DRenderTriangle(RwIm2DVertex * verts __RWUNUSED__,
                          RwInt32 numVerts __RWUNUSED__,
                          RwInt32 v1 __RWUNUSED__,
                          RwInt32 v2 __RWUNUSED__,
                          RwInt32 v3 __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyIm2DRenderTriangle"));

#ifdef etimap1000
    /* Cheesy and hacky for now, but the libs get so big with RWDEBUG and MAP that it fails to link! */
    rwprintf(RWSTRING("Draw triangle from %d,%d to %d,%d to %d,%d\n"),
             (RwInt32) (verts[v1].screen.x),
             (RwInt32) (verts[v1].screen.y),
             (RwInt32) (verts[v2].screen.x),
             (RwInt32) (verts[v2].screen.y),
             (RwInt32) (verts[v3].screen.x),
             (RwInt32) (verts[v3].screen.y));
#endif /* etimap1000 */

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyIm2DRenderPrimitive

 On entry   : verts, indices
 On exit    :
 */

static              RwBool
NullSkyIm2DRenderPrimitive(RwPrimitiveType nPrimType,
                           RwIm2DVertex * tvpVert, RwInt32 nNumVertices)
{
    RwInt32             index;
    RwInt32             nNumIndices = nNumVertices;

    RWFUNCTION(RWSTRING("NullSkyIm2DRenderPrimitive"));

    switch (nPrimType)
    {
        case rwPRIMTYPELINELIST:
            {
                index = 0;
                while (nNumIndices > 1)
                {
                    NullSkyIm2DRenderLine(tvpVert, nNumVertices, index,
                                          index + 1);

                    index += 2;
                    nNumIndices -= 2;
                }

                break;
            }
        case rwPRIMTYPEPOLYLINE:
            {
                index = 0;
                while (nNumIndices > 1)
                {
                    NullSkyIm2DRenderLine(tvpVert, nNumVertices, index,
                                          index + 1);

                    index++;
                    nNumIndices--;
                }

                break;
            }
        case rwPRIMTYPETRILIST:
            {
                index = 0;
                while (nNumIndices > 2)
                {
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices,
                                              index, index + 1,
                                              index + 2);

                    index += 3;
                    nNumIndices -= 3;
                }

                break;
            }
        case rwPRIMTYPETRISTRIP:
            {
                RwInt32             vertInd = 1;

                index = 0;
                while (nNumIndices > 2)
                {
                    /* Dispatch a polygon */
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices,
                                              index, index + vertInd,
                                              index + (vertInd ^ 3));

                    /* Flip the backface test for next time!! This turns 2=>1 and 1=>2 */
                    vertInd ^= 3;

                    /* Next triple of vertices */
                    index++;
                    nNumIndices--;
                }

                break;
            }
        case rwPRIMTYPETRIFAN:
            {
                index = 1;
                while (nNumIndices > 2)
                {
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices, 0,
                                              index, index + 1);

                    index++;
                    nNumIndices--;
                }

                break;
            }
        default:
            {
                break;
            }
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyIm2DRenderIndexedPrimitive

 On entry   : verts, indices
 On exit    :
 */

static              RwBool
NullSkyIm2DRenderIndexedPrimitive(RwPrimitiveType nPrimType,
                                  RwIm2DVertex * tvpVert,
                                  RwInt32 nNumVertices,
                                  RwImVertexIndex * indices,
                                  RwInt32 nNumIndices)
{
    RWFUNCTION(RWSTRING("NullSkyIm2DRenderIndexedPrimitive"));

    switch (nPrimType)
    {
        case rwPRIMTYPELINELIST:
            {
                while (nNumIndices > 1)
                {
                    NullSkyIm2DRenderLine(tvpVert, nNumVertices,
                                          indices[0], indices[1]);

                    indices += 2;
                    nNumIndices -= 2;
                }

                break;
            }
        case rwPRIMTYPEPOLYLINE:
            {
                while (nNumIndices > 1)
                {
                    NullSkyIm2DRenderLine(tvpVert, nNumVertices,
                                          indices[0], indices[1]);

                    indices++;
                    nNumIndices--;
                }

                break;
            }
        case rwPRIMTYPETRILIST:
            {
                while (nNumIndices > 2)
                {
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices,
                                              indices[0], indices[1],
                                              indices[2]);

                    indices += 3;
                    nNumIndices -= 3;
                }

                break;
            }
        case rwPRIMTYPETRISTRIP:
            {
                RwInt32             vertInd = 1;

                nNumIndices -= 2;
                while (nNumIndices > 0)
                {
                    /* Dispatch a polygon */
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices,
                                              indices[0],
                                              indices[vertInd],
                                              indices[vertInd ^ 3]);

                    /* Flip the backface test for next time!! This turns 2=>1 and 1=>2 */
                    vertInd ^= 3;

                    /* Next triple of vertices */
                    indices++;
                    nNumIndices--;
                }

                break;
            }
        case rwPRIMTYPETRIFAN:
            {
                RwInt32             startVert = indices[0];

                nNumIndices -= 2;

                indices++;

                while (nNumIndices > 0)
                {
                    NullSkyIm2DRenderTriangle(tvpVert, nNumVertices,
                                              startVert, indices[0],
                                              indices[1]);

                    indices++;
                    nNumIndices--;
                }

                break;
            }
        default:
            {
                break;
            }
    }

    RWRETURN(TRUE);
}

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

                        Standard functions

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

/**
 * \ingroup nullsky
 * \ref RpSkyRenderStateSet
 * is used to set device specific renderstate
 * for which there is, as yet, no generic equavalent.
 *
 * \param nState The state to set:
 * \li rpSKYRENDERSTATEMAXMIPLEVELS - Specifies the maximum number of mip
 * levels that rasters will be created with. Changing this value does not
 * affect existing rasters. Mip levels will only be created if they are
 * greater than or equal to 8 texels in both dimensions, so you are not
 * guaranteed to get the maximum number of mip levels for all rasters.
 * The maximum allowed value for rpSKYRENDERSTATEMAXMIPLEVELS is 7.
 *
 * \param pParam A state specific argument, cast to be a void*
 *
 * \return Returns TRUE if successful or FALSE if there is an error.
 *
 * \see RpSkyRenderStateGet
 */
RwBool
RpSkyRenderStateSet(RpSkyRenderState nState, void *pParam)
{
    RWAPIFUNCTION(RWSTRING("RpSkyRenderStateSet"));

    switch (nState)
    {
        case rpSKYRENDERSTATEMAXMIPLEVELS:
            {
                /* Levels in a raster go from 0 to n-1.
                 * Levels are only created if >= 8x8 texels.
                 * NumLevels is stored in rasterExtension->maxMipLevel
                 * (numlevels is: (rasExt->maxMipLevel >> 2) + 1) */
                RwInt32             maxMipLevels;

                /* Must remain (> 0) and (<= 7) */
                maxMipLevels = *((RwInt32 *) (pParam));
                if ((maxMipLevels > 0) && (maxMipLevels <= 7))
                {
                    skyMaxMipLevels = maxMipLevels;
                }
                else
                {
                    RWASSERT(maxMipLevels > 0);
                    RWASSERT(maxMipLevels <= 7);
                    RWRETURN(FALSE);
                }
            }
            break;

        default:
            {
                RWRETURN(FALSE);
            }
    }
    RWRETURN(TRUE);
}

/**
 * \ingroup nullsky
 * \ref RpSkyRenderStateGet
 *  is used to get device specific renderstate
 * for which there is, as yet, no generic equavalent.  Because in many cases
 * setting these values changes the default behaviour of RenderWare it is
 * recommended that you contact rw3-support to discuss any implications
 * that might arise from their use.
 *
 * \param nState The state to get:
 * \li rpSKYRENDERSTATEMAXMIPLEVELS - Retreives the maximum number of mip
 * levels that rasters will be created with. Mip levels are only be created
 * if they are greater than or equal to 8 texels in both dimensions, so you
 * are not guaranteed to get the maximum number of mip levels for all rasters.
 *
 * \param pParam A state specific argument, cast to be a void*
 *
 * \return Returns TRUE if successful or FALSE if there is an error.
 *
 * \see RpSkyRenderStateSet
 */
RwBool
RpSkyRenderStateGet(RpSkyRenderState nState, void *pParam)
{
    RWAPIFUNCTION(RWSTRING("RpSkyRenderStateGet"));

    switch (nState)
    {
        case rpSKYRENDERSTATEMAXMIPLEVELS:
            {
                *(RwInt32 *) pParam = skyMaxMipLevels;
                break;
            }
        default:
            {
                RWRETURN(FALSE);
            }
    }
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyCameraBeginUpdate

 On entry   : NULL
            : camera pointer (IN)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyCameraBeginUpdate(void *pOut __RWUNUSED__,
                         void *pCam __RWUNUSED__,
                         RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyCameraBeginUpdate"));

    /* Let's pretend we can do this - we never render anything anyway */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyCameraEndUpdate

 On entry   : NULL
            : camera pointer (IN)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyCameraEndUpdate(void *pOut __RWUNUSED__,
                       void *pCam __RWUNUSED__,
                       RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyCameraEndUpdate"));

    /* Let's pretend we can do this - we never render anything anyway */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyCameraClear

 On entry   : camera pointer (IN)
            : pointer to RwRGBA giving frame buffer color
            : bit field indicating what to clear (rwCAMERACLEARIMAGE,
                                                  rwCAMERACLEARZ)
 On exit    : TRUE on success
 */
static              RwBool
NullSkyCameraClear(void *pCam __RWUNUSED__,
                   void *pCol __RWUNUSED__,
                   RwInt32 nClearWhich __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyCameraClear"));

    /* Let's pretend we can do this - we never render anything anyway */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterShowRaster

 On entry   : raster pointer (IN)
            : device specific pointer (IN) - HWND for windows, eg
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterShowRaster(void *pRas __RWUNUSED__,
                        void *pDev __RWUNUSED__,
                        RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterShowRaster"));

    /* Let's pretend we can do this - we never render anthing anyway */
    RWRETURN(TRUE);
}

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

                         Texture access

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

/**
 * \ingroup nullsky
 * \ref RpSkyTextureSetDefaultMipmapK
 * 
 *  On entry   : val
 *  On exit    : Value actually set
 */
RwReal
RpSkyTextureSetDefaultMipmapK(RwReal val)
{
    RwInt32             i;

    RWAPIFUNCTION(RWSTRING("RpSkyTextureSetDefaultMipmapK"));

    i = (RwInt32) (val * 16.0f);
    if (i < -2048)
    {
        i = -2048;
    }
    else if (i > 2047)
    {
        i = 2047;
    }
    skyDefaultMipmapKL &= ~0xfff;
    skyDefaultMipmapKL |= (RwUInt32) i & 0xfff;
    RWRETURN((RwReal) i * 0.0625f);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureSetDefaultMipmapL
 * 
 *  On entry   : val
 *  On exit    : TRUE on success
 */
RwUInt32
RpSkyTextureSetDefaultMipmapL(RwUInt32 val)
{
    RWAPIFUNCTION(RWSTRING("RpSkyTextureSetDefaultMipmapL"));

    if (val > 3)
    {
        val = 3;
    }
    skyDefaultMipmapKL &= ~(0x03<<12);
    skyDefaultMipmapKL |= (val << 12);
    RWRETURN(val);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureGetDefaultMipmapK
 * 
 *  On entry   :
 *  On exit    : K
 */
RwReal
RpSkyTextureGetDefaultMipmapK(void)
{
    RwInt32             i;

    RWAPIFUNCTION(RWSTRING("RpSkyTextureGetDefaultMipmapK"));

    i = skyDefaultMipmapKL & 0xfff;
    if (i & 0x800)
    {
        i |= ~0xfff;
    }
    RWRETURN((RwReal) i * 0.0625f);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureGetDefaultMipmapL
 * 
 *  On entry   :
 *  On exit    : L
 */
RwUInt32
RpSkyTextureGetDefaultMipmapL(void)
{
    RwUInt32            i;

    RWAPIFUNCTION(RWSTRING("RpSkyTextureGetDefaultMipmapL"));

    i = (skyDefaultMipmapKL & 0x3000) >> 12;
    RWRETURN(i);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureSetMipmapK
 * 
 *  On entry   : tex
 *  On exit    : TRUE on success
 */
RwTexture          *
RpSkyTextureSetMipmapK(RwTexture * tex, RwReal val)
{
    RwInt32             i;

    RWAPIFUNCTION(RWSTRING("RpSkyTextureSetMipmapK"));

    if ((tex) && (tex->raster))
    {
        i = (RwInt32) (val * 16.0f);
        if (i < -2048)
        {
            i = -2048;
        }
        else if (i > 2047)
        {
            i = 2047;
        }
        RASTEREXTFROMRASTER(tex->raster)->mipmapKL &= ~0xfff;
        RASTEREXTFROMRASTER(tex->raster)->mipmapKL |=
            (RwUInt16) i & 0xfff;
        RWRETURN(tex);
    }
    RWRETURN((RwTexture *) NULL);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureSetMipmapL
 * 
 *  On entry   : tex
 *  On exit    : TRUE on success
 */
RwTexture          *
RpSkyTextureSetMipmapL(RwTexture * tex, RwUInt32 val)
{
    RWAPIFUNCTION(RWSTRING("RpSkyTextureSetMipmapL"));

    if ((tex) && (tex->raster))
    {
        if (val > 3)
        {
            val = 3;
        }
        RASTEREXTFROMRASTER(tex->raster)->mipmapKL &= ~0x3000;
        RASTEREXTFROMRASTER(tex->raster)->mipmapKL |=
            (RwUInt16) val << 12;
        RWRETURN(tex);
    }
    RWRETURN((RwTexture *) NULL);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureGetMipmapK
 * 
 *  On entry   : tex
 *  On exit    : K
 */
RwReal
RpSkyTextureGetMipmapK(RwTexture * tex)
{
    RWAPIFUNCTION(RWSTRING("RpSkyTextureGetMipmapK"));
    if ((tex) && (tex->raster))
    {
        RwInt32             i;

        i = RASTEREXTFROMRASTER(tex->raster)->mipmapKL & 0xfff;
        if (i & 0x800)
        {
            i |= ~0xfff;
        }
        RWRETURN((RwReal) i * 0.0625f);
    }
    RWRETURN((RwReal) 0.0f);
}

/**
 * \ingroup nullsky
 * \ref RpSkyTextureGetMipmapL
 * 
 *  On entry   : tex
 *  On exit    : L
 */
RwUInt32
RpSkyTextureGetMipmapL(RwTexture * tex)
{
    RWAPIFUNCTION(RWSTRING("RpSkyTextureGetMipmapL"));
    if ((tex) && (tex->raster))
    {
        RwUInt32            i;

        i = (RASTEREXTFROMRASTER(tex->raster)->mipmapKL & 0x3000) >> 12;
        RWRETURN(i);
    }
    RWRETURN(0);
}

/**
 * \ingroup nullsky
 * \ref  skyReadTexCB
 * 
 *  On entry   :
 *  On exit    :
 */
static RwStream    *
skyReadTexCB(RwStream * stream, RwInt32 len, void *obj,
             RwInt32 __RWUNUSED__ off, RwInt32 __RWUNUSED__ sizeInObj)
{
    RwTexture          *tex = (RwTexture *) obj;
    RwInt32             val;

    RWFUNCTION(RWSTRING("skyReadTexCB"));

    if ((len == 4) && (tex) && (tex->raster))
    {
        if (RwStreamReadInt(stream, &val, sizeof(RwInt32)))
        {
            RASTEREXTFROMRASTER(tex->raster)->mipmapKL = (RwUInt16) val;
            RWRETURN(stream);
        }
        RWRETURN((RwStream *) NULL);
    }
    RWRETURN((RwStream *) NULL);
}

/****************************************************************************
 skyWriteTexCB

 On entry   :
 On exit    :
 */
static RwStream    *
skyWriteTexCB(RwStream * stream, RwInt32 __RWUNUSED__ len,
              const void *obj, RwInt32 __RWUNUSED__ off,
              RwInt32 __RWUNUSED__ sizeInObj)
{
    const RwTexture    *tex = (const RwTexture *) obj;
    RwInt32             val;

    RWFUNCTION(RWSTRING("skyWriteTexCB"));

    if ((tex) && (tex->raster))
    {
        val = (RwInt32) (RASTEREXTFROMRASTER(tex->raster)->mipmapKL);
        if (RwStreamWriteInt(stream, &val, sizeof(RwInt32)))
        {
            RWRETURN(stream);
        }
        RWRETURN((RwStream *) NULL);
    }
    RWRETURN((RwStream *) NULL);
}

/****************************************************************************
 skyGetSizeTexCB

 On entry   :
 On exit    : 4
 */
static              RwInt32
skyGetSizeTexCB(const void *__RWUNUSED__ obj, RwInt32 __RWUNUSED__ off,
                RwInt32 __RWUNUSED__ size)
{
    RWFUNCTION(RWSTRING("skyGetSizeTexCB"));
    RWRETURN(4);
}

/****************************************************************************
 SkyTextureSetRaster

 On entry   : Texture
            : Raster
            : 0
 On exit    : TRUE on success
 */
static              RwBool
SkyTextureSetRaster(void *pTex, void *pRas, RwInt32 __RWUNUSED__ nIn)
{
    RwTexture          *tex = (RwTexture *) pTex;
    RwRaster           *rpRas = (RwRaster *) pRas;

    RWFUNCTION(RWSTRING("SkyTextureSetRaster"));

    /* Try and set the raster */
    tex->raster = rpRas;

    /* All done */
    RWRETURN(TRUE);
}

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

                      Finding the appropriate format

 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/****************************************************************************
 SkyGetRasterFormat

 On entry   :
            : Raster
            : Flags
 On exit    :
 */
static              RwBool
SkyGetRasterFormat(void *__RWUNUSED__ pInOut, void *pRaster,
                   RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwInt32             nFormat =
        flags & (RwInt32) rwRASTERFORMATPIXELFORMATMASK;
    RwInt32             mipmapFlag =
        flags & (RwInt32) (rwRASTERFORMATMIPMAP |
                           rwRASTERFORMATAUTOMIPMAP);
    RwInt32             palette =
        flags & (RwInt32) (rwRASTERFORMATPAL4 | rwRASTERFORMATPAL8);

    RWFUNCTION(RWSTRING("SkyGetRasterFormat"));

    /* Copy over types */
    rpRas->cType = (RwUInt8) (flags & (RwInt32) rwRASTERTYPEMASK);
    rpRas->cFlags = (RwUInt8) (flags & (RwInt32) (~rwRASTERTYPEMASK));

    switch (rpRas->cType)
    {
        case rwRASTERTYPENORMAL:
        case rwRASTERTYPECAMERATEXTURE:
            {
                /* No palettised or mipmap rasters */
                if (palette || mipmapFlag)
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }

                /* Drop through to next case */
            }
        case rwRASTERTYPETEXTURE:
            {
                /* By default textures are 1555 for 16 bit, 8 bit palettised for 8
                 * bit or 8888 for 32 bit.
                 * Stupid depths for palettised textures get rejected later.
                 */
                if (nFormat == (RwInt32) rwRASTERFORMATDEFAULT)
                {
                    switch (rpRas->depth)
                    {
                        case (4):
                            nFormat =
                                (RwInt32) (rwRASTERFORMATPAL4 |
                                           rwRASTERFORMAT1555);
                            break;

                        case (8):
                            nFormat =
                                (RwInt32) (rwRASTERFORMATPAL8 |
                                           rwRASTERFORMAT1555);
                            break;

                        case (24):
                            nFormat = (RwInt32) rwRASTERFORMAT888;
                            break;

                        case (32):
                            nFormat = (RwInt32) rwRASTERFORMAT8888;
                            break;

                        case (16):
                        default:
                            nFormat = (RwInt32) rwRASTERFORMAT1555;
                            break;
                    }
                }

                /* Don't forget the mipmap flag */
                rpRas->cFormat = ((RwUInt8) ((nFormat |
                                              mipmapFlag |
                                              palette) >> 8));

                /* Make sure the depth is good */
                switch (palette)
                {
                    case (0):
                        {
                            switch (nFormat)
                            {
                                case (rwRASTERFORMAT1555):
                                    if ((rpRas->depth != 0)
                                        && (rpRas->depth != 16))
                                    {
                                        RWERROR((E_RW_INVRASTERDEPTH));
                                        RWRETURN(FALSE);
                                    }
                                    rpRas->depth = 16;
                                    break;

                                case (rwRASTERFORMAT888):
                                    if ((rpRas->depth != 0)
                                        && (rpRas->depth != 24))
                                    {
                                        RWERROR((E_RW_INVRASTERDEPTH));
                                        RWRETURN(FALSE);
                                    }
                                    rpRas->depth = 24;
                                    break;

                                case (rwRASTERFORMAT8888):
                                    if ((rpRas->depth != 0)
                                        && (rpRas->depth != 32))
                                    {
                                        RWERROR((E_RW_INVRASTERDEPTH));
                                        RWRETURN(FALSE);
                                    }
                                    rpRas->depth = 32;
                                    break;

                                default:
                                    /* Unsupported raster format */
                                    RWERROR((E_RW_INVRASTERFORMAT));
                                    RWRETURN(FALSE);
                            }
                            break;
                        }
                    case (rwRASTERFORMATPAL4):
                        {
                            if ((rpRas->depth != 0)
                                && (rpRas->depth != 4))
                            {
                                RWERROR((E_RW_INVRASTERDEPTH));
                                RWRETURN(FALSE);
                            }
                            rpRas->depth = 4;

                            /* Reject stupid CLUT formats */
                            switch (nFormat)
                            {
                                case (rwRASTERFORMAT1555):
                                case (rwRASTERFORMAT8888):
                                    /* These formats are cool. */
                                    break;

                                default:
                                    /* Can't use this format with palettised rasters */
                                    RWERROR((E_RW_INVRASTERFORMAT));
                                    RWRETURN(FALSE);
                            }
                            break;
                        }
                    case (rwRASTERFORMATPAL8):
                        {
                            if ((rpRas->depth != 0)
                                && (rpRas->depth != 8))
                            {
                                RWERROR((E_RW_INVRASTERDEPTH));
                                RWRETURN(FALSE);
                            }
                            rpRas->depth = 8;

                            /* Reject stupid CLUT formats */
                            switch (nFormat)
                            {
                                case (rwRASTERFORMAT1555):
                                case (rwRASTERFORMAT8888):
                                    /* These formats are cool. */
                                    break;

                                default:
                                    /* Can't use this format with palettised rasters */
                                    RWERROR((E_RW_INVRASTERFORMAT));
                                    RWRETURN(FALSE);
                            }
                            break;
                        }
                    default:
                        {
                            /* Can't do this - palettised 4 and 8 at the same time? */
                            RWERROR((E_RW_INVRASTERFORMAT));
                            RWRETURN(FALSE);
                        }
                }

                break;
            }
        case rwRASTERTYPECAMERA:
            {
                /* No mipmaps or palettised rasters here */
                if (mipmapFlag || palette)
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }

                /* 1555 or 8888 depending on camera depth */
                if ((rpRas->depth != 0) &&
                    (rpRas->depth != videoModes[currentMode].depth))
                {
                    RWERROR((E_RW_INVRASTERDEPTH));
                    RWRETURN(FALSE);
                }
                rpRas->depth = videoModes[currentMode].depth;

                if ((nFormat != (RwInt32) rwRASTERFORMATDEFAULT) &&
                    (nFormat != currentCameraFormat))
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }
                nFormat = currentCameraFormat;

                rpRas->cFormat = (RwUInt8) (nFormat >> 8);

                break;
            }
        case rwRASTERTYPEZBUFFER:
            {
                /* No mipmaps or palettised rasters here */
                if (mipmapFlag || palette)
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }

                /* zBufferDepth bit Z buffers */
                if ((rpRas->depth != 0) &&
                    (rpRas->depth != (RwInt32) zBufferDepth))
                {
                    RWERROR((E_RW_INVRASTERDEPTH));
                    RWRETURN(FALSE);
                }
                rpRas->depth = zBufferDepth;

                /* By default, Z buffers are 16 bit */
                if ((nFormat != (RwInt32) rwRASTERFORMATDEFAULT) &&
                    (nFormat !=
                     (RwInt32) (zBufferDepth ==
                                16 ? rwRASTERFORMAT16 :
                                rwRASTERFORMAT32)))
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }
                nFormat =
                    (RwInt32) (zBufferDepth ==
                               16 ? rwRASTERFORMAT16 :
                               rwRASTERFORMAT32);

                rpRas->cFormat = (RwUInt8) (nFormat >> 8);

                break;
            }
        default:
            {
                RWRETURN(FALSE);
            }
    }

    RWRETURN(TRUE);
}

#ifdef BETTERPACK
/************************************************************************
 * This code is included from work in progress. Eventually mipmapped    *
 * textures will be uploaded in one shot, but for now the more efficient*
 * packing code is inserted into the original version to save VRAM.     *
 *                                                                      *
 * This code will only work correctly for the sizes used at present.    *
 * If you wish to change things you will probably need to rework the    *
 * palette hiding logic (In fact, maxlevels 7, min w,h 8 also work)     *
 ************************************************************************/

/*
 * Macros to take a linear address and turn it into a block in a physical
 * address.
 */

/* 32 -> 0->0 1->2 2->4 3->1 4->3 */
#define PSMCT32BlockToAddress(B)        \
    (((B)&~0x1f)                        \
    |(((B) & 0x1) << 0)                 \
    |(((B) & 0x2) << 1)                 \
    |(((B) & 0x4) << 2)                 \
    |(((B) & 0x8) >> 2)                 \
    |(((B) & 0x10)>> 1))

/* 32Z -> 32 ^ 0x18 */
#define PSMZ32BlockToAddress(B)         \
    (PSMCT32BlockToAddress(B) ^ 0x18)

/* 16 -> 0->1 1->3 2->0 3->2 4->4 */
#define PSMCT16BlockToAddress(B)        \
    (((B)&~0x1f)                        \
    |(((B) & 0x1) << 1)                 \
    |(((B) & 0x2) << 2)                 \
    |(((B) & 0x4) >> 2)                 \
    |(((B) & 0x8) >> 1)                 \
    |(((B) & 0x10)<< 0))

/* 16Z -> 16 ^ 0x18 */
#define PSMZ16BlockToAddress(B)         \
    (PSMCT16BlockToAddress(B) ^ 0x18)

/* 16S -> 0->1 1->4 2->0 3->3 4->2 */
#define PSMCT16SBlockToAddress(B)       \
    (((B)&~0x1f)                        \
    |(((B) & 0x1) << 1)                 \
    |(((B) & 0x2) << 3)                 \
    |(((B) & 0x4) >> 2)                 \
    |(((B) & 0x8) << 0)                 \
    |(((B) &0x10) >> 2))

/* 16ZZ -> 16S ^ 0x18 */
#define PSMZ16SBlockToAddress(B)        \
    (PSMCT16SBlockToAddress(B) ^ 0x18)

/* 8 -> 0->0 1->2 2->4 3->1 4->3 */
#define PSMT8BlockToAddress(B)          \
    (((B)&~0x1f)                        \
    |(((B) & 0x1) << 0)                 \
    |(((B) & 0x2) << 1)                 \
    |(((B) & 0x4) << 2)                 \
    |(((B) & 0x8) >> 2)                 \
    |(((B) &0x10) >> 1))

/* 4 -> 0->1 1->3 2->0 3->2 4->4 */
#define PSMT4BlockToAddress(B)          \
    (((B)&~0x1f)                        \
    |(((B) & 0x1) << 1)                 \
    |(((B) & 0x2) << 2)                 \
    |(((B) & 0x4) >> 2)                 \
    |(((B) & 0x8) >> 1)                 \
    |(((B) &0x10) << 0))

/* 32 -> 0->0 1->3 2->1 3->4 4->2 */
#define PSMCT32AddressToBlock(A)        \
    (((A)&~0x1f)                        \
    |(((A) & 0x1) << 0)                 \
    |(((A) & 0x2) << 2)                 \
    |(((A) & 0x4) >> 1)                 \
    |(((A) & 0x8) << 1)                 \
    |(((A) & 0x10)>> 2))

/* 16 -> 0->2 1->0 2->3 3->1 4->4 */
#define PSMCT16AddressToBlock(A)        \
    (((A)&~0x1f)                        \
    |(((A) & 0x1) << 2)                 \
    |(((A) & 0x2) >> 1)                 \
    |(((A) & 0x4) << 1)                 \
    |(((A) & 0x8) >> 2)                 \
    |(((A) &0x10) << 0))

/* 8 -> 0->0 1->3 2->1 3->4 4->2 */
#define PSMT8AddressToBlock(A)          \
    (((A)&~0x1f)                        \
    |(((A) & 0x1) << 0)                 \
    |(((A) & 0x2) << 2)                 \
    |(((A) & 0x4) >> 1)                 \
    |(((A) & 0x8) << 1)                 \
    |(((A) &0x10) >> 2))

/* 4 -> 0->2 1->0 2->3 3->1 4->4 */
#define PSMT4AddressToBlock(A)          \
    (((A)&~0x1f)                        \
    |(((A) & 0x1) << 2)                 \
    |(((A) & 0x2) >> 1)                 \
    |(((A) & 0x4) << 1)                 \
    |(((A) & 0x8) >> 2)                 \
    |(((A) &0x10) << 0))

#define GSBlockToAddress(__result, B, FORMAT)           \
MACRO_START                                             \
{                                                       \
    switch (FORMAT)                                     \
    {                                                   \
        case SCE_GS_PSMCT32:                            \
        case SCE_GS_PSMCT24:                            \
        case SCE_GS_PSMT8H:                             \
        case SCE_GS_PSMT4HL:                            \
        case SCE_GS_PSMT4HH:                            \
        {                                               \
            __result = PSMCT32BlockToAddress((B));      \
            break;                                      \
        }                                               \
        case SCE_GS_PSMCT16:                            \
        {                                               \
            __result = PSMCT16BlockToAddress((B));      \
            break;                                      \
        }                                               \
        case SCE_GS_PSMCT16S:                           \
        {                                               \
            __result = PSMCT16SBlockToAddress((B));     \
            break;                                      \
        }                                               \
        case SCE_GS_PSMT8:                              \
        {                                               \
            __result = PSMT8BlockToAddress((B));        \
            break;                                      \
        }                                               \
        case SCE_GS_PSMT4:                              \
        {                                               \
            __result = PSMT4BlockToAddress((B));        \
            break;                                      \
        }                                               \
        case SCE_GS_PSMZ32:                             \
        case SCE_GS_PSMZ24:                             \
        {                                               \
            __result = PSMZ32BlockToAddress((B));       \
            break;                                      \
        }                                               \
        case SCE_GS_PSMZ16:                             \
        {                                               \
            __result = PSMZ16BlockToAddress((B));       \
            break;                                      \
        }                                               \
        case SCE_GS_PSMZ16S:                            \
        {                                               \
            __result = PSMZ16SBlockToAddress((B));      \
            break;                                      \
        }                                               \
        default:                                        \
	    __result = (B);                             \
    }                                                   \
}                                                       \
MACRO_STOP

/* Block sizes */
#define PSMCT32BlockWidth 8
#define PSMCT32BlockHeight 8

#define PSMZ32BlockWidth 8
#define PSMZ32BlockHeight 8

#define PSMCT16BlockWidth 16
#define PSMCT16BlockHeight 8

#define PSMZ16BlockWidth 16
#define PSMZ16BlockHeight 8

#define PSMCT16SBlockWidth 16
#define PSMCT16SBlockHeight 8

#define PSMZ16SBlockWidth 16
#define PSMZ16SBlockHeight 8

#define PSMT8BlockWidth 16
#define PSMT8BlockHeight 16

#define PSMT4BlockWidth 32
#define PSMT4BlockHeight 16

/* Page sizes */
#define PSMCT32PageWidth 64
#define PSMCT32PageHeight 32

#define PSMZ32PageWidth 64
#define PSMZ32PageHeight 32

#define PSMCT16PageWidth 64
#define PSMCT16PageHeight 64

#define PSMZ16PageWidth 64
#define PSMZ16PageHeight 64

#define PSMCT16SPageWidth 64
#define PSMCT16SPageHeight 64

#define PSMZ16SPageWidth 64
#define PSMZ16SPageHeight 64

#define PSMT8PageWidth 128
#define PSMT8PageHeight 64

#define PSMT4PageWidth 128
#define PSMT4PageHeight 128

/* Min transfer width */
#define PSMCT32MinTW 2

#define PSMZ32MinTW 2

#define PSMCT24MinTW 8

#define PSMZ24MinTW 8

#define PSMCT16MinTW 4

#define PSMCT16SMinTW 4

#define PSMZ16MinTW 4

#define PSMZ16SMinTW 4

#define PSMT8MinTW 8

#define PSMT8HMinTW 8

#define PSMT4MinTW 8

#define PSMT4HLMinTW 8

#define PSMT4HHMinTW 8

static void
calcOffsets(RwUInt32 width, RwUInt32 height, int format,
            RwUInt64 *offsets, RwUInt64 *bufwidth, RwUInt32 *xyoff,
            RwUInt32 *texMemSize, RwUInt32 *paletteOffset)
{
    RwUInt32 blockWidth;
    RwUInt32 blockHeight;
    RwUInt32 pageWidth;
    RwUInt32 pageHeight;

    int palette;
    int palettewidth;
    int bufheight[7];
    int bufstart[7];
    int maxlevel;

    /* Sub page stuff */
    int interioroffsetx;
    int interioroffsety;
    int piviot;

    /* stack for final fill stage */
    int stackx[8];
    RwUInt32 stackh[8];
    RwUInt32 stackw[8];
    RwUInt32 stacko[8];
    int stackp;

    int i;

    RWFUNCTION(RWSTRING("calcOffsets"));

    switch (format)
    {
        case SCE_GS_PSMCT32:
        case SCE_GS_PSMCT24:
        case SCE_GS_PSMT8H:
        case SCE_GS_PSMT4HL:
        case SCE_GS_PSMT4HH:
            {
                blockWidth = PSMCT32BlockWidth;
                blockHeight = PSMCT32BlockHeight;
                pageWidth = PSMCT32PageWidth;
                pageHeight = PSMCT32PageHeight;
                break;
            }
        case SCE_GS_PSMCT16:
            {
                blockWidth = PSMCT16BlockWidth;
                blockHeight = PSMCT16BlockHeight;
                pageWidth = PSMCT16PageWidth;
                pageHeight = PSMCT16PageHeight;
                break;
            }
        case SCE_GS_PSMCT16S:
            {
                blockWidth = PSMCT16SBlockWidth;
                blockHeight = PSMCT16SBlockHeight;
                pageWidth = PSMCT16SPageWidth;
                pageHeight = PSMCT16SPageHeight;
                break;
            }
        case SCE_GS_PSMT8:
            {
                blockWidth = PSMT8BlockWidth;
                blockHeight = PSMT8BlockHeight;
                pageWidth = PSMT8PageWidth;
                pageHeight = PSMT8PageHeight;
                break;
            }
        case SCE_GS_PSMT4:
            {
                blockWidth = PSMT4BlockWidth;
                blockHeight = PSMT4BlockHeight;
                pageWidth = PSMT4PageWidth;
                pageHeight = PSMT4PageHeight;
                break;
            }
        case SCE_GS_PSMZ32:
        case SCE_GS_PSMZ24:
            {
                blockWidth = PSMZ32BlockWidth;
                blockHeight = PSMZ32BlockHeight;
                pageWidth = PSMZ32PageWidth;
                pageHeight = PSMZ32PageHeight;
                break;
            }
        case SCE_GS_PSMZ16:
            {
                blockWidth = PSMZ16BlockWidth;
                blockHeight = PSMZ16BlockHeight;
                pageWidth = PSMZ16PageWidth;
                pageHeight = PSMZ16PageHeight;
                break;
            }
        case SCE_GS_PSMZ16S:
        default:
            {
                blockWidth = PSMZ16SBlockWidth;
                blockHeight = PSMZ16SBlockHeight;
                pageWidth = PSMZ16SPageWidth;
                pageHeight = PSMZ16SPageHeight;
                break;
            }
    }

    maxlevel = 1;
    i = height > width? width : height;
    while ((i > 8) && (maxlevel < skyMaxMipLevels))
    {
        maxlevel += 1;
        i >>= 1;
    }

    offsets[0] = 0;
    bufwidth[0] = ((width + pageWidth - 1)/pageWidth) * (pageWidth/64);
    bufheight[0] = ((height + pageHeight -1 )/pageHeight);
    bufstart[0] = 0;

    i = 1;
    interioroffsetx = 0;
    interioroffsety = 0;
    piviot = 0;
    stackp = 0;
    while (i < maxlevel)
    {
        if ((width >= pageWidth) && (height >= pageHeight))
        {
            /* Easy case. Previous level filled a whole number of pages */
            offsets[i] = offsets[i-1]+(width/blockWidth)*(height/blockHeight);
            bufwidth[i] = (((width>>1)+pageWidth-1)/pageWidth)*(pageWidth/64);
            bufheight[i] = (((height>>1) + pageHeight -1 )/pageHeight);
            bufstart[i] = offsets[i];
            interioroffsetx = 0;
            interioroffsety = 0;
        }
        else if ((width < pageWidth) && (height >= pageHeight))
        {
            /* Previous level fills a level vertically, but doesn't
               horizontally. */
            /* We have to catch the case where there isn't any space
               at the right of the block */
            bufstart[i] = bufstart[i-1];
            bufwidth[i] = bufwidth[i-1];
            bufheight[i] = bufheight[i-1];
            if ((interioroffsetx + (width > blockWidth ? width:blockWidth))
                < pageWidth)
            {
                stackx[stackp] = interioroffsetx;
                stackh[stackp] = (height)>blockHeight?(height)
                    :blockHeight;
                stackw[stackp] = (width)>blockWidth?(width):blockWidth;
                stacko[stackp] = offsets[i-1]+(((height)+blockHeight-1)
                                               /blockHeight)
                    *(pageWidth/blockWidth);
                stackp++;
                /* as its all power of 2, we know we can put the new new
                   level next to the old */
                interioroffsetx += width > blockWidth ? width:blockWidth;
                offsets[i] = offsets[i-1]+((width+blockWidth-1)/blockWidth);
            }
            else
            {
                if (stackp)
                {
                    offsets[i] = stacko[stackp-1];
                    if (((width>>1) > blockWidth ? (width>>1):blockWidth)
                        < stackw[stackp-1])
                    {
                        stacko[stackp-1] += (((width>>1)+blockWidth-1)
                                             /blockWidth);
                        stackw[stackp-1] -= ((width>>1)>blockWidth?(width>>1)
                                             :blockWidth);
                    }
                    else if (((height>>1)>blockHeight ?
                              (height>>1):blockHeight) < stackh[stackp-1])
                    {
                        stacko[stackp-1] += (((height>>1)+blockHeight-1)
                                             /blockHeight)
                            *(pageWidth/blockWidth);
                        stackh[stackp-1] -= ( (height>>1)>blockHeight?
                                              (height>>1)
                                              :blockHeight );
                    }
                    else
                    {
                        stackp--;
                    }
                    piviot = 1;
                }
                else
                {
                    /* We need to move down to the end of the level */
                    interioroffsety += ( (height>blockHeight) ?
                                         height:
                                         blockHeight );
                    offsets[i] = offsets[i-1]+((height+blockHeight-1)
                                               /blockHeight)
                        *(pageWidth/blockWidth);
                }
            }
        }
        else if ((width >= pageWidth) && (height <pageHeight))
        {
            /* Previous level is a whole number of pages wide, but there is
               probably some spare space beneath */
            /* Same buf width as last one */
            bufstart[i] = bufstart[i-1];
            bufwidth[i] = bufwidth[i-1];
            bufheight[i] = bufheight[i-1];
            if ((interioroffsety + (height > blockHeight ? height:blockHeight))
                < pageHeight)
            {
                /* as its all power of 2, we know we can put the new new
                   level next to the old */
                interioroffsety += height > blockHeight ? height : blockHeight;
                offsets[i] = offsets[i-1]+((height+blockHeight-1)/blockHeight)
                    *(pageWidth/blockWidth)
                    *(bufwidth[i]/(pageWidth/64));
            }
            else
            {
                /* We need to move down to the end of the level */
                interioroffsetx += width > blockWidth ? width:blockWidth;
                offsets[i] = offsets[i-1]+((width+blockWidth-1)/blockWidth);
            }
        }
        else
        {
            bufstart[i] = bufstart[i-1];
            bufwidth[i] = bufwidth[i-1];
            bufheight[i] = bufheight[i-1];
            /* We make a choice to go in the major direction, ie based on
               which offset is 0 */
            if ((interioroffsetx + (width > blockWidth ? width :blockWidth))
                < (bufwidth[i]*64))
            {
                stackx[stackp] = interioroffsetx;
                stackh[stackp] = (height)>blockHeight?(height)
                    :blockHeight;
                stackw[stackp] = (width)>blockWidth?(width):blockWidth;
                stacko[stackp] = offsets[i-1]+(((height)+blockHeight-1)
                                               /blockHeight)
                    *(pageWidth/blockWidth);
                stackp++;

                interioroffsetx += width > blockWidth ? width:blockWidth;
                offsets[i] = offsets[i-1]+((width+blockWidth-1)/blockWidth);
            }
            else if (((interioroffsety +  ( (height > blockHeight) ?
                                            height:
                                            blockHeight) )
                      < bufheight[i]*pageHeight)
                     && (!piviot))
            {
                interioroffsety += blockHeight ? height:blockHeight;
                offsets[i] = offsets[i-1]+((height+blockHeight-1)/blockHeight)
                    *(pageWidth/blockWidth);
                piviot = i;
            }
            else
            {
                offsets[i] = stacko[stackp-1];
                if (((width>>1) > blockWidth ? (width>>1):blockWidth)
                    < stackw[stackp-1])
                {
                    stacko[stackp-1] += (((width>>1)+blockWidth-1)/blockWidth);
                    stackw[stackp-1] -= ((width>>1) > blockWidth ? (width>>1)
                                         :blockWidth);
                }
                else if (((height>>1) > blockHeight ? (height>>1):blockHeight)
                         < stackh[stackp-1])
                {
                    stacko[stackp-1] += (((height>>1)+blockHeight-1)
                                         /blockHeight)
                        *(pageWidth/blockWidth);
                    stackh[stackp-1] -= ((height>>1) > blockHeight?(height>>1)
                                         :blockHeight);
                }
                else
                {
                    stackp--;
                }
            }
        }

        width >>= 1;
        height >>= 1;

        i++;
    }

    {
        /* If we have a palette */
        /* Can we hide the palette ? */
        if ((bufwidth[maxlevel-1]*64 == width)
            && (bufheight[maxlevel-1]*pageHeight == height))
        {
            if ((format == SCE_GS_PSMT8)
                || (format == SCE_GS_PSMT4))
            {
                palette = bufstart[maxlevel-1]
                    + (bufwidth[maxlevel-1]*64/blockWidth)
                    *(bufheight[maxlevel-1]*pageHeight)/blockHeight;
                palettewidth = 1;
            }
            else
            {
                palette = 0;
                palettewidth = 0;
            }
        }
        else
        {
            if (format == SCE_GS_PSMT8)
            {
                /* bottom four blocks required */
                palette = bufstart[maxlevel-1]+((64*bufwidth[maxlevel-1])
                                                /pageWidth)
                    *bufheight[maxlevel-1]*32
                    -((64*bufwidth[maxlevel-1])/pageWidth)
                    *(pageWidth/blockWidth)
                    -2;
                palettewidth = bufwidth[maxlevel-1];
            }
            else if (format == SCE_GS_PSMT4)
            {
                /* bottom block required */
                palette = bufstart[maxlevel-1]+((64*bufwidth[maxlevel-1])
                                                /pageWidth)
                    *bufheight[maxlevel-1]*32 - 1;
                palettewidth = bufwidth[maxlevel-1];
            }
            else
            {
                palette = 0;
                palettewidth = 0;
            }
        }
    }
    width <<= maxlevel-1;
    height <<= maxlevel-1;
    {
        int result;
        RwUInt32 bw,bs;

        /* Postprocess offsets and add xyoffsets for TRXPOS */
        bs = bufstart[0];
        bw = bufwidth[0];
        for (i=0; i<maxlevel; i++)
        {
            /* Only reset if we have to. This should alow 128xN 8 bits to
               upload in 1 go. */
            if ((bw != bufwidth[i])
                || (((((offsets[i] - bs)*blockWidth)/(bw*64))*blockHeight)
                    > 0x7ff))
            {
                bs = bufstart[i];
                bw = bufwidth[i];
                RWASSERT(offsets[i] == (RwUInt64)bufstart[i]);
                xyoff[i] = 0;
            }
            else
            {
                RwUInt32 x, y;

                x = ((offsets[i] - bs)*blockWidth) % (bw*64);
                y = (((offsets[i] - bs)*blockWidth)/(bw*64))*blockHeight;
                xyoff[i] = (y << 16) | x;
            }
            if (bw*64/pageWidth > 1)
            {
                /* offset is across the full buffer width, but we are
                   tiled in memory */
                offsets[i] = (offsets[i] & ~((32*64*bw/pageWidth)
                                             -(pageWidth/blockWidth)))
                             |((offsets[i] & ((bw*64/blockWidth)
                                              -(pageWidth/blockWidth)))
                               <<((32*64*bw/pageWidth)/(bw*64/blockWidth)-1))
                             |((offsets[i] & ((32*64*bw/pageWidth)
                                              -(bw*64/blockWidth)))
                               >>((bw*64/blockWidth)/(pageWidth/blockWidth)-1));
            }
            GSBlockToAddress(result, offsets[i], format);
            offsets[i] = result;
        }
        /* palette offset is always correct */
        GSBlockToAddress(result, palette, format);
        palette = result;
    }
    *paletteOffset = palette;
    /* Return Size of texture only, in words */

    *texMemSize = (bufstart[maxlevel-1] +
                   ((bufwidth[maxlevel-1]*64)/blockWidth) *
                   ((bufheight[maxlevel-1]*pageHeight)
                    /blockHeight)) *64;

    RWRETURNVOID();
}

/************************************************************************
 * End Insert                                                           *
 ************************************************************************/
#endif /* BETTERPACK */

/****************************************************************************
 skyTransferMinSize

 enforce GS min transfers by pixel format.

 On entry   : format
            : raster extension flags
            : min transfer width return
            : min transfer height return
 */

static void
skyTransferMinSize(long format, RwUInt8 flags, int *minTW, int *minTH)
{
    int                 mintw, minth;

    RWFUNCTION(RWSTRING("skyTransferMinSize"));
    /* Compute min width and height */
    minth = 1;
    switch (format)
    {
        case SCE_GS_PSMCT32:
            {
                mintw = PSMCT32MinTW;
                break;
            }
        case SCE_GS_PSMZ32:
            {
                mintw = PSMZ32MinTW;
                break;
            }
        case SCE_GS_PSMCT24:
            {
                mintw = PSMCT24MinTW;
                break;
            }
        case SCE_GS_PSMZ24:
            {
                mintw = PSMZ24MinTW;
                break;
            }
        case SCE_GS_PSMCT16:
            {
                mintw = PSMCT16MinTW;
                break;
            }
        case SCE_GS_PSMCT16S:
            {
                mintw = PSMCT16SMinTW;
                break;
            }
        case SCE_GS_PSMZ16:
            {
                mintw = PSMZ16MinTW;
                break;
            }
        case SCE_GS_PSMZ16S:
            {
                mintw = PSMZ16SMinTW;
                break;
            }
        case SCE_GS_PSMT8:
            {
                mintw = PSMT8MinTW;
                break;
            }
        case SCE_GS_PSMT8H:
            {
                mintw = PSMT8HMinTW;
                break;
            }
        case SCE_GS_PSMT4:
            {
                mintw = PSMT4MinTW;
                break;
            }
        case SCE_GS_PSMT4HL:
            {
                mintw = PSMT4HLMinTW;
                break;
            }
        case SCE_GS_PSMT4HH:
            {
                mintw = PSMT4HHMinTW;
                break;
            }
        default:
            RWASSERT((int) "Duff format" & 0);
    }
    /* Fixup for twiddled case */
    if ((flags & 2) && (format == SCE_GS_PSMT8))
    {
        /* assuming that twiddling happens in a block */
        mintw = 16;
        minth = 4;             /* column height */
    }
#if 0
    /* This is very complicated if texture is sub page
     * sized, so we don't do it for now */
    if ((flags & 2) && (format == SCE_GS_PSMT4))
    {
        /* assuming that twiddling happens in a block */
        mintw = 32;
        minth = 4;             /* column height */
        /* We also need to mirror width/height */
    }
#endif
    if ((flags & 4) && (format == SCE_GS_PSMT4))
    {
        /* assuming that twiddling happens in a block */
        mintw = 32;
        minth = 4;             /* column height */
    }
    *minTW = mintw;
    *minTH = minth;
    RWRETURNVOID();
}

/****************************************************************************
 SkyRasterCreate

 Create a raster

 On entry   : NULL
            : pRaster - raster to allocate
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterCreate(void *__RWUNUSED__ pInOut, void *pRaster, RwInt32 flags)
{
    static const RwUInt32 rasterPageWidths[32] =
        { 128, 128, 128, 128, 128, 128, 128, 128,
        64, 64, 64, 64, 64, 64, 64, 64,
        64, 64, 64, 64, 64, 64, 64, 64,
        64, 64, 64, 64, 64, 64, 64, 64
    };
    static const RwUInt32 rasterPageHeights[32] =
        { 128, 128, 128, 128, 64, 64, 64, 64,
        64, 64, 64, 64, 64, 64, 64, 64,
        32, 32, 32, 32, 32, 32, 32, 32,
        32, 32, 32, 32, 32, 32, 32, 32
    };
    static const RwUInt32 PSCMT3224BlockOffsets[8] =
        { 0, 2, 2, 8, 8, 10, 10, 32 };
    static const RwUInt32 PSCMT16BlockOffsets[8] =
        { 0, 1, 4, 5, 16, 17, 20, 21 };
    static const RwUInt32 PSCMT16SBlockOffsets[8] =
        { 0, 1, 8, 9, 4, 5, 12, 13 };
    static const RwUInt32 PSMT8BlockOffsets[8] =
        { 0, 2, 2, 8, 8, 10, 10, 32 };
    static const RwUInt32 PSMT4BlockOffsets[8] =
        { 0, 1, 4, 5, 16, 17, 20, 21 };

    RwRaster           *rpRas = (RwRaster *) pRaster;
    _SkyRasterExt      *ext = RASTEREXTFROMRASTER(rpRas);

    RWFUNCTION(RWSTRING("SkyRasterCreate"));

    if (!SkyGetRasterFormat(pInOut, pRaster, flags))
    {
        RWRETURN(FALSE);
    }

    RWASSERT(skyMaxMipLevels <= 7);

    /* Set up */
    rpRas->cpPixels = (unsigned char *) NULL;
    rpRas->palette = (unsigned char *) NULL;
    ext->bLocked = FALSE;
    /* No upload packets at creation */
    ext->cachePkts = FALSE;
    ext->palUploadPkt = (u_long128 *) NULL;
    ext->mipUploadPkts[0] = (u_long128 *) NULL;
    ext->mipUploadPkts[1] = (u_long128 *) NULL;
    ext->mipUploadPkts[2] = (u_long128 *) NULL;
    ext->mipUploadPkts[3] = (u_long128 *) NULL;
    ext->mipUploadPkts[4] = (u_long128 *) NULL;
    ext->mipUploadPkts[5] = (u_long128 *) NULL;
    ext->mipUploadPkts[6] = (u_long128 *) NULL;
    /* Not cached to start with */
    ext->mpCacheEntry = (_SkyMemBlock *) NULL;
    /* Flags are initially all zero */
    ext->flags = 0;

    rpRas->originalWidth = rpRas->width;
    rpRas->originalHeight = rpRas->height;
    rpRas->originalPixels = rpRas->cpPixels;

    /* If is not a camera or Z buffer, then we need to allocate real memory */
    if ((rpRas->width) && (rpRas->height))
    {
        switch (rpRas->cType)
        {
            case rwRASTERTYPECAMERATEXTURE:
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
                }
            case rwRASTERTYPETEXTURE:
                {
                    RwUInt64            offsetBy64[7], widthBy64[7];
                    RwUInt32            xyoffset[7];
                    RwInt32             bytesPerPalPixel, palHeight,
                        palWidth, overW, overH;
                    RwUInt32            pageWidth, pageHeight,
                        palPageWidth, palPageHeight;

                    pageWidth = rasterPageWidths[rpRas->depth - 1];
                    pageHeight = rasterPageHeights[rpRas->depth - 1];

                    /* We set up a TEX0 and a size (for caching) if a texture */
                    overW = _rwSkyFindMSB(rpRas->width);
                    if ((1 << overW) < rpRas->width)
                    {
                        overW++;
                    }
                    overH = _rwSkyFindMSB(rpRas->height);
                    if ((1 << overH) < rpRas->height)
                    {
                        overH++;
                    }
                    ext->lsb = ((((RwUInt32) rpRas->width > pageWidth) ?
                                 rpRas->
                                 width >> 6 : (pageWidth >> 6)) << 14 |
                                (overW & 0xf) << 26 | (overH & 0xf) <<
                                30);
                    ext->msb = ((overH & 0xf) >> 2 | 0l << 3); /* MODULATE */

                    /* We set up mipmapK to be 0 initially */
                    ext->mipmapKL = (RwUInt16) skyDefaultMipmapKL;

                    /* It's a texture so we cache the packets */
                    ext->cachePkts = TRUE;

                    /* Fill in a type, whether texture alpha exists */
                    /* Don't think that the following looks right (gjd) */
                    /* switch (rpRas->cFormat & (rwRASTERFORMATPAL4|rwRASTERFORMATPAL8 >> 8)) */
                    switch (rpRas->
                            cFormat &
                            ((rwRASTERFORMATPAL4 | rwRASTERFORMATPAL8)
                             >> 8))
                    {
                        case (0):
                            {
                                /* No palette for this one */
                                bytesPerPalPixel = palWidth =
                                    palHeight = 0;
                                palPageWidth = palPageHeight = 0;

                                switch (rpRas->
                                        cFormat &
                                        (rwRASTERFORMATPIXELFORMATMASK
                                         >> 8))
                                {
                                    case (rwRASTERFORMAT1555 >> 8):
                                        {
                                            ext->lsb |= PSMCT16S << 20;
                                            ext->msb |= 1l << (34 - 32); /* Use RGBA from texture */
                                            break;
                                        }
                                    case (rwRASTERFORMAT888 >> 8):
                                        {
                                            ext->lsb |= PSMCT24 << 20;
                                            break;
                                        }
                                    case (rwRASTERFORMAT8888 >> 8):
                                        {
                                            ext->lsb |= PSMCT32 << 20;
                                            ext->msb |= 1l << (34 - 32); /* Use RGBA from texture */
                                            break;
                                        }
                                    default:
                                        {
                                            /* Unsupported format */
                                            RWERROR((E_RW_INVRASTERFORMAT));
                                            RWRETURN(FALSE);
                                        }
                                }
                                break;
                            }
                        case (rwRASTERFORMATPAL4 >> 8):
                            {
                                palWidth = 8;
                                palHeight = 2;

                                ext->lsb |= PSMT4 << 20;
                                ext->msb |= 1l << (34 - 32); /* Use RGBA from texture */
                                ext->msb |= 1l << (61 - 32);

                                switch (rpRas->
                                        cFormat &
                                        (rwRASTERFORMATPIXELFORMATMASK
                                         >> 8))
                                {
                                    case (rwRASTERFORMAT1555 >> 8):
                                        {
                                            ext->msb |=
                                                PSMCT16S << (51 - 32);
                                            bytesPerPalPixel = 2;
                                            palPageWidth = 64;
                                            palPageHeight = 64;
                                            break;
                                        }
                                    case (rwRASTERFORMAT8888 >> 8):
                                        {
                                            ext->msb |=
                                                PSMCT32 << (51 - 32);
                                            bytesPerPalPixel = 4;
                                            palPageWidth = 64;
                                            palPageHeight = 32;
                                            break;
                                        }
                                    default:
                                        {
                                            /* Unsupported format */
                                            RWERROR((E_RW_INVRASTERFORMAT));
                                            RWRETURN(FALSE);
                                        }
                                }
                                break;
                            }
                        case (rwRASTERFORMATPAL8 >> 8):
                            {
                                palWidth = 16;
                                palHeight = 16;

                                ext->lsb |= PSMT8 << 20;
                                ext->msb |= 1l << (34 - 32); /* Use RGBA from texture */
                                ext->msb |= 1l << (61 - 32);

                                switch (rpRas->
                                        cFormat &
                                        (rwRASTERFORMATPIXELFORMATMASK
                                         >> 8))
                                {
                                    case (rwRASTERFORMAT1555 >> 8):
                                        {
                                            ext->msb |=
                                                PSMCT16S << (51 - 32);
                                            bytesPerPalPixel = 2;
                                            palPageWidth = 64;
                                            palPageHeight = 64;
                                            break;
                                        }
                                    case (rwRASTERFORMAT8888 >> 8):
                                        {
                                            ext->msb |=
                                                PSMCT32 << (51 - 32);
                                            bytesPerPalPixel = 4;
                                            palPageWidth = 64;
                                            palPageHeight = 32;
                                            break;
                                        }
                                    default:
                                        {
                                            /* Unsupported format */
                                            RWERROR((E_RW_INVRASTERFORMAT));
                                            RWRETURN(FALSE);
                                        }
                                }
                                break;
                            }
                        default:
                            {
                                /* Huh? ! */
                                RWERROR((E_RW_INVRASTERFORMAT));
                                RWRETURN(FALSE);
                            }
                    }

                    /* Set up the stride */
                    rpRas->stride = (rpRas->depth * rpRas->width) >> 3;

                    /* Set up size for texture caching, and calculated texture base pointers */
                    if (rpRas->cFormat & (rwRASTERFORMATMIPMAP >> 8))
                    {
                        RwUInt32            levels, texMemSize,
                            sysMemSize, width, height;
#ifdef BETTERPACK
                        RwUInt32            paletteOffset;
#endif /* BETTERPACK */
                        RwUInt64            prevWidthBy64;
                        RwUInt64            word64;
                        RwUInt32            maxMip;
                        RwUInt32            lastMapPages,
                            lastMapPageWidth, lastMapPageHeight;
                        RwUInt32            sizeBeforePrevMip,
                            blockOffsetBy4;

                        width = rpRas->width;
                        height = rpRas->height;
                        levels = 0;
                        texMemSize = 0;
                        sysMemSize = 0;
                        sizeBeforePrevMip = 0;

                        offsetBy64[0] = offsetBy64[1] = offsetBy64[2] =
                            0;
                        offsetBy64[3] = offsetBy64[4] = offsetBy64[5] =
                            0;
                        offsetBy64[6] = 0;
                        widthBy64[0] = widthBy64[1] = widthBy64[2] = 1;
                        widthBy64[3] = widthBy64[4] = widthBy64[5] = 1;
                        widthBy64[6] = 1;

                        prevWidthBy64 =
                            (width >
                             pageWidth) ? (width >> 6) : (pageWidth >>
                                                          6);

                        while ((width != 0) && (height != 0)
                               && (levels < (RwUInt32) skyMaxMipLevels)
                               &&
                               ((rpRas->width < 8 || rpRas->height < 8)
                                || (width >= 8 && height >= 8)))
                        {
                            RwUInt32            stride;
                            RwUInt32            size;

                            size = (rpRas->depth * width * height) >> 3;
                            size = (size + 15) & ~15;

                            /* Space in system memory for this level */
                            sysMemSize += size;

                            widthBy64[levels] =
                                (width >
                                 pageWidth) ? (width >> 6) : (pageWidth
                                                              >> 6);
                            stride =
                                (int) (rpRas->depth *
                                       (widthBy64[levels] << 6)) >> 3;

                            /* If we go to a different width, we need to align */
                            if (widthBy64[levels] != prevWidthBy64)
                            {
                                RwUInt32            maxMip = levels - 1;

                                RWASSERT(levels > 0);

                                lastMapPageWidth =
                                    ((rpRas->width >> maxMip) +
                                     (pageWidth - 1)) / pageWidth;
                                lastMapPageHeight =
                                    ((rpRas->height >> maxMip) +
                                     (pageHeight - 1)) / pageHeight;
                                lastMapPages =
                                    lastMapPageWidth *
                                    lastMapPageHeight;
                                texMemSize =
                                    ((sizeBeforePrevMip) +
                                     (lastMapPages * 2048)) & ~2047;
                            }
                            prevWidthBy64 = widthBy64[levels];

                            /* Align to 64 words */
                            texMemSize = ((texMemSize + 63) & ~63);

                            /* find out how many multiples of 4 blocks we are through
                             * current page */
                            blockOffsetBy4 = (texMemSize & 2047) / 256;

                            switch ((ext->lsb >> 20) & 0x3F)
                            {
                                case PSMCT32:
                                case PSMCT24:
                                    offsetBy64[levels] =
                                        ((texMemSize / 2048) * 32) +
                                        PSCMT3224BlockOffsets
                                        [blockOffsetBy4];
                                    break;
                                case PSMCT16:
                                    offsetBy64[levels] =
                                        ((texMemSize / 2048) * 32) +
                                        PSCMT16BlockOffsets
                                        [blockOffsetBy4];
                                    break;
                                case PSMCT16S:
                                    offsetBy64[levels] =
                                        ((texMemSize / 2048) * 32) +
                                        PSCMT16SBlockOffsets
                                        [blockOffsetBy4];
                                    break;
                                case PSMT8:
                                    offsetBy64[levels] =
                                        ((texMemSize / 2048) * 32) +
                                        PSMT8BlockOffsets
                                        [blockOffsetBy4];
                                    break;
                                case PSMT4:
                                    offsetBy64[levels] =
                                        ((texMemSize / 2048) * 32) +
                                        PSMT4BlockOffsets
                                        [blockOffsetBy4];
                                    break;
                            }

                            /* cache texmemsize before this mipmap in case we need to
                             * align to page boundaries due to page width changes */
                            sizeBeforePrevMip = texMemSize;
                            texMemSize += (height * stride) / 4; /* Four bytes per word */
                            texMemSize = (texMemSize + 63) & ~63; /* Align on 64 bytes */

                            levels++;
                            width >>= 1;
                            height >>= 1;
                        }

#ifdef BETTERPACK
#if 0
                        lastMapPageWidth =
                            ((rpRas->width >> (levels - 1)) +
                             (pageWidth - 1)) / pageWidth;
                        lastMapPageHeight =
                            ((rpRas->height >> (levels - 1)) +
                             (pageHeight - 1)) / pageHeight;
                        lastMapPages =
                            lastMapPageWidth * lastMapPageHeight;
                        printf("old: %d\n",
                               ((offsetBy64[levels - 1] * 64) +
                                (lastMapPages * 2048)) & ~2047);
#endif
                        calcOffsets(rpRas->width, rpRas->height,
                                    ((ext->lsb >> 20) & 0x3F),
                                    offsetBy64, widthBy64, xyoffset,
                                    &texMemSize, &paletteOffset);
#if 0
                        printf("new: %d\n", texMemSize);
#endif
#endif /* BETTERPACK */

                        /* So how much memory do we need */
                        ext->sysMemSize = sysMemSize;

                        /* How many mipmap levels do we have? */
                        maxMip = levels - 1;
                        ext->maxMipLevel = (RwUInt8) (maxMip << 2);

                        /* Set up the base addresses for the mipmap */
                        word64 = ((offsetBy64[1] & 0x3fff) << 0)
                            | (widthBy64[1] << 14) |
                            ((offsetBy64[2] & 0x3fff) << 20)
                            | (widthBy64[2] << 34) |
                            ((offsetBy64[3] & 0x3fff) << 40)
                            | (widthBy64[3] << 54);
                        ext->miptbp1Lsb = (RwUInt32) (word64);
                        ext->miptbp1Msb = (RwUInt32) (word64 >> 32);
#if defined(GSB) && defined(GSPLUS)
                        word64 = ((offsetBy64[1] & 0x1ffff) << 0) |
                            ((offsetBy64[2] & 0x1ffff) << 20) |
                            ((offsetBy64[3] & 0x1ffff) << 40);
                        ext->miptbp3Lsb = (RwUInt32) (word64);
                        ext->miptbp3Msb = (RwUInt32) (word64 >> 32);
#endif /* defined(GSB) && defined(GSPLUS) */
                        word64 = ((offsetBy64[4] & 0x3fff) << 0)
                            | (widthBy64[4] << 14) |
                            ((offsetBy64[5] & 0x3fff) << 20)
                            | (widthBy64[5] << 34) |
                            ((offsetBy64[6] & 0x3fff) << 40)
                            | (widthBy64[6] << 54);
                        ext->miptbp2Lsb = (RwUInt32) (word64);
                        ext->miptbp2Msb = (RwUInt32) (word64 >> 32);
#if defined(GSB) && defined(GSPLUS)
                        word64 = ((offsetBy64[4] & 0x1ffff) << 0) |
                            ((offsetBy64[5] & 0x1ffff) << 20) |
                            ((offsetBy64[6] & 0x1ffff) << 40);
                        ext->miptbp4Lsb = (RwUInt32) (word64);
                        ext->miptbp4Msb = (RwUInt32) (word64 >> 32);
#endif /* defined(GSB) && defined(GSPLUS) */

                        ext->sysMemPalSize =
                            palWidth * palHeight * bytesPerPalPixel;
#ifndef HIDEPALETTE
                        /* Round up to next page size */
                        lastMapPageWidth =
                            ((rpRas->width >> maxMip) +
                             (pageWidth - 1)) / pageWidth;
                        lastMapPageHeight =
                            ((rpRas->height >> maxMip) +
                             (pageHeight - 1)) / pageHeight;
                        lastMapPages =
                            lastMapPageWidth * lastMapPageHeight;
                        ext->nTexCacheSize =
                            ((offsetBy64[maxMip] * 64) +
                             (lastMapPages * 2048)) & ~2047;

                        /* Sort out the palette alignment */
                        if (ext->sysMemPalSize)
                        {
                            /* Bang in the palette offset (Need to align to new page, 'cos it's a different format) */
                            ext->palOffset = ext->nTexCacheSize >> 6;

                            /* Now re-align to next page boundary for size */
                            lastMapPageWidth =
                                (palWidth +
                                 (palPageWidth - 1)) / palPageWidth;
                            lastMapPageHeight =
                                (palHeight +
                                 (palPageHeight - 1)) / palPageHeight;
                            lastMapPages =
                                lastMapPageWidth * lastMapPageHeight;
                            ext->nTexCacheSize =
                                (ext->nTexCacheSize +
                                 (lastMapPages * 2048)) & ~2047;
                        }
                        else
                        {
                            ext->palOffset = 0;
                        }
#else /* !HIDEPALETTE */
#ifdef BETTERPACK
                        ext->nTexCacheSize = texMemSize;
                        if (ext->sysMemPalSize)
                        {
                            ext->palOffset = paletteOffset;
                            if ((paletteOffset << 6) == texMemSize)
                            {
                                /* Palette takes the next page */
                                ext->nTexCacheSize += 2048;
                            }
                        }
                        else
                        {
                            ext->palOffset = 0;
                        }
#else /* BETTERPACK */
                        /* Sort out the palette alignment */
#if 1
                        if (ext->sysMemPalSize)
                        {
                            lastMapPageWidth = ((rpRas->width >> maxMip)
                                                + (pageWidth -
                                                   1)) / pageWidth;
                            if (palHeight == 2)
                            {
                                int                 blockStart;

                                /* Convert offset back into block */
                                blockStart = (offsetBy64[maxMip] & 1)
                                    | ((offsetBy64[maxMip] & 4) >> 1)
                                    | ((offsetBy64[maxMip] & 16) >> 2);
                                /* Round to next full page */
                                lastMapPageHeight =
                                    ((((rpRas->height >> maxMip) +
                                       15) >> 4) + blockStart + 7) >> 3;
                                lastMapPages =
                                    lastMapPageWidth *
                                    lastMapPageHeight;
                                ext->nTexCacheSize =
                                    ((offsetBy64[maxMip] * 64) +
                                     (lastMapPages * 2048)) & ~2047;
                                /* We are a 16 entry palette which will fit */
                                /* in a single block */
                                if ((rpRas->width >> maxMip) < 128)
                                {
                                    /* Space on the end of a row of blocks */
                                    /* We know that we always start on the */
                                    /* beginning of a row */
                                    /* 0->10, 1->11, 4->14, 5->15, 16->26, */
                                    /* 17->27, 20->30, 21->31 */
                                    RWASSERT(!
                                             (offsetBy64[maxMip] & 31 &
                                              10));
                                    ext->palOffset =
                                        offsetBy64[maxMip] + 10;

#if 0
                                    /* Round to next full page */
                                    lastMapPageHeight =
                                        ((((rpRas->height >> maxMip) +
                                           15) >> 4) + blockStart +
                                         7) >> 3;
                                    lastMapPages =
                                        lastMapPageWidth *
                                        lastMapPageHeight;
                                    ext->nTexCacheSize =
                                        ((offsetBy64[maxMip] * 64) +
                                         (lastMapPages * 2048)) & ~2047;
#endif
                                }
                                else
                                {
                                    /* Have to put it after texture */
                                    if ((((rpRas->height
                                           >> maxMip) + 15) >> 4) +
                                        blockStart < 8)
                                    {
                                        /* Space on end of block */
                                        ext->palOffset =
                                            (offsetBy64[maxMip] & ~31) +
                                            PSMT4BlockOffsets[(((rpRas->
                                                                 height
                                                                 >>
                                                                 maxMip)
                                                                +
                                                                15) >>
                                                               4) +
                                                              blockStart];
                                        /* Strictly ....
                                         * lastMapPageHeight = ((((rpRas->height
                                         * >> maxMip)
                                         * +15)>>4)
                                         * +blockStart+7+1) >>3;
                                         * but the if condition protects us, so
                                         * we factor out common code */
#if 0
                                        lastMapPageHeight =
                                            ((((rpRas->
                                                height >> maxMip) +
                                               15) >> 4) + blockStart +
                                             7) >> 3;
                                        lastMapPages =
                                            lastMapPageWidth *
                                            lastMapPageHeight;
                                        ext->nTexCacheSize =
                                            ((offsetBy64[maxMip] * 64) +
                                             (lastMapPages *
                                              2048)) & ~2047;
#endif
                                    }
                                    else
                                    {
                                        /* Its going to have to have a page to */
                                        /* itself. Sob */
#if 0
                                        lastMapPageHeight =
                                            ((((rpRas->
                                                height >> maxMip) +
                                               15) >> 4) + blockStart +
                                             7) >> 3;
                                        lastMapPages =
                                            lastMapPageWidth *
                                            lastMapPageHeight;
                                        ext->nTexCacheSize =
                                            ((offsetBy64[maxMip] * 64) +
                                             (lastMapPages *
                                              2048)) & ~2047;
#endif
                                        ext->palOffset =
                                            ext->nTexCacheSize >> 6;
                                        ext->nTexCacheSize += 2048;
                                    }
                                }
                            }
                            else
                            {
                                /* must be a 256 entry palette */
                                /* A palette takes either 1x2 or 2x2 blocks */
                                /* For simplicity, I assume 2x2 */
                                int                 blockStart;

                                /* Convert offset back into block */
                                blockStart =
                                    ((offsetBy64[maxMip] & 2) >> 1) |
                                    ((offsetBy64[maxMip] & 8) >> 2);
                                /* Round to next full page */
                                lastMapPageHeight =
                                    ((((rpRas->height >> maxMip) +
                                       15) >> 4) + blockStart + 3) >> 2;
                                lastMapPages =
                                    lastMapPageWidth *
                                    lastMapPageHeight;
                                ext->nTexCacheSize =
                                    ((offsetBy64[maxMip] * 64) +
                                     (lastMapPages * 2048)) & ~2047;
                                /* if the last mip is < 128 wide and is 2 blocks */
                                /* from end, or spans 2 pages, we can put it in */
                                /* the bottom right of the final page */
                                if (((rpRas->width >> maxMip) < 128)
                                    && ((blockStart < 3)
                                        ||
                                        ((((rpRas->height >> maxMip) +
                                           15) >> 4) > 1)))
                                {
                                    /* Space on the end of a row of blocks */
                                    /* We know that we always start on the */
                                    /* beginning of a row */
                                    /* 0,2,8->28 */
                                    RWASSERT(!
                                             (offsetBy64[maxMip] & 31 &
                                              21));
                                    ext->palOffset =
                                        (offsetBy64[maxMip] & ~31) + 28;
                                    /* If it spans two pages */
                                    /* Second half of conditional strictly
                                     * unecessary, but left in as not speed
                                     * critical code path */
                                    if ((blockStart == 3)
                                        &&
                                        ((((rpRas->height >> maxMip) +
                                           15) >> 4) > 1))
                                    {
                                        ext->palOffset += 32;
                                    }
#if 0
                                    /* Round to next full page */
                                    lastMapPageHeight =
                                        ((((rpRas->height >> maxMip) +
                                           15) >> 4) + blockStart +
                                         3) >> 2;
                                    lastMapPages =
                                        lastMapPageWidth *
                                        lastMapPageHeight;
                                    ext->nTexCacheSize =
                                        ((offsetBy64[maxMip] * 64) +
                                         (lastMapPages * 2048)) & ~2047;
#endif
                                }
                                else
                                {
                                    /* Have to put it after texture */
                                    if ((((rpRas->height
                                           >> maxMip) + 15) >> 4) +
                                        blockStart < 3)
                                    {
                                        /* Space on end of block */
                                        ext->palOffset =
                                            (offsetBy64[maxMip] & ~31) +
                                            PSMT8BlockOffsets[(((rpRas->
                                                                 height
                                                                 >>
                                                                 maxMip)
                                                                +
                                                                15) >>
                                                               4) +
                                                              blockStart];
                                        /* Strictly ....
                                         * lastMapPageHeight = ((((rpRas->height
                                         * >> maxMip)
                                         * +15)>>4)
                                         * +blockStart+3+2) >>2;
                                         * but the if condition protects us, so
                                         * we factor out common code */
#if 0
                                        lastMapPageHeight =
                                            ((((rpRas->
                                                height >> maxMip) +
                                               15) >> 4) + blockStart +
                                             3) >> 2;
                                        lastMapPages =
                                            lastMapPageWidth *
                                            lastMapPageHeight;
                                        ext->nTexCacheSize =
                                            ((offsetBy64[maxMip] * 64) +
                                             (lastMapPages *
                                              2048)) & ~2047;
#endif
                                    }
                                    else
                                    {
                                        /* Its going to have to have a page to */
                                        /* itself. Sob */
#if 0
                                        lastMapPageHeight =
                                            ((((rpRas->
                                                height >> maxMip) +
                                               15) >> 4) + blockStart +
                                             3) >> 2;
                                        lastMapPages =
                                            lastMapPageWidth *
                                            lastMapPageHeight;
                                        ext->nTexCacheSize =
                                            ((offsetBy64[maxMip] * 64) +
                                             (lastMapPages *
                                              2048)) & ~2047;
#endif
                                        ext->palOffset =
                                            ext->nTexCacheSize >> 6;
                                        ext->nTexCacheSize += 2048;
                                    }
                                }
                            }
                        }
                        else
#endif
                        {
                            /* Round up to next page size */
                            lastMapPageWidth = ((rpRas->width >> maxMip)
                                                + (pageWidth -
                                                   1)) / pageWidth;
                            lastMapPageHeight =
                                ((rpRas->height >> maxMip) +
                                 (pageHeight - 1)) / pageHeight;
                            lastMapPages =
                                lastMapPageWidth * lastMapPageHeight;
                            ext->nTexCacheSize =
                                ((offsetBy64[maxMip] * 64) +
                                 (lastMapPages * 2048)) & ~2047;
                            ext->palOffset = 0;
                        }
#endif /* BETTERPACK */
#endif /* !HIDEPALETTE */
                    }
                    else
                    {
                        RwUInt64            word64;
                        RwUInt32            lastMapPages,
                            lastMapPageWidth, lastMapPageHeight;
                        RwUInt32            widthByPage;
                        RwUInt32            size;

                        size = rpRas->height * rpRas->stride;
                        size = (size + 15) & ~15;
                        ext->sysMemSize = size;

                        /* Set to something sensible */
                        word64 =
                            (1l << 14) | ((RwUInt64) 1l << 34) |
                            ((RwUInt64) 1l << 54);
                        ext->miptbp1Lsb = (RwUInt32) (word64);
                        ext->miptbp1Msb = (RwUInt32) (word64 >> 32);
                        ext->miptbp2Lsb = (RwUInt32) (word64);
                        ext->miptbp2Msb = (RwUInt32) (word64 >> 32);
                        ext->maxMipLevel = 0;

                        /* So that we can reference in common code below */
                        offsetBy64[0] = 0;
                        widthBy64[0] =
                            ((rpRas->width + pageWidth -
                              1) / pageWidth) * (pageWidth / 64);
                        xyoffset[0] = 0;

                        /* Round up to next page size */
                        widthByPage =
                            (rpRas->width + pageWidth - 1) / pageWidth;
                        lastMapPageHeight =
                            (rpRas->height +
                             (pageHeight - 1)) / pageHeight;
                        lastMapPages = widthByPage * lastMapPageHeight;
                        ext->nTexCacheSize =
                            ((lastMapPages * 2048) & ~2047);

                        /* Sort out the palette alignment */
                        ext->sysMemPalSize =
                            palWidth * palHeight * bytesPerPalPixel;
                        if (ext->sysMemPalSize)
                        {
#ifdef HIDEPALETTE
                            if (((RwInt32) (widthByPage * pageWidth) >
                                 rpRas->width)
                                ||
                                ((RwInt32)
                                 (lastMapPageHeight * pageHeight) >
                                 rpRas->height))
                            {
                                /* We can definately hide the palette in the
                                 * bottom corner of the page */
                                ext->palOffset =
                                    (ext->nTexCacheSize >> 6) - 4;
                            }
                            else
#endif /* HIDEPALETTE */
                            {
                                /* Bang in the palette offset (Need to align
                                 * to new page, 'cos it's a different format) */
                                ext->palOffset =
                                    ext->nTexCacheSize >> 6;

                                /* Now re-align to next page boundary for size */
                                lastMapPageWidth =
                                    (palWidth +
                                     (palPageWidth - 1)) / palPageWidth;
                                lastMapPageHeight =
                                    (palHeight +
                                     (palPageHeight -
                                      1)) / palPageHeight;
                                lastMapPages =
                                    lastMapPageWidth *
                                    lastMapPageHeight;
                                ext->nTexCacheSize =
                                    (ext->nTexCacheSize +
                                     (lastMapPages * 2048)) & ~2047;
                            }
                        }
                        else
                        {
                            ext->palOffset = 0;
                        }
                    }

                    /* Make the system memory size a multiple of 16 bytes */
                    ext->sysMemSize = (ext->sysMemSize + 15) & ~15;

                    /* We now decide if we can use the new texture upload
                     * format. This is limited to mip 0 being less than
                     * equal to 32767 qw in size */
#ifdef ALTTEXFORM
                    if ((!skyNoNewStyleRasters)
                        &&
                        ((((rpRas->height * rpRas->width *
                            rpRas->depth) >> 3) >> 4) < 32767))
                    {
                        int                 minTW;
                        int                 minTH;
                        RwUInt64            tmp, tmp1;
                        u_long128           ltmp, giftag, giftag1;
                        u_long128          *data, *data1;
                        int                 w, h, i;
                        int                 pktSize;
                        RwUInt64            palxyoffset = 0;
                        int                 pixelDataSize;
                        int                 prefixDataSize;

                        /* new format 1 */
                        ext->flags |= 1;

                        /* Do we intend to twiddle? */
                        /* This should really be user controlled as it */
                        /* affects the min width and heights that can */
                        /* be transfered */
                        if (((ext->lsb >> 20) & 0x3f) == SCE_GS_PSMT8)
                        {
                            ext->flags |= 2;
                            if (((ext->msb >> (51 - 32)) & 0xf) ==
                                SCE_GS_PSMCT32)
                            {
                                /* Final mip must be 1 page in width */
                                if (widthBy64[((ext->maxMipLevel) >> 2)]
                                    == 2)
                                {
                                    RwUInt32            bs;
                                    RwUInt32            x, y;

                                    /* Figure out where effective buffer
                                     * start is given the offset of last
                                     * mip level */

                                    x = xyoffset[((ext->
                                                   maxMipLevel) >> 2)] &
                                        0x7ff;
                                    y = (xyoffset
                                         [((ext->
                                            maxMipLevel) >> 2)] >> 16) &
                                        0x7ff;
                                    bs = PSMT8AddressToBlock(offsetBy64
                                                             [((ext->
                                                                maxMipLevel)
                                                               >> 2)]) -
                                        (x / PSMT8BlockWidth) -
                                        ((y / PSMT8BlockHeight) *
                                         (PSMT8PageWidth /
                                          PSMT8BlockWidth));

                                    x = ((PSMCT32AddressToBlock
                                          (ext->palOffset) -
                                          bs) * PSMCT32BlockWidth) % 64;
                                    y = (((PSMCT32AddressToBlock
                                           (ext->palOffset) -
                                           bs) * PSMCT32BlockWidth) /
                                         64) * PSMCT32BlockHeight;

                                    /* We have to be able to generate a valid
                                     * TRXPOS from the pal offset */
                                    if (y < 0x800)
                                    {
                                        palxyoffset =
                                            (RwUInt64) ((y << 16) | x)
                                            << 32;
                                    }
                                    else
                                    {
                                        palxyoffset = 0;
                                    }
                                }
                                else
                                {
                                    palxyoffset = 0;
                                }
                            }
                        }
                        if (((ext->lsb>>20)&0x3f) == SCE_GS_PSMT4)
                        {
                            ext->flags |= 4;
                            /* One day we will twiddle palettes so that they
                               always seem to be SCE_GS_PSMCT16 for 4 bit */
                            if (((ext->msb >> (51-32)) & 0xf) == SCE_GS_PSMCT16)
                            {
                                /* Final mip must be 1 page in width */
                                if (widthBy64[((ext->maxMipLevel) >> 2)] == 2)
                                {
                                    RwUInt32 bs;
                                    RwUInt32 x, y;

                                    /* Figure out where effective buffer
                                       start is given the offset of last
                                       mip level */

                                    x = xyoffset[((ext->maxMipLevel)>>2)]&0x7ff;
                                    y = (xyoffset[((ext->maxMipLevel)>>2)]>>16)
                                        & 0x7ff;
                                    bs = PSMT4AddressToBlock(offsetBy64[((
                                                         ext->maxMipLevel)>>2)])
                                         - (x / PSMT4BlockWidth)
                                         - ((y / PSMT4BlockHeight)
                                            * (PSMT4PageWidth/PSMT4BlockWidth));

                                    x = ((PSMCT16AddressToBlock(ext->palOffset)
                                          -bs)*PSMCT16BlockWidth)
                                        % 64;
                                    y = (((PSMCT16AddressToBlock(ext->palOffset)
                                           -bs)*PSMCT16BlockWidth)
                                         /64)*PSMCT16BlockHeight;

                                    /* We have to be able to generate a valid
                                       TRXPOS from the pal offset */
                                    if (y < 0x800)
                                    {
                                        palxyoffset = (RwUInt64)((y << 16) | x)
                                                                <<32;
                                    }
                                    else
                                    {
                                        palxyoffset = 0;
                                    }
                                }
                                else
                                {
                                    palxyoffset = 0;
                                }
                            }
                        }

                        /* We need to compute the main memory size */
                        /* Each mip needs gif + 3 reg + gif <+ data> = 5 qw */
                        ext->sysMemSize =
                            (5 * (((ext->maxMipLevel) >> 2) + 1)) << 4;

                        /* Compute min width and height */
                        skyTransferMinSize(((ext->lsb >> 20) & 0x3f),
                                           ext->flags, &minTW, &minTH);

                        w = rpRas->width;
                        h = rpRas->height;
                        /* add space for each mip level's data */
                        for (i = 0; i <= ((ext->maxMipLevel) >> 2); i++)
                        {
                            int                 levelWidth, levelHeight;

                            levelWidth = w < minTW ? minTW : w;
                            levelHeight = h < minTH ? minTW : h;
                            ext->sysMemSize +=
                                (((levelWidth * levelHeight *
                                   rpRas->depth) >> 3) + 15) & ~0xf;
                            w >>= 1;
                            h >>= 1;
                        }
                        pixelDataSize = ext->sysMemSize;
                        /* And similarly for the palette */
                        if (ext->sysMemPalSize)
                        {
                            /* we know that this is a qw multiple */
                            if (palHeight == 2)
                            {
                                palHeight = 3;
                            }
                            ext->sysMemPalSize = palWidth * palHeight
                                * bytesPerPalPixel + (5 << 4);
                        }

                        /* We also need a prefix pseudo packet that contains */
                        /* an upload template */
                        /* <address of mip0>   <qwc of template>
                         * <cnt2>
                         * <A+D>               <gif1>
                         * <blit>              <vals>
                         * <address of pkt0>   <ref>
                         * <cnt2>
                         * <A+D>               <gif1>
                         * <blit>              <vals>
                         * <address of pkt0>   <ref>
                         * ...                                     */
                        prefixDataSize = 16;
                        pktSize = 0;

                        for (i = 0; i <= ((ext->maxMipLevel) >> 2); i++)
                        {
                            if (xyoffset[i] == 0)
                            {
                                prefixDataSize += 4 << 4;
                                pktSize++;
                            }
                        }
                        if (ext->sysMemPalSize)
                        {
                            prefixDataSize += 4 << 4;
                            pktSize++;
                        }

                        /* Allocate with both "raster" and "palette" on 128s */
                        if ((ext->sysMemPalSize) && !(palxyoffset))
                        {
                            rpRas->cpPixels = (RwUInt8 *) alignedMalloc(
                                                                           /* Prefix + alow to next 8qw */
                                                                           (prefixDataSize + 112)
                                                                           /* data rounded up to 8qw */
                                                                           +
                                                                           ((ext->sysMemSize + 127) & ~0x7f)
                                                                           /* palette rounded to cacheline */
                                                                           +
                                                                           ((ext->sysMemPalSize + 63) & ~63));
                        }
                        else
                        {
                            rpRas->cpPixels = (RwUInt8 *) alignedMalloc(
                                                                           /* Prefix + alow to next 8qw */
                                                                           (prefixDataSize + 112)
                                                                           /* data rounded up to cacheline */
                                                                           +
                                                                           ((ext->sysMemSize + ext->sysMemPalSize + 63) & ~0x3f));
                        }

                        if (!rpRas->cpPixels)
                        {
                            RWERROR((E_RW_NOMEM,
                                     (prefixDataSize + 112) +
                                     ((ext->sysMemSize + 127) & ~0x7f) +
                                     ((ext->sysMemPalSize +
                                       63) & ~0x3f)));
                            RWRETURN(FALSE);
                        }

                        ((RwUInt32 *) (rpRas->cpPixels))[0] = pktSize;
                        ((RwUInt8 **) (rpRas->cpPixels))[1] =
                            (RwUInt8
                             *) (((RwUInt32) rpRas->cpPixels + 16 +
                                  ((pktSize * 4) << 4) + 0x7f) & ~0x7f);
                        ((RwUInt32 *) (rpRas->cpPixels))[2] = pktSize;

                        /* If we have a palxyoffset, we will fix up later */
                        if ((ext->sysMemPalSize) && !(palxyoffset))
                        {
                            /* System memory pointer for palette */
                            rpRas->palette =
                                (RwUInt8
                                 *) ((((int) rpRas->cpPixels +
                                       prefixDataSize + 112) & ~0x7f) +
                                     ((ext->sysMemSize + 127) & ~0x7f));
                            /* rather nasty */
                            /* This points to the actual palette data, but */
                            /* valid packet data prefixes it */
                            rpRas->palette = rpRas->palette + (5 << 4);
                        }

                        /* Layout giftags etc */
                        data =
                            (u_long128
                             *) ((RwUInt8 **) (rpRas->cpPixels))[1];
                        data1 = (u_long128 *) (rpRas->cpPixels) + 1;

                        tmp = /* NLOOP */ 3l
                            | /* EOP */ ( ((RwUInt64)0) << 15)
                            | /* PRE */ ( ((RwUInt64)0) << 46)
                            | /* FLG */ ( ((RwUInt64)0) << 58)
                            | /* NREG */ ((RwUInt64) 1 << 60);
                        tmp1 = /* A+D */ (0xel << (64 - 64));

                        MAKE128(giftag, tmp1, tmp);

                        tmp = /* NLOOP */ 1l
                            | /* EOP */ ( ((RwUInt64)0) << 15)
                            | /* PRE */ ( ((RwUInt64)0) << 46)
                            | /* FLG */ ( ((RwUInt64)0) << 58)
                            | /* NREG */ ((RwUInt64) 1 << 60);
                        tmp1 = /* A+D */ (0xel << (64 - 64));

                        MAKE128(giftag1, tmp1, tmp);

                        w = rpRas->width;
                        h = rpRas->height;
                        for (i = 0; i <= ((ext->maxMipLevel) >> 2); i++)
                        {
                            int                 levelWidth, levelHeight;

                            levelWidth = w < minTW ? minTW : w;
                            levelHeight = h < minTH ? minTH : h;

                            *data++ = giftag;

                            if (((ext->flags & 2)
                                 && (((ext->lsb >> 20) & 0x3f) ==
                                     SCE_GS_PSMT8)) || ((ext->flags & 4)
                                                        &&
                                                        (((ext->
                                                           lsb >> 20) &
                                                          0x3f) ==
                                                         SCE_GS_PSMT4)))
                            {
                                /* Offsets are half */
                                tmp =
                                    (RwUInt64) (xyoffset[i] & ~0x10001)
                                    << 31;
                            }
                            else
                            {
                                tmp = (RwUInt64) xyoffset[i] << 32;
                            }
                            tmp1 = GS_TRXPOS;
                            MAKE128(ltmp, tmp1, tmp);
                            *data++ = ltmp;

                            if (((ext->flags & 2)
                                 && (((ext->lsb >> 20) & 0x3f) ==
                                     SCE_GS_PSMT8)) || ((ext->flags & 4)
                                                        &&
                                                        (((ext->
                                                           lsb >> 20) &
                                                          0x3f) ==
                                                         SCE_GS_PSMT4)))
                            {
                                /* Need to adjust for half size blocks */
                                tmp = (levelWidth >> 1)
                                    | (((RwUInt64) levelHeight >> 1) <<
                                       32);
                            }
                            else
                            {
                                tmp =
                                    levelWidth | ((RwUInt64) levelHeight
                                                  << 32);
                            }
                            tmp1 = GS_TRXREG;
                            MAKE128(ltmp, tmp1, tmp);
                            *data++ = ltmp;

                            tmp = 0;
                            tmp1 = GS_TRXDIR;
                            MAKE128(ltmp, tmp1, tmp);
                            *data++ = ltmp;

                            /* An image mode gif tag for the data */
                            tmp = ((((levelWidth * levelHeight
                                      * rpRas->depth) >> 3) + 15) >> 4)
                                | ((RwUInt64) 2 << 58);
                            pktSize = tmp & 0x7fff;
                            MAKE128(ltmp, 0, tmp);
                            *data++ = ltmp;

                            /* Build dma pkt data */
                            if (xyoffset[i] == 0)
                            {
                                tmp = (1l << 28) | 2l;
                                tmp1 =
                                    (RwUInt64) ((0x50l << 24) | 2l) <<
                                    32;
                                MAKE128(ltmp, tmp1, tmp);
                                *data1++ = ltmp;

                                *data1++ = giftag1;

                                if ((ext->flags & 2)
                                    && (((ext->lsb >> 20) & 0x3f) ==
                                        SCE_GS_PSMT8))
                                {
                                    tmp = ((widthBy64[i] & 0x3e) << 15)
                                        | (SCE_GS_PSMCT32 << 24)
                                        | (offsetBy64[i] << 32)
                                        | ((widthBy64[i] & 0x3e) << 47)
                                        | ((RwUInt64) SCE_GS_PSMCT32 <<
                                           56);
                                }
                                else if ((ext->flags & 4)
                                         && (((ext->lsb >> 20) & 0x3f)
                                             == SCE_GS_PSMT4))
                                {
                                    tmp = ((widthBy64[i] & 0x3e) << 15)
                                        | (SCE_GS_PSMCT16 << 24)
                                        | (offsetBy64[i] << 32)
                                        | ((widthBy64[i] & 0x3e) << 47)
                                        | ((RwUInt64) SCE_GS_PSMCT16 <<
                                           56);
                                }
                                else
                                {
                                    tmp = (widthBy64[i] << 16)
                                        | (((ext->lsb >> 20) & 0x3f) <<
                                           24) | (offsetBy64[i] << 32) |
                                        (widthBy64[i] << 48) |
                                        ((RwUInt64)
                                         ((ext->
                                           lsb >> 20) & 0x3f) << 56);
                                }
                                MAKE128(ltmp, GS_BITBLTBUF, tmp);
                                *data1++ = ltmp;

                                /* Build ref */
                                tmp = (3l << 28) | (pktSize + 5)
                                    | (((RwUInt64) (int) (data - 5)) <<
                                       32);
                                tmp1 =
                                    (RwUInt64) ((0x50l << 24) |
                                                (pktSize + 5)) << 32;
                                MAKE128(ltmp, tmp1, tmp);
                                *data1++ = ltmp;
                            }
                            else
                            {
                                /* Inc qwc in previous ref tag */
                                tmp = *(RwUInt32 *) (data1 - 1);
                                tmp =
                                    (3l << 28) | ((tmp & 0xffff) +
                                                  (pktSize + 5));
                                *(RwUInt32 *) (data1 - 1) = tmp;

                                tmp = *(((RwUInt32 *) data1) - 1);
                                tmp = (0x50l << 24)
                                    | ((tmp & 0xffff) + (pktSize + 5));
                                *(((RwUInt32 *) data1) - 1) = tmp;
                            }

                            /* Skip the actual data */
                            data += pktSize;

                            w >>= 1;
                            h >>= 1;
                        }

                        if (ext->sysMemPalSize)
                        {
                            if (palxyoffset)
                            {
                                /* Palette pkt follows mip levels. Pointer
                                 * is set to actual data */
                                rpRas->palette = (RwUInt8 *) (data + 5);
                            }

                            /* Add tags for palette */
                            data = (u_long128 *) (rpRas->palette) - 5;
                            *data++ = giftag;

                            tmp1 = GS_TRXPOS;
                            MAKE128(ltmp, tmp1, palxyoffset);
                            *data++ = ltmp;

                            tmp =
                                palWidth | ((RwUInt64) palHeight << 32);
                            tmp1 = GS_TRXREG;
                            MAKE128(ltmp, tmp1, tmp);
                            *data++ = ltmp;

                            tmp = 0;
                            tmp1 = GS_TRXDIR;
                            MAKE128(ltmp, tmp1, tmp);
                            *data++ = ltmp;

                            /* An image mode gif tag for the data */
                            tmp =
                                ((palWidth * palHeight *
                                  bytesPerPalPixel +
                                  15) >> 4) | ((RwUInt64) 2 << 58);
                            MAKE128(ltmp, 0, tmp);
                            *data++ = ltmp;
                            pktSize = tmp & 0x7fff;

                            tmp = (1l << 28) | 2l;
                            tmp1 =
                                (RwUInt64) ((0x50l << 24) | 2l) << 32;
                            MAKE128(ltmp, tmp1, tmp);
                            *data1++ = ltmp;

                            *data1++ = giftag1;

                            if (palxyoffset)
                            {
                                /* Nick the bitbltbuf reg value from the
                                 * last one */
                                *data1 = *(data1 - 4);
                                data1++;

                                /* Dec pktsize by 1. We have built the upload
                                 * pkt so that we have the option of uploading
                                 * the palette on its own. */
                                ((RwUInt32 *) (rpRas->cpPixels))[0]--;

                                /* Add to previous ref */
                                tmp = *(RwUInt32 *) (data1 - 4);
                                tmp =
                                    (3l << 28) | ((tmp & 0xffff) +
                                                  (pktSize + 5));
                                *(RwUInt32 *) (data1 - 4) = tmp;

                                tmp = *(((RwUInt32 *) (data1 - 3)) - 1);
                                tmp = (0x50l << 24)
                                    | ((tmp & 0xffff) + (pktSize + 5));
                                *(((RwUInt32 *) (data1 - 3)) - 1) = tmp;
                            }
                            else
                            {
                                tmp = (1l << 16)
                                    |
                                    ((RwUInt64)
                                     ((ext->
                                       msb >> (51 -
                                               32)) & 0xf) << 24) |
                                    ((RwUInt64) ext->
                                     palOffset << 32) | ((RwUInt64) 1l
                                                         << 48) |
                                    ((RwUInt64)
                                     ((ext->
                                       msb >> (51 - 32)) & 0xf) << 56);
                                MAKE128(ltmp, GS_BITBLTBUF, tmp);
                                *data1++ = ltmp;
                            }

                            /* Build ref */
                            tmp = (3l << 28) | (pktSize + 5)
                                | (((RwUInt64) (int) (data - 5)) << 32);
                            tmp1 =
                                (RwUInt64) ((0x50l << 24) |
                                            (pktSize + 5)) << 32;
                            MAKE128(ltmp, tmp1, tmp);
                            *data1++ = ltmp;
                        }
                    }
                    else
#endif /* ALTTEXFORM */
                    {
                        /* Revert to old code */

                        /* Allocate space (for pixels and palette) */
                        rpRas->cpPixels =
                            (RwUInt8 *) alignedMalloc(ext->sysMemSize +
                                                      ext->
                                                      sysMemPalSize);

                        if (!rpRas->cpPixels)
                        {
                            RWERROR((E_RW_NOMEM,
                                     ext->sysMemSize +
                                     ext->sysMemPalSize));
                            RWRETURN(FALSE);
                        }

                        if (ext->sysMemPalSize)
                        {
                            /* System memory pointer for palette */
                            rpRas->palette =
                                rpRas->cpPixels + ext->sysMemSize;
                        }

#ifdef TWIDDLEEIGHT
                        /* Permit old style textures to be twiddled too */
                        if (rpRas->depth == 8)
                        {
                            ext->flags |= 2;
                        }
#endif

                        //skyPrepareUploadRaster(rpRas);
                    }

                    rpRas->originalPixels = rpRas->cpPixels;
                    rpRas->originalStride = rpRas->stride;

                    if (ext->flags & 1)
                    {
                        /* Need to adjust cpPixels */
                        rpRas->cpPixels = (RwUInt8 *)
                            ((u_long128
                              *) ((RwUInt8 **) (rpRas->cpPixels))[1] +
                             5);
                    }

                    break;
                }
            case rwRASTERTYPENORMAL:
                {
                    RwUInt32            lastMapPages, lastMapPageWidth,
                        lastMapPageHeight;
                    RwUInt32            pageWidth, pageHeight;

                    pageWidth = rasterPageWidths[rpRas->depth - 1];
                    pageHeight = rasterPageHeights[rpRas->depth - 1];

                    /* Set up the stride */
                    rpRas->stride = (rpRas->depth * rpRas->width) >> 3;

                    /* Doesn't hurt to fill this in */
                    ext->sysMemSize = rpRas->height * rpRas->stride;

                    /* Round up to next page size in video memory */
                    lastMapPageWidth =
                        (rpRas->width + (pageWidth - 1)) / pageWidth;
                    lastMapPageHeight =
                        (rpRas->height + (pageHeight - 1)) / pageHeight;
                    lastMapPages = lastMapPageWidth * lastMapPageHeight;
                    ext->nTexCacheSize = lastMapPages * 2048;

                    if (!
                        (rpRas->
                         cFlags & (RwUInt8) rwRASTERDONTALLOCATE))
                    {
                        /* Allocate space */
#if 0
                        rpRas->cpPixels =
                            (RwUInt8 *) RwMalloc(ext->sysMemSize);
#else
                        rpRas->cpPixels =
                            (RwUInt8 *) alignedMalloc(ext->sysMemSize);
#endif

                        if (!rpRas->cpPixels)
                        {
                            RWERROR((E_RW_NOMEM, ext->sysMemSize));
                            RWRETURN(FALSE);
                        }
                    }
                    else
                    {
                        rpRas->cpPixels = (unsigned char *) NULL;
                    }

                    rpRas->originalPixels = rpRas->cpPixels;
                    rpRas->originalStride = rpRas->stride;

                    break;
                }
            case rwRASTERTYPEZBUFFER:

                {
                    rpRas->stride = 0;
                    rpRas->cpPixels = (unsigned char *) NULL;
                    rpRas->cFlags = (RwUInt8) rwRASTERDONTALLOCATE;

                    rpRas->originalPixels = rpRas->cpPixels;
                    rpRas->originalStride = rpRas->stride;

                    break;
                }
            case rwRASTERTYPECAMERA:
                {
                    rpRas->stride = 0;
                    rpRas->cpPixels = (unsigned char *) NULL;

                    rpRas->originalPixels = rpRas->cpPixels;
                    rpRas->originalStride = rpRas->stride;

                    rpRas->cFlags = (RwUInt8) rwRASTERDONTALLOCATE;
                    break;
                }
            default:
                {
                    RWRETURN(FALSE);
                }
        }
    }
    else
    {
        rpRas->cFlags = (RwUInt8) rwRASTERDONTALLOCATE; /* Not allocated */
        rpRas->stride = 0;
        rpRas->originalStride = rpRas->stride;
    }

    /* Zero pending ref cont */
    RASTEREXTFROMRASTER(rpRas)->dmaRefCount = 0;
    RASTEREXTFROMRASTER(rpRas)->dmaClrCount = 0;

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyRasterSubRaster

 On entry   : Raster (OUT)
            : Raster (IN)
            : None
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterSubRaster(void *pRas, void *pIn, RwInt32 __RWUNUSED__ nIn)
{
    RwRaster           *rpRas = (RwRaster *) pRas;
    RwRaster           *rpIn = (RwRaster *) pIn;
    RwRaster           *pixelOwner = rpIn->parent;

    RWFUNCTION(RWSTRING("SkyRasterSubRaster"));

    /* It won't get this far if rwRASTERDONTALLOCATE is not set
     * in the raster - see check in RwRasterSubRaster().
     */

    /* Core already set up offset and size */

    /* Can't sub raster textures because we need the alignment for DMA
     * purposes.
     */

    /* Inherit some stuff */
    rpRas->cFormat = rpIn->cFormat;
    rpRas->stride = rpIn->stride;
    rpRas->depth = rpIn->depth;

    /* If we are trying to subraster a camera into a camera texture then ensure that alignment */
    /* is valid and create the appropriate register settings */
    if ((rpIn->cType & rwRASTERTYPECAMERA)
        && (rpRas->cType & rwRASTERTYPECAMERATEXTURE))
    {
        /* Adjust bounding box to fall on a valid rectangle */
        RwInt32             nAdjust;

        /* Make sure we don't even consider trying to upload this */
        rpRas->cType = rpIn->cType | (RwUInt8) rwRASTERDONTALLOCATE;

        /* Start X on the previous 64 pixel boundary */
        nAdjust = rpRas->nOffsetX & ((1 << 6) - 1);
        rpRas->nOffsetX -= (short) nAdjust;
        rpRas->width += nAdjust;

        /* Make width a power of two */
        nAdjust =
            rpRas->width & ((1 << _rwSkyFindMSB(rpRas->width)) - 1);
        if (nAdjust)
        {
            rpRas->width = (rpRas->width - nAdjust) << 1;
        }

        /* If we are now overrunning the buffer then move X back more */
        nAdjust = (rpRas->nOffsetX + rpRas->width) - rpIn->width;
        if (nAdjust > 0 && nAdjust < rpRas->nOffsetX)
        {
            rpRas->nOffsetX -= (short) nAdjust;
        }

        /* Start Y on the previous 32/64 pixel boundary depending on pixel format */
        nAdjust = rpRas->nOffsetY & ((320 / (rpIn->stride >> 8)) - 1);
        rpRas->nOffsetY -= (short) nAdjust;
        rpRas->height += nAdjust;

        /* Make width a power of two */
        nAdjust =
            rpRas->height & ((1 << _rwSkyFindMSB(rpRas->height)) - 1);
        if (nAdjust)
        {
            rpRas->height = (rpRas->height - nAdjust) << 1;
        }

        /* If we are now overrunning the buffer then move Y back more */
        nAdjust = (rpRas->nOffsetY + rpRas->height) - rpIn->height;
        if (nAdjust > 0 && nAdjust < rpRas->nOffsetY)
        {
            rpRas->nOffsetY -= (short) nAdjust;
        }

        /* Setup a valid set of tex registers for this new texture ! */
        {
            _SkyRasterExt      *rasExt = RASTEREXTFROMRASTER(rpRas);

            /* Tex0 - TBP0 - Note that we don't know which buffer will be used so just provide the offset */
            /* looks odd. RE */
            rasExt->lsb =
                (((rpRas->nOffsetX & 0xfffl) >> 1) +
                 (rpRas->nOffsetY * (rpIn->stride >> 8))) & 0x1ff;
            /* Tex0 - TBW */
            //rasExt->lsb |=  ((skyFrame_1>>16)&0x3f)<<14;
            /* Tex0 - PSM */
            //rasExt->lsb |= ((skyFrame_1>>24)&0x3f)<<20;
            /* Tex0 - TW */
            rasExt->lsb |= (_rwSkyFindMSB(rpRas->width) & 0xf) << 26;
            /* Tex0 - TH */
            rasExt->lsb |= (_rwSkyFindMSB(rpRas->height) & 0xf) << 30;
            rasExt->msb |= (_rwSkyFindMSB(rpRas->height) & 0xf) >> 2;
            /* Tex0 - TCC */
            rasExt->msb |= 0l << (34 - 32); /* Use Alpha from TexA register */
            /* Tex0 - TFX */
            rasExt->msb |= 0l << (35 - 32); /* MODULATE */
#if defined(GSB) && defined(GSPLUS)
            rasExt->lsb3 =
                (((rpRas->nOffsetX & 0xfffl) >> 1) +
                 (rpRas->nOffsetY * (rpIn->stride >> 8))) & 0xfff;
            rasExt->msb3 = 0;
#endif /* defined(GSB) && defined(GSPLUS) */
        }
    }
    else
    {
        /* Normal case is just a copy */
        rpRas->cType = rpIn->cType;
    }

    rpRas->cpPixels = (pixelOwner->cpPixels) +
        (pixelOwner->stride * rpRas->nOffsetY) +
        ((rpRas->nOffsetX * ((pixelOwner->depth + 7))) >> 3);

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyRasterDestroy

 On entry   : NULL
            : Raster to destroy
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterDestroy(void *__RWUNUSED__ pOut, void *pRaster,
                 RwInt32 __RWUNUSED__ nIn)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;

    RWFUNCTION(RWSTRING("SkyRasterDestroy"));

    //skyTexCacheReleaseRaster(rpRas);

#ifdef SHOWUPLOADEDTEXTURES
    {
        RwInt32             nIndex;

        /* Find a this texture */
        for (nIndex = 0; nIndex < SHOWUPLOADEDTEXTUREMAXTEXTURES;
             nIndex++)
        {
            if (rpShowUploadedRasters[nIndex] == rpRas)
            {
                printf("Removing Texture %s\n",
                       RwTextureGetName(tpShowUploadedTextures
                                        [nIndex]));
                tpShowUploadedTextures[nIndex] = NULL;
                rpShowUploadedRasters[nIndex] = NULL;
                break;
            }
        }
    }
#endif

    if (!(rpRas->cFlags & (RwUInt8) rwRASTERDONTALLOCATE))
    {
        _SkyRasterExt      *rasExt = RASTEREXTFROMRASTER(rpRas);

        RWASSERT(0 <= rasExt->dmaRefCount);

#if 0
        if (rasExt->dmaRefCount == 0)
        {
#endif
            if (rpRas->originalPixels)
            {
#if 0
                RwFree(rpRas->originalPixels);
#else
                alignedFree((char *)(rpRas->originalPixels));
#endif
            }
#if 0
        }
        else
        {
            /* We need to defer the delete */
            /* This is a bit sneaky */
            /* We want to call free with this, so don't pass CIRCALLOC flag */
            _sweAddPkt(rpRas->originalPixels,
                       SWE_PKT_NULL | SWE_PKT_LOCAL);
        }
#endif

        {
            RwInt32             level;
            _SkyRasterExt      *rasExt = RASTEREXTFROMRASTER(rpRas);

            RWASSERT(0 <= rasExt->dmaRefCount);

#if 0
            if (rasExt->dmaRefCount == 0)
            {
#endif
                if (rasExt->palUploadPkt)
                {
                    RwFree(rasExt->palUploadPkt);
                    rasExt->palUploadPkt = (u_long128 *) NULL;
                }
                for (level = 0; level < 7; level++)
                {
                    if (rasExt->mipUploadPkts[level])
                    {
                        RwFree(rasExt->mipUploadPkts[level]);
                        rasExt->mipUploadPkts[level] =
                            (u_long128 *) NULL;
                    }
                }
#if 0
            }
            else
            {
                /* We need to defer the delete */
                /* This is a bit sneaky */
                /* We want to call free with this, so don't pass CIRCALLOC flag */
                if (rasExt->palUploadPkt)
                {
                    _sweAddPkt(rasExt->palUploadPkt,
                               SWE_PKT_NULL | SWE_PKT_LOCAL);
                    rasExt->palUploadPkt = (u_long128 *) NULL;
                }
                for (level = 0; level < 7; level++)
                {
                    if (rasExt->mipUploadPkts[level])
                    {
                        _sweAddPkt(rasExt->mipUploadPkts[level],
                                   SWE_PKT_NULL | SWE_PKT_LOCAL);
                        rasExt->mipUploadPkts[level] =
                            (u_long128 *) NULL;
                    }
                }
            }
#endif
        }
    }

    RWRETURN(TRUE);
}

/* These macros are somewhat missnamed, as you pass in the location in
   a 32 (or 16) bit block and are returned the location in the source
   4, 8 or 16 bit block */

#define EvenColumn8to32(A)   \
        (((((A) & 2) << 2)   \
          |(((A) & 4) >> 2)  \
          |(((A) & 8) >> 2)  \
          |(((A) &16) >> 2)  \
          |(((A) &32) >> 1)) \
         ^((((A) & 1) << 5)  \
          |(((A) & 1) << 2)))

#define OddColumn8to32(A)    \
        (((((A) & 2) << 2)   \
          |(((A) & 4) >> 2)  \
          |(((A) & 8) >> 2)  \
          |(((A) &16) >> 2)  \
          |(((A) &32) >> 1)) \
         ^((((A) & 1) << 5)  \
          |((~(A)& 1) << 2)))

#define Location16to32(A)    \
        ((((A) & 2) >> 1)    \
         |(((A) & 1) << 3)  \
         |(((A) & 4) >> 1)  \
         |(((A) & 8) >> 1)  \
         |(((A) &16)))

#define EvenColumn4to32(A)   \
        (((((A) & 2) << 2)   \
          |(((A) & 4) << 2)  \
          |(((A) & 8) >> 3)  \
          |(((A) &16) >> 3)  \
          |(((A) &32) >> 3)  \
          |(((A) &64) >> 1)) \
         ^((((A) & 1) << 6)  \
          |(((A) & 1) << 2)))

#define OddColumn4to32(A)    \
        (((((A) & 2) << 2)   \
          |(((A) & 4) << 2)  \
          |(((A) & 8) >> 3)  \
          |(((A) &16) >> 3)  \
          |(((A) &32) >> 3)  \
          |(((A) &64) >> 1)) \
         ^((((A) & 1) << 6)  \
          |((~(A)& 1) << 2)))

#define EvenColumn4to16(A)   \
        (((((A) & 2) << 2)   \
          |(((A) &32) >> 1)  \
          |(((A) & 4) >> 2)  \
          |(((A) & 8) >> 2)  \
          |(((A) &16) >> 2)  \
          |(((A) &64) >> 1)) \
         ^((((A) & 1) << 6)  \
          |(((A) & 1) << 2)))

#define OddColumn4to16(A)    \
        (((((A) & 2) << 2)   \
          |(((A) &32) >> 1)  \
          |(((A) & 4) >> 2)  \
          |(((A) & 8) >> 2)  \
          |(((A) &16) >> 2)  \
          |(((A) &64) >> 1)) \
         ^((((A) & 1) << 6)  \
          |((~(A)& 1) << 2)))

/****************************************************************************
 SkyRasterLock

 On entry   : Pixel pointer
            : raster
            : Flags
 On exit    : TRUE on success
 */
#if 0
#if defined(GSB) && defined(GSPLUS)
static sceGsPlusStoreImage skySis __attribute__ ((aligned(64)));
#else /* defined(GSB) && defined(GSPLUS) */
static sceGsStoreImage skySis __attribute__ ((aligned(64)));
#endif /* defined(GSB) && defined(GSPLUS) */
#endif

static              RwBool
SkyRasterLock(void *pPixels, void *pRaster, RwInt32 flags)
{
    RwUInt8           **cppPixels = (RwUInt8 **) pPixels;
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwUInt8             mipLevel =
        (RwUInt8) ((flags & (RwInt32) 0xFF00) >> 8);
    _SkyRasterExt      *ext;
    RwUInt8             currentLevel;

    RWFUNCTION(RWSTRING("SkyRasterLock"));

    flags = flags & 0xFF;

    /* currently nofetch has no effect on the sky2 driver */
    flags = flags & ~rwRASTERLOCKNOFETCH;

    /* Can't lock Z buffer raster */
    switch (rpRas->cType & rwRASTERTYPEMASK)
    {
        case rwRASTERTYPECAMERA:
            {
                RWERROR((E_RW_INVRASTERLOCKREQ));
                RWRETURN(FALSE);
            }
        case rwRASTERTYPEZBUFFER:
            {
                RWERROR((E_RW_INVRASTERLOCKREQ));
                RWRETURN(FALSE);
            }

        default:
            {
                break;
            }
    }

    ext = RASTEREXTFROMRASTER(rpRas);
    if (mipLevel > ((ext->maxMipLevel) >> 2))
    {
        RWERROR((E_RW_INVRASTERMIPLEVEL));
        RWRETURN(FALSE);
    }

    if (flags & rwRASTERLOCKWRITE)
    {
        /* Kick it out of cache so it gets updated */
        //skyTexCacheReleaseRaster(rpRas);
    }

#if 0
    /* Initialised in RasterCreate */
    rpRas->originalPixels = rpRas->cpPixels;
    rpRas->originalWidth = rpRas->width;
    rpRas->originalHeight = rpRas->height;
    rpRas->originalStride = rpRas->stride;
#endif

    if (!(ext->flags & 1))
    {
        for (currentLevel = 0; currentLevel < mipLevel; currentLevel++)
        {
            rpRas->stride = (rpRas->depth * rpRas->width) >> 3;
            rpRas->cpPixels =
                (RwUInt8 *) (((RwUInt32) (rpRas->cpPixels) + 15) & ~15);
            rpRas->cpPixels += (rpRas->stride * rpRas->height);
            rpRas->width = rpRas->width >> 1;
            rpRas->height = rpRas->height >> 1;
        }
        rpRas->cpPixels =
            (RwUInt8 *) (((RwUInt32) (rpRas->cpPixels) + 15) & ~15);
        rpRas->stride = (rpRas->depth * rpRas->width) >> 3;
    }
    else
    {
        int                 minTW, minTH, w, h;

        /* we need to skip over all the inlined stuff */
        skyTransferMinSize(((ext->lsb >> 20) & 0x3f), ext->flags,
                           &minTW, &minTH);
        w = rpRas->width;
        h = rpRas->height;
        /* Initial cpPixels points to mip 0 data */
        /* add space for each mip level's data */
        for (currentLevel = 0; currentLevel < mipLevel; currentLevel++)
        {
            int                 levelWidth, levelHeight;

            /* skip data */
            levelWidth = w < minTW ? minTW : w;
            levelHeight = h < minTH ? minTW : h;
            rpRas->cpPixels +=
                (((levelWidth * levelHeight * rpRas->depth) >> 3) +
                 15) & ~0xf;
            /* skip inline data */
            rpRas->cpPixels += (5 << 4);
            w >>= 1;
            h >>= 1;
        }
        rpRas->stride = (rpRas->depth * (w < minTW ? minTW : w)) >> 3;
        rpRas->width = w;
        rpRas->height = h;

    }

    if (flags & ((RwInt32) rwRASTERLOCKREAD))
    {
        /* We may need to twiddle outgoing data */
        if ((ext->flags & 2)
            && (((ext->lsb >> 20) & 0x3f) == SCE_GS_PSMT8))
        {
            /* Need a scan buffer that is width*4 in size */
            /* max width is 1024, so 4K is required */
            RwUInt8             buf[4096];
            int                 i, j, k, l, x, y;
            u_long128           column[4];
            RwUInt8            *src;

            for (y = 0; y < rpRas->height; y += 4)
            {
                src = (RwUInt8 *) column;
                for (x = 0; x < rpRas->width; x += 16)
                {
                    column[0] = *(u_long128 *) (rpRas->cpPixels
                                                + (y * rpRas->stride)
                                                + (x * 2));
                    column[1] = *(u_long128 *) (rpRas->cpPixels
                                                + (y * rpRas->stride)
                                                + (x * 2) + 16);
                    column[2] = *(u_long128 *) (rpRas->cpPixels
                                                +
                                                ((y +
                                                  2) * rpRas->stride) +
                                                (x * 2));
                    column[3] =
                        *(u_long128 *) (rpRas->cpPixels +
                                        ((y + 2) * rpRas->stride) +
                                        (x * 2) + 16);
                    for (j = 0; j < 64; j += 16)
                    {
                        for (k = 0; k < 16; k++)
                        {
                            if (y & 4)
                            {
                                l = OddColumn8to32(j + k);
                            }
                            else
                            {
                                l = EvenColumn8to32(j + k);
                            }
                            buf[x + (l & 0xf) + ((l >> 4) << 10)] =
                                src[j + k];
                        }
                    }
                }
                /* Copy back into the raster */
                /* Copy a 4 pixel high stripe */
                for (i = 0; i < 4; i++)
                {
                    for (x = 0; x < rpRas->width; x += 16)
                    {
                        *(u_long128 *) (rpRas->cpPixels +
                                        ((y + i) * rpRas->stride) + x) =
                            *(u_long128 *) (buf + i * 1024 + x);
                    }
                }
            }
        }
        else if ((ext->flags & 4)
            && (((ext->lsb>>20)&0x3f) == SCE_GS_PSMT4)
            && (rpRas->stride >= 16))
        {
            /* Need a scan buffer that is width*4*depth in size */
            /* max width is 1024, so 2K is required */
            RwUInt8 buf[2048];
            int i, j, k, l, x, y;
            u_long128 column[4];
            RwUInt8 *src;

            for (y = 0; y < rpRas->height; y += 4)
            {
                src = (RwUInt8*)column;
                for (x=0; x<rpRas->width; x+= 32)
                {
                    column[0] = *(u_long128*)(rpRas->cpPixels
                                              +(y*rpRas->stride)
                                              +(x));
                    column[1] = *(u_long128*)(rpRas->cpPixels
                                              +(y*rpRas->stride)
                                              +(x)+16);
                    column[2] = *(u_long128*)(rpRas->cpPixels
                                              +((y+2)*rpRas->stride)
                                              +(x));
                    column[3] = *(u_long128*)(rpRas->cpPixels
                                              +((y+2)*rpRas->stride)
                                              +(x)+16);
                    /* Slightly anoying: We need to clear down buf */
                    *(RwUInt64*)&(buf[x>>1]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+8]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+512]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+512+8]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+1024]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+1024+8]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+1536]) = 0;
                    *(RwUInt64*)&(buf[(x>>1)+1536+8]) = 0;

                    for (j=0; j<128; j += 32)
                    {
                        for (k=0; k<32; k++)
                        {
                            if (y & 4)
                            {
                                l = OddColumn4to16(j+k);
                            }
                            else
                            {
                                l = EvenColumn4to16(j+k);
                            }
                            if (l&1)
                            {
                                buf[(x+(l&0x1f)+((l>>5)<<10))>>1]
                                             |= (k&1)?(src[(j+k)>>1]&0xf0)
                                                      :(src[(j+k)>>1]&0xf)<<4;
                            }
                            else
                            {
                                buf[(x+(l&0x1f)+((l>>5)<<10))>>1]
                                             |= (k&1)?((src[(j+k)>>1] &0xf0)>>4)
                                                     :src[(j+k)>>1]&0xf;
                            }
                        }
                    }
                }
                /* Copy back into the raster */
                /* Copy a 4 pixel high stripe */
                for (i=0; i<4; i++)
                {
                    for (x = 0; x< (rpRas->width)>>1; x+= (32>>1))
                    {
                        *(u_long128*)(rpRas->cpPixels+((y+i)*rpRas->stride) +x)
                                            = *(u_long128*)(buf+i*512+x);
                    }
                }
            }
        }
    }

    (*cppPixels) = rpRas->cpPixels;
    ext->lockedMipLevel = mipLevel;

    if (flags & rwRASTERLOCKREAD)
    {
        rpRas->privateFlags |= rwRASTERPIXELLOCKEDREAD;
    }
    if (flags & rwRASTERLOCKWRITE)
    {
        rpRas->privateFlags |= rwRASTERPIXELLOCKEDWRITE;
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyRasterUnlock

 On entry   : NULL
            : Raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterUnlock(void *__RWUNUSED__ pInOut, void *pRaster,
                RwInt32 __RWUNUSED__ flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;

    RWFUNCTION(RWSTRING("SkyRasterUnlock"));

    if (!(rpRas->privateFlags & rwRASTERPIXELLOCKED))
    {
        RWRETURN(FALSE);
    }

    switch (rpRas->cType & rwRASTERTYPEMASK)
    {
        case rwRASTERTYPECAMERA:
        case rwRASTERTYPECAMERATEXTURE:
        case rwRASTERTYPEZBUFFER:
            {
                /* SyncDCache to flush any changes to the pixels */
                if (rpRas->cpPixels)
                {
#if 0
                    SyncDCache(rpRas->cpPixels,
                               SCESYNCDCACHEROUNDUP(rpRas->cpPixels +
                                                    ((rpRas->width
                                                      * rpRas->height
                                                      * rpRas->depth) /
                                                     8)));
#endif
                }
                /* Only have mipLevel 0 so values are not buffered */
                break;
            }
        default:
            {
                const _SkyRasterExt *rasExt =
                    RASTEREXTFROMRASTER(rpRas);

                /* SyncDCache to flush any changes to the pixels */
                if (rpRas->cpPixels)
                {
                    /* We may need to twiddle incomming data */
                    if ((rasExt->flags & 2)
                        && (((rasExt->lsb >> 20) & 0x3f) ==
                            SCE_GS_PSMT8))
                    {
                        /* Need a scan buffer that is width*4 in size */
                        /* max width is 1024, so 4K is required */
                        RwUInt8             buf[4096];
                        int                 i, j, k, l, x, y;
                        u_long128           column[4];
                        RwUInt8            *dst;

                        for (y = 0; y < rpRas->height; y += 4)
                        {
                            /* Copy a 4 pixel high stripe */
                            for (i = 0; i < 4; i++)
                            {
                                for (x = 0; x < rpRas->width; x += 16)
                                {
                                    *(u_long128 *) (buf + i * 1024 +
                                                    x) =
                                        *(u_long128 *) (rpRas->
                                                        cpPixels +
                                                        ((y +
                                                          i) *
                                                         rpRas->
                                                         stride) + x);
                                }
                            }
                            /* now copy back. Note that the 32 bit */
                            /* texture is 2*width in memory */
                            dst = (RwUInt8 *) column;
                            for (x = 0; x < rpRas->width; x += 16)
                            {
                                for (j = 0; j < 64; j += 16)
                                {
                                    for (k = 0; k < 16; k++)
                                    {
                                        if (y & 4)
                                        {
                                            l = OddColumn8to32(j + k);
                                        }
                                        else
                                        {
                                            l = EvenColumn8to32(j + k);
                                        }
                                        dst[j + k] =
                                            buf[x + (l & 0xf) +
                                                ((l >> 4) << 10)];
                                    }
                                }
                                /* Copy back into the raster */
                                *(u_long128 *) (rpRas->cpPixels
                                                + (y * rpRas->stride)
                                                + (x * 2)) = column[0];
                                *(u_long128 *) (rpRas->cpPixels
                                                + (y * rpRas->stride)
                                                + (x * 2) + 16) =
                                    column[1];
                                *(u_long128 *) (rpRas->cpPixels +
                                                ((y +
                                                  2) * rpRas->stride) +
                                                (x * 2)) = column[2];
                                *(u_long128 *) (rpRas->cpPixels +
                                                ((y +
                                                  2) * rpRas->stride) +
                                                (x * 2) + 16) =
                                    column[3];
                            }
                        }
                    }
                    else if ((rasExt->flags & 4)
                        && (((rasExt->lsb>>20)&0x3f) == SCE_GS_PSMT4)
                        && (rpRas->stride >= 16))
                    {
                        /* Need a scan buffer that is depth*width*4 in size */
                        /* max width is 1024, so 2K is required */
                        RwUInt8 buf[2048];
                        int i, j, k, l, x, y;
                        u_long128 column[4];
                        RwUInt8 *dst;

                        for (y = 0; y < rpRas->height; y += 4)
                        {
                            /* Copy a 4 pixel high stripe */
                            for (i=0; i<4; i++)
                            {
                                for (x = 0; x< (rpRas->width)>>1; x+= (32>>1))
                                {
                                    *(u_long128*)(buf+i*512+x) =
                                       *(u_long128*)(rpRas->cpPixels
                                                     +((y+i)*rpRas->stride)
                                                     +x);
                                }
                            }
                            /* No need to clear down dst as we always write
                               bottom 4 bits first */
                            /* now copy back. Note that the 16 bit */
                            /* texture is 2*width in memory */
                            dst = (RwUInt8*)column;
                            for (x=0; x<rpRas->width; x+= 32)
                            {
                                for (j=0; j<128; j += 32)
                                {
                                    for (k=0; k<32; k++)
                                    {
                                        if (y & 4)
                                        {
                                            l = OddColumn4to16(j+k);
                                        }
                                        else
                                        {
                                            l = EvenColumn4to16(j+k);
                                        }
                                        if (k&1)
                                        {
                                            dst[(j+k)>>1]
                                                |= l&1 ?
                                                   buf[(x+(l&0x1f)
                                                         +((l>>5)<<10))
                                                        >>1]&0xf0
                                                   :(buf[(x+(l&0x1f)
                                                         +((l>>5)<<10))>>1]&0xf)
                                                    <<4;
                                        }
                                        else
                                        {
                                            dst[(j+k)>>1]
                                                = l&1 ?
                                                   (buf[(x+(l&0x1f)
                                                         +((l>>5)<<10))
                                                        >>1]>>4)&0xf
                                                   :buf[(x+(l&0x1f)
                                                         +((l>>5)<<10))>>1]&0xf;
                                        }
                                    }
                                }
                                /* Copy back into the raster */
                                *(u_long128*)(rpRas->cpPixels
                                              +(y*rpRas->stride)
                                              +(x)) = column[0];
                                *(u_long128*)(rpRas->cpPixels
                                              +(y*rpRas->stride)
                                              +(x)+16) = column[1];
                                *(u_long128*)(rpRas->cpPixels
                                              +((y+2)*rpRas->stride)
                                              +(x)) = column[2];
                                *(u_long128*)(rpRas->cpPixels
                                              +((y+2)*rpRas->stride)
                                              +(x)+16) = column[3];
                            }
                        }
                    }

#if 0
                    SyncDCache(rpRas->cpPixels,
                               SCESYNCDCACHEROUNDUP(rpRas->cpPixels +
                                                    ((rpRas->width
                                                      * rpRas->height
                                                      * rpRas->depth) /
                                                     8)));
#endif
                }
                /* restore mipLevel 0 settings */
                rpRas->width = rpRas->originalWidth;
                rpRas->height = rpRas->originalHeight;
                rpRas->stride = rpRas->originalStride;
                rpRas->cpPixels = rpRas->originalPixels;
                if (rasExt->flags & 1)
                {
                    /* new format raster needs cpPixels adjusted */
                    /* Need to adjust cpPixels */
                    rpRas->cpPixels = (RwUInt8 *)
                        ((u_long128
                          *) ((RwUInt8 **) (rpRas->cpPixels))[1] + 5);
                }
            }
    }

    if ((rpRas->cFormat & (rwRASTERFORMATMIPMAP >> 8)) &&
        (rpRas->cFormat & (rwRASTERFORMATAUTOMIPMAP >> 8)) &&
        (rpRas->privateFlags & rwRASTERPIXELLOCKEDWRITE))
    {
        rpRas->privateFlags =
            rpRas->privateFlags & ~rwRASTERPIXELLOCKED;
        RwTextureRasterGenerateMipmaps(rpRas, (RwImage *) NULL);
    }
    else
    {
        rpRas->privateFlags =
            rpRas->privateFlags & ~rwRASTERPIXELLOCKED;
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyRasterLockPalette

 On entry   : Pixel pointer
            : raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterLockPalette(void *pPalette, void *pRaster, RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;

    RWFUNCTION(RWSTRING("SkyRasterLockPalette"));

    /* Can only do this if we have a palette */
    if (rpRas->
        cFormat & ((rwRASTERFORMATPAL4 | rwRASTERFORMATPAL8) >> 8))
    {
        RwUInt8           **cppPalette = (RwUInt8 **) pPalette;

        /*if ((flags == rwRASTERLOCKWRITE) ||
         * (flags == rwRASTERLOCKREADWRITE)) */
        /* Now done as bits specifically, so test for write bit */
        if (flags & rwRASTERLOCKWRITE)
        {
            /* Kick it out of cache so it gets updated */
            //skyTexCacheReleaseRaster(rpRas);
        }

        (*cppPalette) = rpRas->palette;
        if (flags & rwRASTERLOCKWRITE)
        {
            rpRas->privateFlags |= rwRASTERPALETTELOCKEDWRITE;
        }
        if (flags & rwRASTERLOCKREAD)
        {
            rpRas->privateFlags |= rwRASTERPALETTELOCKEDREAD;
        }

        RWRETURN(TRUE);
    }

    RWRETURN(FALSE);
}

/****************************************************************************
 SkyRasterUnlockPalette

 On entry   : NULL
            : Raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterUnlockPalette(void *__RWUNUSED__ pInOut,
                       void *pRaster, RwInt32 __RWUNUSED__ flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwRasterFormat      format;

    RWFUNCTION(RWSTRING("SkyRasterUnlockPalette"));

    format = (RwRasterFormat) RwRasterGetFormat(rpRas);

    /* One day we will have to do stuff on texture unlock */

    /* Can only do this if we have a palette */
    if (format & (rwRASTERFORMATPAL4 | rwRASTERFORMATPAL8))
    {
        /* Make sure the palette data is written through from DCache */
        if (rpRas->palette)
        {
            RwInt32             nPaletteSize = 0, numPalEntries = 0;

            if (format & rwRASTERFORMATPAL4)
            {
                numPalEntries = 16;
            }
            else
            {
                numPalEntries = 256;
            }

            switch (format & rwRASTERFORMATPIXELFORMATMASK)
            {
                case rwRASTERFORMAT1555:
                    /* 2 bytes per palette entry */
                    nPaletteSize = numPalEntries * 2;
                    break;
                case rwRASTERFORMAT8888:
                    /* 4 bytes per palette entry */
                    nPaletteSize = numPalEntries * 4;
                    break;
                default:
                    /* Can't do this format - should never get here */
                    RWERROR((E_RW_INVRASTERFORMAT));
                    RWRETURN(FALSE);
            }

#if 0
            {
                int                 i;
                RwUInt16           *ptr = (RwUInt16 *) (rpRas->palette);

                for (i = 0; i < nPaletteSize; i += 2)
                {
                    *ptr++ = 0x80ff;
                }
            }
#endif
#if 0
            SyncDCache(rpRas->palette,
                       SCESYNCDCACHEROUNDUP(rpRas->palette +
                                            nPaletteSize));
#endif

            rpRas->privateFlags =
                rpRas->privateFlags & ~rwRASTERPALETTELOCKED;
        }
        RWRETURN(TRUE);
    }

    RWRETURN(FALSE);
}

/****************************************************************************
 SkyRasterGetMipLevels

 On entry   : Pixel pointer
            : raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
SkyRasterGetMipLevels(void *pOut, void *pInOut, RwInt32 __RWUNUSED__ nI)
{
    RwRaster           *raster = (RwRaster *) pInOut;
    RwInt32            *numMipLevels = (RwInt32 *) pOut;
    const _SkyRasterExt *rasExt = RASTEREXTFROMRASTER(raster);

    RWFUNCTION(RWSTRING("SkyRasterGetMipLevels"));
    RWASSERT(raster);
    RWASSERT(numMipLevels);

    if (raster->cpPixels)
    {
        if ((raster->cFormat & (rwRASTERFORMATMIPMAP >> 8)) && (rasExt))
        {
            *numMipLevels = (rasExt->maxMipLevel >> 2) + 1;
        }
        else
        {
            *numMipLevels = 1;
        }
    }
    else
    {
        RWRETURN(FALSE);
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterClear

 On entry   : NULL
            : NULL
            : Pixel value defining what to clear the raster to
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterClear(void *pOut __RWUNUSED__,
                   void *pInOut __RWUNUSED__,
                   RwInt32 nValue __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterClear"));

    /* Do nothing here */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterClearRect

 On entry   : NULL
            : RwRect defining area to clear
            : Pixel value defining what to clear the raster to
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterClearRect(void *pOut __RWUNUSED__,
                       void *pRect __RWUNUSED__,
                       RwInt32 nAvlue __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterClearRect"));

    /* Do nothing */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterRender

 On entry   : Raster to render (blit)
            : RwRect defining location to blit to (take x and y only)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterRender(void *pRas __RWUNUSED__,
                    void *pLoc __RWUNUSED__, RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterRender"));

    /* Do nothing */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterRenderScaled

 On entry   : Raster to render (blit)
            : RwRect defining region to blit to (take x,
 y,
 w and h)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterRenderScaled(void *pRas __RWUNUSED__,
                          void *pRect __RWUNUSED__,
                          RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterRenderScaled"));

    /* Do nothing */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterRenderFast

 On entry   : Raster to render (blit) - raster has no mask info, so optimise for this
            : RwRect defining location to blit to (take x and y only)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterRenderFast(void *pRas __RWUNUSED__,
                        void *pLoc __RWUNUSED__,
                        RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterRenderFast"));

    /* Do nothing */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterSetContext

 On entry   : NULL
            : Raster to be the destination of future raster ops.
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterSetContext(void *pOut __RWUNUSED__,
                        void *pRas __RWUNUSED__,
                        RwInt32 nData __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyRasterSetContext"));

    /* Do nothing */
    RWRETURN(TRUE);
}

static              RwBool
NullSkyHintRenderFront2Back(void *pInOut __RWUNUSED__,
                            void *pIn __RWUNUSED__,
                            RwInt32 flags __RWUNUSED__)
{
    RWFUNCTION(RWSTRING("NullSkyHintRenderFront2Back"));
    RWRETURN(TRUE);
}

/****************************************************************************
 sizeTEXInStream

 On entry   : Raster to size up
 On exit    : Size of raster when serialized
 */
static              RwUInt32
sizeTEXInStream(const RwRaster * raster)
{
    RwUInt32            size;
    const _SkyRasterExt *rasExt;
    RwUInt32            pixelDataSize;

    RWFUNCTION(RWSTRING("sizeTEXInStream"));
    RWASSERT(raster);

    rasExt = RASTEREXTFROMRASTERCONST(raster);
    pixelDataSize = rasExt->sysMemSize + rasExt->sysMemPalSize;

    /* The raster structure */
    size = (sizeof(_rwSkyNativeRaster) + rwCHUNKHEADERSIZE);

    /* The pixel data itself */
    size += (pixelDataSize + rwCHUNKHEADERSIZE);

    RWRETURN(size);
}

/****************************************************************************
 writeTEXToStream

 On entry   : Stream to write to
            : Raster to write
            : Number of bytes to write
 On exit    : RwRaster pointer on success, NULL on failure.
 */
static const RwRaster *
writeTEXToStream(RwStream * stream,
                 const RwRaster * raster,
                 RwInt32 __RWUNUSED__ bytesToWrite)
{
    _rwSkyNativeRaster  nativeRaster;
    const _SkyRasterExt *rasExt;
    RwUInt32            pixelDataSize;

    RWFUNCTION(RWSTRING("writeTEXToStream")) RWASSERT(stream);
    RWASSERT(raster);

    /* If the raster is locked then we don't know the correct
     * values.. i.e. mip level 0 might have been altered and
     * these changes will not have been propagated to the other
     * mip levels as this is done when the raster is unlocked.
     */
    if (raster->privateFlags & rwRASTERLOCKED)
    {
        RWRETURN((const RwRaster *) NULL);
    }

    /* We're gonna need these */
    rasExt = RASTEREXTFROMRASTERCONST(raster);
    pixelDataSize = rasExt->sysMemSize + rasExt->sysMemPalSize;

    /* Dump the state of the raster extension */
    nativeRaster.width = raster->width;
    nativeRaster.height = raster->height;
    nativeRaster.depth = raster->depth;
    nativeRaster.format =
        ((RwUInt16) raster->cFormat << 8) | raster->cType;
    nativeRaster.version = 0;
    /* For twiddled but compatible textures we use version 1 */
    if ((rasExt->flags == 2) && (raster->depth == 8))
    {
        nativeRaster.version = 1;
    }
#ifdef ALTTEXFORM
    if ((rasExt->flags & 1) == 1)
    {
        /* Things are abit more complex. We have dma data in the texture */
        nativeRaster.version = 2;
    }
#endif /* ALTTEXFORM */
    nativeRaster.lsb = rasExt->lsb;
    nativeRaster.msb = rasExt->msb;
    nativeRaster.palOffset = rasExt->palOffset;
    nativeRaster.maxMipLevel = (RwUInt32) rasExt->maxMipLevel;
    nativeRaster.miptbp1Lsb = rasExt->miptbp1Lsb;
    nativeRaster.miptbp1Msb = rasExt->miptbp1Msb;
    nativeRaster.miptbp2Lsb = rasExt->miptbp2Lsb;
    nativeRaster.miptbp2Msb = rasExt->miptbp2Msb;
    nativeRaster.sysMemSize = rasExt->sysMemSize;
    nativeRaster.sysMemPalSize = rasExt->sysMemPalSize;
    nativeRaster.texCacheSize = rasExt->nTexCacheSize;
    nativeRaster.mipmapKL = rasExt->mipmapKL;
#if defined(GSB) && defined(GSPLUS)
    /* We don't dump the GSPlus specific stuff, as this is just addresses */
#endif /* defined(GSB) && defined(GSPLUS) */

    /* Write the raster descriptor structure */
    if (!RwStreamWriteChunkHeader
        (stream, rwID_STRUCT, sizeof(nativeRaster)))
    {
        RWRETURN((const RwRaster *) NULL);
    }
    if (!RwStreamWriteInt(stream, (RwInt32 *) & nativeRaster,
                          sizeof(nativeRaster)))
    {
        RWRETURN((const RwRaster *) NULL);
    }

    /* And finally the pixel data (no endianess issues - read and write on
     * same machine).
     */
    if (!RwStreamWriteChunkHeader(stream, rwID_STRUCT, pixelDataSize))
    {
        RWRETURN((const RwRaster *) NULL);
    }
#ifdef ALTTEXFORM
    if ((nativeRaster.version == 0) || (nativeRaster.version == 1))
    {
#endif /* ALTTEXFORM */
        if (!RwStreamWrite(stream, raster->cpPixels, pixelDataSize))
        {
            RWRETURN((const RwRaster *) NULL);
        }
#ifdef ALTTEXFORM
    }
    else if (nativeRaster.version == 2)
    {
        RwUInt32            dataAddr;

        /* This is messy */

        dataAddr =
            (RwUInt32) ((RwUInt8 **) (raster->originalPixels))[1];

        /* Write actual pixel data */
        if (!RwStreamWrite
            (stream, (RwUInt8 *) dataAddr, rasExt->sysMemSize))
        {
            RWRETURN((const RwRaster *) NULL);
        }

        /* If there is a palette, write the palette */
        if ((rasExt->sysMemPalSize)
            && (!RwStreamWrite(stream, raster->palette - (5 << 4),
                               rasExt->sysMemPalSize)))
        {
            RWRETURN((const RwRaster *) NULL);
        }
    }
    else
    {
        RWRETURN((const RwRaster *) NULL);
    }
#endif /* ALTTEXFORM */

    /* All done - that was nice and easy - not like D3D at all :-) */
    RWRETURN(raster);
}

/****************************************************************************
 readTEXFromStream

 On entry   : Stream to read from
            : Bytes to read
 On exit    : RwRaster pointer on success, NULL on failure
 */
static RwRaster    *
readTEXFromStream(RwStream * stream, RwInt32 __RWUNUSED__ structLength)
{
    _rwSkyNativeRaster  nativeRaster;
    RwRaster           *raster;
    _SkyRasterExt      *rasExt;
    RwUInt32            origMemAlloced;
    RwUInt32            length, version;

    RWFUNCTION(RWSTRING("readTEXFromStream"));
    RWASSERT(stream);

    /* Read in the raster descriptor structure */
    if (!RwStreamFindChunk(stream, rwID_STRUCT, &length, &version))
    {
        RWRETURN((RwRaster *) NULL);
    }

    RWASSERT(version >= rwLIBRARYBASEVERSION);
    RWASSERT(version <= rwLIBRARYCURRENTVERSION);
    if ((version >= rwLIBRARYBASEVERSION) &&
        (version <= rwLIBRARYCURRENTVERSION))
    {
        RWASSERT(length <= sizeof(nativeRaster));
        memset(&nativeRaster, 0, sizeof(nativeRaster));
        if (!RwStreamReadInt
            (stream, (RwInt32 *) & nativeRaster, length))
        {
            RWRETURN((RwRaster *) NULL);
        }

#ifdef ALTTEXFORM
        if (nativeRaster.version < 2)
        {
            skyNoNewStyleRasters = TRUE;
        }
#endif /* ALTTEXFORM */
        /* Create the raster to receive the pixel data */
        raster = RwRasterCreate(nativeRaster.width, nativeRaster.height,
                                nativeRaster.depth,
                                nativeRaster.format);
#ifdef ALTTEXFORM
        skyNoNewStyleRasters = FALSE;
#endif /* ALTTEXFORM */
        if (!raster)
        {
            RWRETURN((RwRaster *) NULL);
        }

        /* compatible old textures have this filled with a sign extention */
#ifdef TWIDDLEEIGHT
#ifdef ALTTEXFORM
        RWASSERT((nativeRaster.version == 0)
                 || (nativeRaster.version == 1)
                 || (nativeRaster.version == 2)
                 || (nativeRaster.version == 0xffff));
#else /* ALTTEXFORM */
        RWASSERT((nativeRaster.version == 0)
                 || (nativeRaster.version == 1)
                 || (nativeRaster.version == 0xffff));
#endif /* ALTTEXFORM */
#else
        RWASSERT((nativeRaster.version == 0)
                 || (nativeRaster.version == 0xffff));
#endif
        /* Find out how much memory we already have */
        rasExt = RASTEREXTFROMRASTER(raster);
        origMemAlloced = rasExt->sysMemSize + rasExt->sysMemPalSize;

        /* Fill in the extension with the right numbers for the pixel data */
        rasExt->lsb = nativeRaster.lsb;
        rasExt->msb = nativeRaster.msb;
        rasExt->palOffset = nativeRaster.palOffset;
        rasExt->maxMipLevel = (RwUInt8) nativeRaster.maxMipLevel;
        rasExt->miptbp1Lsb = nativeRaster.miptbp1Lsb;
        rasExt->miptbp1Msb = nativeRaster.miptbp1Msb;
        rasExt->miptbp2Lsb = nativeRaster.miptbp2Lsb;
        rasExt->miptbp2Msb = nativeRaster.miptbp2Msb;
        rasExt->sysMemSize = nativeRaster.sysMemSize;
        rasExt->sysMemPalSize = nativeRaster.sysMemPalSize;
        rasExt->nTexCacheSize = nativeRaster.texCacheSize;
        rasExt->mipmapKL = (RwUInt16) nativeRaster.mipmapKL;
#if defined(GSB) && defined(GSPLUS)
        rasExt->lsb3 = 0;
        rasExt->msb3 = 0;
        rasExt->miptbp3Lsb = 0;
        rasExt->miptbp3Msb = 0;
        rasExt->miptbp4Lsb = 0;
        rasExt->miptbp4Msb = 0;
#endif /* defined(GSB) && defined(GSPLUS) */
#ifdef ALTTEXFORM
        if (nativeRaster.version < 2)
        {
#endif /* ALTTEXFORM */
            raster->palette = raster->cpPixels + rasExt->sysMemSize;
#ifdef ALTTEXFORM
        }
#endif /* ALTTEXFORM */

#ifdef ALTTEXFORM
        if (nativeRaster.version < 2)
        {
#endif /* ALTTEXFORM */
            /* At the moment we overwrite the flags field in the raster */
            /* This code is very brittle: it must be kept in sync with */
            /* the raster creation function */
            if (nativeRaster.version == 1)
            {
                /* A version 1 native texture is an original format raster, */
                /* but twiddled */
                if (!(rasExt->flags & 1))
                {
                    rasExt->flags |= 2;
                }
                else
                {
                    RwRasterDestroy(raster);
                    RWRETURN((RwRaster *) NULL);
                }
            }
            else
            {
                /* all others are non-twiddled */
                if (!(rasExt->flags & 1))
                {
                    rasExt->flags &= ~2;
                }
                else
                {
                    RwRasterDestroy(raster);
                    RWRETURN((RwRaster *) NULL);
                }
            }
#ifdef ALTTEXFORM
        }
#endif /* ALTTEXFORM */

        /* Read in the pixel data */
        if (!RwStreamFindChunk(stream, rwID_STRUCT, &length, &version))
        {
            RwRasterDestroy(raster);
            RWRETURN((RwRaster *) NULL);
        }
        RWASSERT(version >= rwLIBRARYBASEVERSION);
        RWASSERT(version <= rwLIBRARYCURRENTVERSION);
        if ((version >= rwLIBRARYBASEVERSION) &&
            (version <= rwLIBRARYCURRENTVERSION))
        {
            RWASSERT(length <= origMemAlloced); /* SANITY CHECK */
#ifdef ALTTEXFORM
            if (nativeRaster.version < 2)
            {
#endif /* ALTTEXFORM */
                if (RwStreamRead(stream, raster->cpPixels, length) !=
                    length)
                {
                    RwRasterDestroy(raster);
                    RWRETURN((RwRaster *) NULL);
                }

#if 0
                SyncDCache(raster->cpPixels,
                           SCESYNCDCACHEROUNDUP(raster->cpPixels +
                                                length));
#endif
#ifdef ALTTEXFORM
            }
            else if (nativeRaster.version == 2)
            {
                /* Need to read in the thing in two chunks */
                if (RwStreamRead(stream,
                                 ((RwUInt8 **) (raster->
                                                originalPixels))[1],
                                 rasExt->sysMemSize) !=
                    rasExt->sysMemSize)
                {
                    RwRasterDestroy(raster);
                    RWRETURN((RwRaster *) NULL);
                }

                if ((rasExt->sysMemPalSize)
                    && (RwStreamRead(stream, raster->palette - (5 << 4),
                                     rasExt->sysMemPalSize)
                        != rasExt->sysMemPalSize))
                {
                    RwRasterDestroy(raster);
                    RWRETURN((RwRaster *) NULL);
                }
#if 0
                SyncDCache(((RwUInt8 **) (raster->originalPixels))[1],
                           SCESYNCDCACHEROUNDUP(raster->palette -
                                                (5 << 4) +
                                                rasExt->sysMemPalSize));
#endif
            }
            else
            {
                RwRasterDestroy(raster);
                RWRETURN((RwRaster *) NULL);
            }
#endif /* ALTTEXFORM */

        }
        else
        {
            RWERROR((E_RW_BADVERSION));
            RWRETURN((RwRaster *) NULL);
        }

        /* All done */
        RWRETURN(raster);
    }
    else
    {
        RWERROR((E_RW_BADVERSION));
        RWRETURN((RwRaster *) NULL);
    }
}

/****************************************************************************
 SkyNativeTextureGetSize

 On entry   : Pointer to size value to fill in
            : Texture to size up
            : 0
 On exit    : TRUE on success
 */
static              RwBool
SkyNativeTextureGetSize(void *pSize, void *pTex,
                        RwInt32 __RWUNUSED__ unusedNumber)
{
    RwUInt32           *size = (RwUInt32 *) pSize;
    RwTexture          *texture = (RwTexture *) pTex;
    RwRaster           *raster;

    RWFUNCTION(RWSTRING("SkyNativeTextureGetSize"));
    RWASSERT(size);
    RWASSERT(texture);

    /* Figure out a length and send it back */
    *size = 0;

    /* The header */
    (*size) += (sizeof(_rwSkyNativeTexture) + rwCHUNKHEADERSIZE);

    /* The strings */
    (*size) +=
        (rwStringStreamGetSize(texture->name) + rwCHUNKHEADERSIZE);
    (*size) +=
        (rwStringStreamGetSize(texture->mask) + rwCHUNKHEADERSIZE);

    /* The native raster data */
    raster = RwTextureGetRaster(texture);
    RWASSERT(raster);
    (*size) += (sizeTEXInStream(raster) + rwCHUNKHEADERSIZE);

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyNativeTextureWrite

 On entry   : Stream to write to
            : Texture to write
            : Amount to write
 On exit    : TRUE on success
 */
static              RwBool
SkyNativeTextureWrite(void *pStream, void *pTex,
                      RwInt32 __RWUNUSED__ size)
{
    RwStream           *stream = (RwStream *) pStream;
    RwTexture          *texture = (RwTexture *) pTex;
    RwRaster           *raster;
    _rwSkyNativeTexture nativeTexture;
    RwTextureFilterMode filtering;
    RwTextureAddressMode addressingU;
    RwTextureAddressMode addressingV;
    RwUInt32            sizeOfNativeTextureData;

    RWFUNCTION(RWSTRING("SkyNativeTextureWrite"));
    RWASSERT(stream);
    RWASSERT(texture);

    raster = RwTextureGetRaster(texture);
    RWASSERT(raster);

    /* Struct header for _rwSkyNativeTexture structure */
    if (!RwStreamWriteChunkHeader
        (stream, rwID_STRUCT, sizeof(nativeTexture)))
    {
        RWRETURN(FALSE);
    }

    /* Set up the identifier */
    memcpy(nativeTexture.id, "PS2\0", 4);
    filtering = RwTextureGetFilterMode(texture);
    addressingU = RwTextureGetAddressingU(texture);
    addressingV = RwTextureGetAddressingV(texture);

    nativeTexture.filterAndAddress = (((RwInt32) filtering) & 0xFF) |
        ((((RwInt32) addressingU) & 0x0F) << 8) |
        ((((RwInt32) addressingV) & 0x0F) << 12);

    /* Convert and write it */
    RwMemLittleEndian(&nativeTexture.filterAndAddress,
                      sizeof(nativeTexture.filterAndAddress));
    if (!RwStreamWrite(stream, &nativeTexture, sizeof(nativeTexture)))
    {
        RWRETURN(FALSE);
    }

    /* Now the strings */
    if (!rwStringStreamWrite(texture->name, stream))
    {
        RWRETURN(FALSE);
    }
    if (!rwStringStreamWrite(texture->mask, stream))
    {
        RWRETURN(FALSE);
    }

    /* The native raster data */
    sizeOfNativeTextureData = sizeTEXInStream(raster);
    if (!RwStreamWriteChunkHeader
        (stream, rwID_STRUCT, sizeOfNativeTextureData))
    {
        RWRETURN(FALSE);
    }
    if (!writeTEXToStream(stream, raster, sizeOfNativeTextureData))
    {
        RWRETURN(FALSE);
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 SkyNativeTextureRead

 On entry   : Stream to read from
            : Pointer to texture pointer to fill in
            : Amount to read
 On exit    : TRUE on success
 */
static              RwBool
SkyNativeTextureRead(void *pStream, void *ppTex,
                     RwInt32 __RWUNUSED__ size)
{
    RwStream           *stream = (RwStream *) pStream;
    RwTexture         **texture = (RwTexture **) ppTex;
    RwTextureAddressMode addressingU;
    RwTextureAddressMode addressingV;
    _rwSkyNativeTexture nativeTexture;
    RwChar              textureName[rwTEXTUREBASENAMELENGTH * 4];
    RwChar              textureMask[rwTEXTUREBASENAMELENGTH * 4];
    RwUInt32            structLength, version;
    RwRaster           *raster;

    RWFUNCTION(RWSTRING("SkyNativeTextureRead"));
    RWASSERT(pStream);
    RWASSERT(ppTex);

    /* We ain't got it yet */
    *texture = (RwTexture *) NULL;

    if (!RwStreamFindChunk
        (stream, rwID_STRUCT, &structLength, &version))
    {
        RWRETURN(FALSE);
    }

    RWASSERT(version >= rwLIBRARYBASEVERSION);
    RWASSERT(version <= rwLIBRARYCURRENTVERSION);
    if ((version >= rwLIBRARYBASEVERSION) &&
        (version <= rwLIBRARYCURRENTVERSION))
    {
        /* This gives us the protection against changing structure sizes */
        RWASSERT(structLength <= sizeof(nativeTexture));
        memset(&nativeTexture, 0, sizeof(nativeTexture));
        if (RwStreamRead(stream, &nativeTexture, structLength) !=
            structLength)
        {
            RWRETURN(FALSE);
        }

        /* Convert it */
        RwMemNative(&nativeTexture.filterAndAddress,
                    sizeof(nativeTexture.filterAndAddress));

        /* Check the ID field */
        if ((nativeTexture.id[0] != 'P') || (nativeTexture.id[1] != 'S')
            || (nativeTexture.id[2] != '2')
            || (nativeTexture.id[3] != 0))
        {
            RWRETURN(FALSE);
        }

        if (!rwStringStreamFindAndRead(textureName, stream))
        {
            RWRETURN(FALSE);
        }
        if (!rwStringStreamFindAndRead(textureMask, stream))
        {
            RWRETURN(FALSE);
        }

        /* Find the native data 'structure' - This just contains the pixel data */
        if (!RwStreamFindChunk
            (stream, rwID_STRUCT, &structLength, &version))
        {
            RWRETURN(FALSE);
        }

        RWASSERT(version >= rwLIBRARYBASEVERSION);
        RWASSERT(version <= rwLIBRARYCURRENTVERSION);
        if ((version >= rwLIBRARYBASEVERSION) &&
            (version <= rwLIBRARYCURRENTVERSION))
        {
            raster = readTEXFromStream(stream, structLength);
            if (!raster)
            {
                RWRETURN(FALSE);
            }
        }
        else
        {
            RWERROR((E_RW_BADVERSION));
            RWRETURN(FALSE);
        }

        /* Create a texture from the raster */
        *texture = RwTextureCreate(raster);
        if (!(*texture))
        {
            RwRasterDestroy(raster);
            RWRETURN(FALSE);
        }

        RwTextureSetName(*texture, textureName);
        RwTextureSetMaskName(*texture, textureMask);

#ifdef SHOWUPLOADEDTEXTURES
        {
            RwInt32             nIndex;

            /* Find a spare slot for this texture */
            for (nIndex = 0; nIndex < SHOWUPLOADEDTEXTUREMAXTEXTURES;
                 nIndex++)
            {
                if (tpShowUploadedTextures[nIndex] == NULL)
                {
                    printf("Registering Texture %s Raster %x\n",
                           textureName, raster);
                    tpShowUploadedTextures[nIndex] = *texture;
                    rpShowUploadedRasters[nIndex] = raster;
                    break;
                }
            }
        }
#endif

        /* Set up Texture Modes */
        RwTextureSetFilterMode(*texture,
                               (RwTextureFilterMode) (nativeTexture.
                                                      filterAndAddress &
                                                      0xFF));

        /* Extract addressing */
        addressingU = (RwTextureAddressMode)
            ((nativeTexture.filterAndAddress >> 8) & 0x0F);
        addressingV = (RwTextureAddressMode)
            ((nativeTexture.filterAndAddress >> 12) & 0x0F);

        /* Make sure addressingV is valid so files old than 3.04 still work */
        if (addressingV == rwTEXTUREADDRESSNATEXTUREADDRESS)
        {
            addressingV = addressingU;
        }

        RwTextureSetAddressingU(*texture, addressingU);
        RwTextureSetAddressingV(*texture, addressingV);

        RWRETURN(TRUE);
    }
    else
    {
        RWERROR((E_RW_BADVERSION));
        RWRETURN(FALSE);
    }
}

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

                              Default

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

/******************* Standard functions ************************************/

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

                      Setting up of standard functions

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

/****************************************************************************
 NullSkyNoStandard

 On entry   : pOut
            : pInOut
            : nIn
 On exit    : FALSE
 */
static              RwBool
NullSkyNoStandard(void *pOut, void *pInOut, RwInt32 nIn)
{
    RWFUNCTION(RWSTRING("NullSkyNoStandard"));

    /* Stop warnings */
    pOut = pOut;
    pInOut = pInOut;
    nIn = nIn;

    RWRETURN(FALSE);
}

/****************************************************************************
 NullSkySetStandards

 On entry   : Standard functions
            : Space
            : Standards
            : Amount of standards
 On exit    :
 */
static void
NullSkySetStandards(RwStandardFunc * fppFuncs,
                    RwInt32 nNumFuncs,
                    RwStandard * spStandards, RwInt32 nNumStandards)
{
    RwInt32             nI;

    RWFUNCTION(RWSTRING("NullSkySetStandards"));

    /* Clear out all of the standards initially */
    for (nI = 0; nI < nNumFuncs; nI++)
    {
        fppFuncs[nI] = NullSkyNoStandard;
    }

    /* Fill in all of the standards */

    while (nNumStandards--)
    {
        if ((spStandards->nStandard < nNumFuncs) &&
            (spStandards->nStandard >= 0))
        {
            fppFuncs[spStandards->nStandard] = spStandards->fpStandard;
        }

        spStandards++;
    }

    RWRETURNVOID();
}

static RwBool
devicesystemrxpipelinerequestpipe(void *pOut,
                                  void *pInOut __RWUNUSED__,
                                  RwInt32 nIn __RWUNUSED__)
{
    RxPipeline        **pipelineRef = (RxPipeline **) pOut;

    RWFUNCTION(RWSTRING("devicesystemrxpipelinerequestpipe"));

    *pipelineRef = NULL;

    RWRETURN(TRUE);
}

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

                           System access

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

static              RwBool
SkyUseMode(RwInt32 nIn)
{
    RwBool              result = FALSE;

    RWFUNCTION(RWSTRING("SkyUseMode"));

    /* Mode index must be in range, and engine not started */
    result =
        (nIn < (RwInt32) (sizeof(videoModes) / sizeof(RwVideoMode)));

    if (result)
    {
        currentMode = nIn;
        if (videoModes[currentMode].depth == 32)
        {
            currentCameraFormat = (RwInt32) rwRASTERFORMAT8888;
        }
        else
        {
            currentCameraFormat = (RwInt32) rwRASTERFORMAT1555;
        }
    }

    RWRETURN(result);
}

static              RwBool
SkyGetNumModes(void *pOut)
{
    RWFUNCTION(RWSTRING("SkyGetNumModes"));

    *((RwInt32 *) pOut) = sizeof(videoModes) / sizeof(RwVideoMode);

    RWRETURN(TRUE);
}

static              RwBool
SkyGetModeinfo(void *pOut, RwInt32 nIn)
{
    RwBool              result;
    RwVideoMode        *vpMode;

    RWFUNCTION(RWSTRING("SkyGetModeinfo"));

    vpMode = (RwVideoMode *) pOut;

    result =
        nIn < ((RwInt32) (sizeof(videoModes) / sizeof(RwVideoMode)));

    if (result)
    {
        *vpMode = videoModes[nIn];
    }

    /* Mode index out of range */
    RWRETURN(result);
}

static              RwBool
SkyGetMode(void *pOut)
{
    RWFUNCTION(RWSTRING("SkyGetMode"));

    *((RwInt32 *) pOut) = currentMode;
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkySystem

 On entry   : Request
            : Data out
            : Data in/out
            : Number in
 On exit    : TRUE on success
 */
static              RwBool
NullSkySystem(RwInt32 nRequest, void *pOut, void *pInOut, RwInt32 nIn)
{
    RWFUNCTION(RWSTRING("NullSkySystem"));

    switch (nRequest)
    {

        /******************* Opening/Closing **********************/

            /* Gives the device access to the libraries device block */

        case rwDEVICESYSTEMREGISTER:
            {
                RwDevice           *dpDevice = (RwDevice *) pOut;
                RwMemoryFunctions  *mfpFuncs =
                    (RwMemoryFunctions *) pInOut;
                RwDevice           *lpdGD3d = _rwDeviceGetHandle();

                /* Set up the fast device access.. */

                *dpDevice = *lpdGD3d;

                dgGGlobals.memFuncs = mfpFuncs;

                /* Reserve some memory inside raster structures */
                skyRasterExt =
                    RwRasterRegisterPlugin(sizeof(_SkyRasterExt),
                                           rwID_DEVICEMODULE,
                                           (RwPluginObjectConstructor)
                                           NULL,
                                           (RwPluginObjectDestructor)
                                           NULL,
                                           (RwPluginObjectCopy) NULL);
                skyTextureExt =
                    RwTextureRegisterPlugin(0, rwID_SKYMIPMAPVAL,
                                            (RwPluginObjectConstructor)
                                            NULL,
                                            (RwPluginObjectDestructor)
                                            NULL,
                                            (RwPluginObjectCopy) NULL);

                skyTextureExt =
                    RwTextureRegisterPluginStream(rwID_SKYMIPMAPVAL,
                                                  skyReadTexCB,
                                                  skyWriteTexCB,
                                                  skyGetSizeTexCB);

                RWRETURN(TRUE);
            }

        /******************* Opening/Closing **********************/

            /* The purpose of Open is to put the hardware in a state where
             * it can be queried (about its capabilities). This function also
             * tests if it is a candidate at all (like it can be started at
             * all). NOTE this includes setting up a minimal set of standard
             * handlers that can be used for querying the device. */

        case rwDEVICESYSTEMOPEN:
            {
                /* We're not interested in the window handle here, but if we
                 * were, it would be accessible as:
                 * (HWND)(((RwEngineOpenParams *)pInOut)->displayID);
                 */

                currentMode =
                    (sizeof(videoModes) / sizeof(RwVideoMode)) - 1;

                if (videoModes[currentMode].depth == 32)
                {
                    currentCameraFormat = (RwInt32) rwRASTERFORMAT8888;
                }
                else
                {
                    currentCameraFormat = (RwInt32) rwRASTERFORMAT1555;
                }
                /* Done */
                RWRETURN(TRUE);
            }

            /* The purpose of Close is to remove any set up that was performed
             * by Open */

        case rwDEVICESYSTEMCLOSE:
            {
                /* All done - nothing to do */
                RWRETURN(TRUE);
            }

        /************** Starting stopping ******************/

            /* Start means that this bit of hardware has been selected for
             * rendering - so get it into a state ready for rendering */

        case rwDEVICESYSTEMSTART:
            {
                /* All done */
                RWRETURN(TRUE);
            }

            /* Puts back the hardware into the state it was in immediately
             * after being opened */

        case rwDEVICESYSTEMSTOP:
            {

                /* All done */
                RWRETURN(TRUE);
            }

            /************* pipeline initialisation **************************/
        case rwDEVICESYSTEMINITPIPELINE:
            {
                RWRETURN(TRUE);
            }

        case rwDEVICESYSTEMRXPIPELINEREQUESTPIPE:
            {
                RwBool              result;

                result =
                    devicesystemrxpipelinerequestpipe(pOut, pInOut,
                                                      nIn);
                RWRETURN(result);
            }

        case rwDEVICESYSTEMUSEMODE:
            {
                RwBool              result;

                result = SkyUseMode(nIn);
                RWRETURN(result);
            }

        case rwDEVICESYSTEMGETNUMMODES:
            {
                RwBool              result;

                result = SkyGetNumModes(pOut);
                RWRETURN(result);
            }

        case rwDEVICESYSTEMGETMODEINFO:
            {
                RwBool              result;

                result = SkyGetModeinfo(pOut, nIn);
                RWRETURN(result);
            }

        case rwDEVICESYSTEMGETMODE:
            {
                RwBool              result;

                result = SkyGetMode(pOut);
                RWRETURN(result);
            }

        /************* standard device functions ************************/

        case rwDEVICESYSTEMSTANDARDS:
            {
                /* Standard functions */
                static RwStandard   saGStandards[] = {
                    /* Camera ops */
                    {rwSTANDARDCAMERABEGINUPDATE,
                     NullSkyCameraBeginUpdate},
                    {rwSTANDARDCAMERAENDUPDATE, NullSkyCameraEndUpdate},
                    {rwSTANDARDCAMERACLEAR, NullSkyCameraClear},

                    /* Raster/Pixel operations */
                    {rwSTANDARDRASTERSHOWRASTER,
                     NullSkyRasterShowRaster},
#if 0
                    {rwSTANDARDRGBTOPIXEL, NullSkyRGBToPixel},
                    {rwSTANDARDPIXELTORGB, NullSkyPixelToRGB},
                    {rwSTANDARDRASTERSETIMAGE, NullSkyRasterSetImage},
                    {rwSTANDARDIMAGEGETRASTER, NullSkyImageGetRaster},
#else
                    {rwSTANDARDRGBTOPIXEL, _rwSkyRGBToPixel},
                    {rwSTANDARDPIXELTORGB, _rwSkyPixelToRGB},
                    {rwSTANDARDRASTERSETIMAGE, _rwSkyRasterSetImage},
                    {rwSTANDARDIMAGEGETRASTER, _rwSkyImageGetRaster},
#endif

                    /* Raster creation and destruction */
#if 0
                    {rwSTANDARDRASTERDESTROY, NullSkyRasterDestroy},
                    {rwSTANDARDRASTERCREATE, NullSkyRasterCreate},
                    {rwSTANDARDRASTERSUBRASTER, NullSkyRasterSubRaster},
#else
                    {rwSTANDARDRASTERDESTROY, SkyRasterDestroy},
                    {rwSTANDARDRASTERCREATE, SkyRasterCreate},
                    {rwSTANDARDRASTERSUBRASTER, SkyRasterSubRaster},
#endif

                    /* Finding about a raster type */
#if 0
                    {rwSTANDARDIMAGEFINDRASTERFORMAT,
                     NullSkyImageFindRasterFormat},
#else
                    {rwSTANDARDIMAGEFINDRASTERFORMAT,
                     _rwSkyImageFindRasterFormat},
#endif

                    /* Texture operations */
#if 0
                    {rwSTANDARDTEXTURESETRASTER,
                     NullSkyTextureSetRaster},
#else
                    {rwSTANDARDTEXTURESETRASTER, SkyTextureSetRaster},
#endif

                    /* Locking and releasing */
#if 0
                    {rwSTANDARDRASTERLOCK, NullSkyRasterLock},
                    {rwSTANDARDRASTERUNLOCK, NullSkyRasterUnlock},
#else
                    {rwSTANDARDRASTERLOCK, SkyRasterLock},
                    {rwSTANDARDRASTERUNLOCK, SkyRasterUnlock},
                    {rwSTANDARDRASTERLOCKPALETTE, SkyRasterLockPalette},
                    {rwSTANDARDRASTERUNLOCKPALETTE,
                     SkyRasterUnlockPalette},
#endif

                    /* Raster operations */
                    {rwSTANDARDRASTERCLEAR, NullSkyRasterClear},
                    {rwSTANDARDRASTERCLEARRECT, NullSkyRasterClearRect},
                    {rwSTANDARDRASTERRENDER, NullSkyRasterRender},
                    {rwSTANDARDRASTERRENDERSCALED,
                     NullSkyRasterRenderScaled},
                    {rwSTANDARDRASTERRENDERFAST,
                     NullSkyRasterRenderFast},
                    {rwSTANDARDSETRASTERCONTEXT,
                     NullSkyRasterSetContext},

                    /* Render order hint */
                    {rwSTANDARDHINTRENDERF2B,
                     NullSkyHintRenderFront2Back},

                    /* Device specific texture dictionary serialisation */
                    {rwSTANDARDNATIVETEXTUREGETSIZE,
                     SkyNativeTextureGetSize},
                    {rwSTANDARDNATIVETEXTUREWRITE,
                     SkyNativeTextureWrite},
                    {rwSTANDARDNATIVETEXTUREREAD, SkyNativeTextureRead},

                    /* Raster mip levels */
#if 0
                    {rwSTANDARDRASTERGETMIPLEVELS,
                     NullSkyRasterGetMipLevels}
#else
                    {rwSTANDARDRASTERGETMIPLEVELS, SkyRasterGetMipLevels}
#endif
                };

                NullSkySetStandards((RwStandardFunc *) pOut, nIn,
                                    saGStandards,
                                    sizeof(saGStandards) /
                                    sizeof(RwStandard));

                RWRETURN(TRUE);
            }

        /******************* not supported ******************************/

        default:
            {
                break;
            }
    }

    RWRETURN(FALSE);
}

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

                     Getting the device structure

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

/****************************************************************************
 _rwDeviceGetHandle

 On entry   :
 On exit    : device block handle
 */
RwDevice           *
_rwDeviceGetHandle(void)
{
    static RwDevice     dGNullDevice = {
        (RwReal) (1),           /* Default gamma correction */

        NullSkySystem,

        (RwReal) (65535.0), (RwReal) (0.0), /* Z buffer limits - what does it matter? */

        NullSkySetRenderState,  /* Setting the rendering state */
        NullSkyGetRenderState,  /* Getting the rendering state */

        NullSkyIm2DRenderLine,  /* Line rendering function */
        NullSkyIm2DRenderTriangle, /* Rendering a triangle under the current state */
        NullSkyIm2DRenderPrimitive,
        NullSkyIm2DRenderIndexedPrimitive,

        /* These get set up when the immediate mode module is set up */
        NULL, NULL, NULL, NULL
    };                          /* NULL system */

    RWFUNCTION(RWSTRING("_rwDeviceGetHandle"));

    RWRETURN(&dGNullDevice);
}

#if (0)

/****************************************************************************
 NullSkyPixelToRGB

 On entry   : Palette entry (OUT)
            : NULL
            : Palette entry (IN)
 On exit    : TRUE on success
 */
static              RwBool
NullSkyPixelToRGB(void *pRGB, void *pPixel, RwInt32 nFormat)
{
    RwRGBA             *rpRGB = (RwRGBA *) pRGB;
    RwInt32             nPixel = *(RwInt32 *) pPixel;

    RWFUNCTION(RWSTRING("NullSkyPixelToRGB"));
    RWASSERT(pPixel);
    RWASSERT(pRGB);

    switch (nFormat & (RwInt32) rwRASTERFORMATPIXELFORMATMASK)
    {
        case rwRASTERFORMAT8888:
        case rwRASTERFORMATDEFAULT:
            {
                rpRGB->red = (RwUInt8) (nPixel >> 24);
                rpRGB->green = (RwUInt8) (nPixel >> 16);
                rpRGB->blue = (RwUInt8) (nPixel >> 8);
                rpRGB->alpha = (RwUInt8) (nPixel >> 0);

                break;
            }
        case rwRASTERFORMAT888:
            {
                rpRGB->red = (RwUInt8) (nPixel >> 16);
                rpRGB->green = (RwUInt8) (nPixel >> 8);
                rpRGB->blue = (RwUInt8) (nPixel >> 0);
                rpRGB->alpha = 0xFF;

                break;
            }
        default:
            {
                RWERROR((E_RW_INVRASTERFORMAT));
                RWRETURN(FALSE);
            }
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyImageFindRasterFormat

 On entry   : Raster (OUT)
            : Image
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyImageFindRasterFormat(void *pRaster, void *pImage, RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwImage            *ipImage = (RwImage *) pImage;

    RWFUNCTION(RWSTRING("NullSkyImageFindRasterFormat"));

    /* Do the default thing first */
    rpRas->width = ipImage->width;
    rpRas->height = ipImage->height;
    rpRas->depth = 0;          /* Use the default depth for now... */

    /* Try to find the format with what we've got */

    if (!NullSkyGetRasterFormat(NULL, pRaster, flags))
    {
        RWRETURN(FALSE);
    }

    /* The format is already set up */

    /* See whats possible */

    switch (rpRas->cType)
    {
        case rwRASTERTYPETEXTURE:
            {
                RwInt32             format;

                NullSkyImageFindFormat(ipImage, &format);

#if (0)
                rpRas->cFormat = (RwUInt8)
                    ((format |
                      (flags &
                       (rwRASTERFORMATMIPMAP |
                        rwRASTERFORMATAUTOMIPMAP)) >> 8));
#endif /* (0) */

                rpRas->cFormat = (RwUInt8)
                    ((format |
                      (flags &
                       (rwRASTERFORMATMIPMAP |
                        rwRASTERFORMATAUTOMIPMAP))) >> 8);

                /* We have our format */
                RWRETURN(TRUE);
            }
        case rwRASTERTYPENORMAL:
        case rwRASTERTYPECAMERA:
        case rwRASTERTYPEZBUFFER:
            {
                /* Just take the default case */

                RWRETURN(TRUE);
            }
    }

    RWRETURN(FALSE);
}

/****************************************************************************
 NullSkyRasterCreate

 Create a raster

 On entry   : NULL
            : pRaster - raster to allocate
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterCreate(void *pInOut, void *pRaster, RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwInt32             nFormat = flags & (RwInt32) rwRASTERFORMATMASK;

    RWFUNCTION(RWSTRING("NullSkyRasterCreate"));

    /* Stop warnings */
    pInOut = pInOut;

    if (!NullSkyGetRasterFormat(pInOut, pRaster, flags))
    {
        RWRETURN(FALSE);
    }

    /* Set up */

    rpRas->cpPixels = NULL;

    /* If is not a camera buffer, then we need to allocate real memory for it
     */

    if ((rpRas->width) && (rpRas->height))
    {
        switch (rpRas->cType)
        {
            case rwRASTERTYPETEXTURE:
                {
                    switch (nFormat & rwRASTERFORMATPIXELFORMATMASK)
                    {
                        case rwRASTERFORMAT8888:
                            {
                                rpRas->stride = 4 * rpRas->width;
                                rpRas->cpPixels =
                                    (RwUInt8 *) RwDriverMalloc(rpRas->
                                                               stride *
                                                               rpRas->
                                                               height);
                                if (!rpRas->cpPixels)
                                {
                                    RWRETURN(FALSE);
                                }
                                break;
                            }
                        case rwRASTERFORMAT888:
                            {
                                rpRas->stride = 3 * rpRas->width;
                                rpRas->cpPixels =
                                    (RwUInt8 *) RwDriverMalloc(rpRas->
                                                               stride *
                                                               rpRas->
                                                               height);
                                if (!rpRas->cpPixels)
                                {
                                    RWRETURN(FALSE);
                                }
                                break;
                            }
                        default:
                            {
                                RWERROR((E_RW_INVRASTERFORMAT));
                                RWRETURN(FALSE);
                            }
                            break;
                    }
                    break;
                }
            case rwRASTERTYPECAMERA:
            case rwRASTERTYPENORMAL:
                {
                    /* Calculate stride */
                    rpRas->stride = 4 * rpRas->width;

                    /* Allocate space */
                    rpRas->cpPixels =
                        (RwUInt8 *) RwDriverMalloc(rpRas->stride *
                                                   rpRas->height);

                    if (!rpRas->cpPixels)
                    {
                        RWRETURN(FALSE);
                    }
                    break;
                }
            case rwRASTERTYPEZBUFFER:
                {
                    /* Calculate stride */
                    rpRas->stride = 2 * rpRas->width;

                    /* Allocate space */
                    rpRas->cpPixels =
                        (RwUInt8 *) RwDriverMalloc(rpRas->stride *
                                                   rpRas->height);

                    if (!rpRas->cpPixels)
                    {
                        RWRETURN(FALSE);
                    }
                    break;
                }
            default:
                {
                    RWRETURN(FALSE);
                }
        }
    }
    else
    {
        rpRas->cFlags = (RwUInt8) rwRASTERDONTALLOCATE; /* Not allocated */
        rpRas->stride = 0;
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterSubRaster

 On entry   : Raster (OUT)
            : Raster (IN)
            : None
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterSubRaster(void *pRas, void *pIn, RwInt32 nIn __RWUNUSED__)
{
    RwRaster           *rpRas = (RwRaster *) pRas;
    RwRaster           *rpIn = (RwRaster *) pIn;
    RwRaster           *pixelOwner = rpIn->parent;

    RWFUNCTION(RWSTRING("NullSkyRasterSubRaster"));

    /* Core already set up offset and size */

    /* This baby has most certainly not been allocated */
    rpRas->cFormat = rpIn->cFormat;
    rpRas->stride = rpIn->stride;
    rpRas->depth = rpIn->depth;
    rpRas->cType = rpIn->cType;

    switch (rpIn->depth)
    {
        case 24:
            {
                rpRas->cpPixels = (pixelOwner->cpPixels) +
                    (pixelOwner->stride * rpRas->nOffsetY) +
                    (rpRas->nOffsetX * 3);
                break;
            }
        case 32:
            {
                rpRas->cpPixels = (pixelOwner->cpPixels) +
                    (pixelOwner->stride * rpRas->nOffsetY) +
                    (rpRas->nOffsetX * 4);
                break;
            }
        default:
            {
                RWERROR((E_RW_INVRASTERFORMAT));
                RWRETURN(FALSE);
            }
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterDestroy

 On entry   : NULL
            : Raster to destroy
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterDestroy(void *pOut, void *pRaster, RwInt32 nIn)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;

    RWFUNCTION(RWSTRING("NullSkyRasterDestroy"));

    /* Stop warnings */
    pOut = pOut;
    nIn = nIn;

    if (!(rpRas->cFlags & (RwUInt8) rwRASTERDONTALLOCATE))
    {
        RwDriverFree(rpRas->cpPixels);
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterLock

 On entry   : Pixel pointer
            : raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterLock(void *pPixels, void *pRaster, RwInt32 flags)
{
    RwUInt8           **cppPixels = (RwUInt8 **) pPixels;
    RwRaster           *raster = (RwRaster *) pRaster;
    RwUInt8             mipLevel =
        (RwUInt8) (((RwInt32) 0xFF00 & flags) >> 8);

    RWFUNCTION(RWSTRING("NullSkyRasterLock"));

    flags = flags & 0xFF;

    if (mipLevel > 0)
    {
        RWRETURN(FALSE);
    }

    (*cppPixels) = raster->cpPixels;

    if (flags & rwRASTERLOCKREAD)
    {
        raster->privateFlags |= rwRASTERPIXELLOCKEDREAD;
    }
    if (flags & rwRASTERLOCKWRITE)
    {
        raster->privateFlags |= rwRASTERPIXELLOCKEDWRITE;
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterUnlock

 On entry   : NULL
            : Rastre
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterUnlock(void *pInOut, void *pRaster, RwInt32 flags)
{
    RwRaster           *raster = (RwRaster *) pRaster;

    RWFUNCTION(RWSTRING("NullSkyRasterUnlock"));

    /* Stop warnings */
    pInOut = pInOut;
    pRaster = pRaster;
    flags = flags;

    raster->privateFlags &= ~rwRASTERPIXELLOCKED;

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRasterGetMipLevels

 On entry   : Pixel pointer
            : raster
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterGetMipLevels(void *pOut,
                          void *pInOut, RwInt32 nI __RWUNUSED__)
{
    RwRaster           *raster = (RwRaster *) pInOut;
    RwInt32            *numMipLevels = (RwInt32 *) pOut;

    RWFUNCTION(RWSTRING("NullSkyRasterGetMipLevels"));
    RWASSERT(raster);
    RWASSERT(numMipLevels);

    if (raster->cpPixels)
    {
        *numMipLevels = 1;

    }
    else
    {
        *numMipLevels = 0;
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyImageGetRaster

 On entry   : Image (MODIFY)
            : Raster
 On exit    : TRUE on success
 */
static              RwBool
NullSkyImageGetRaster(void *pImage,
                      void *pRaster, RwInt32 nNum __RWUNUSED__)
{
    RwRaster           *raster = (RwRaster *) pRaster;
    RwImage            *image = (RwImage *) pImage;
    RwBool              alreadyPixelLocked = FALSE;
    RwBool              result = TRUE;

    RWFUNCTION(RWSTRING("NullSkyImageGetRaster"));

    if (image->cpPixels)
    {
        RwInt32             x;
        RwInt32             y;
        RwUInt8            *srcPixels = NULL;
        RwRasterFormat      format;

        if ((image->width < raster->width) ||
            (image->height < raster->height) || (image->depth != 32))
        {
            RWRETURN(FALSE);
        }

        if (raster->privateFlags & rwRASTERPIXELLOCKEDREAD)
        {
            alreadyPixelLocked = TRUE;
        }
        else
        {
            srcPixels = RwRasterLock(raster, 0, rwRASTERLOCKREAD);
            if (srcPixels == NULL)
            {
                RWRETURN(FALSE);
            }
        }

        format = RwRasterGetFormat(raster);
        switch (format & rwRASTERFORMATPIXELFORMATMASK)
        {
            case rwRASTERFORMAT888:
                {
                    RwUInt8            *rasterPixels;
                    RwUInt8            *dstPixels;
                    RwRGBA             *imageRGBA;

                    dstPixels = image->cpPixels;

                    for (y = 0; y < raster->height; y++)
                    {
                        rasterPixels = srcPixels;
                        imageRGBA = (RwRGBA *) dstPixels;
                        for (x = 0; x < raster->width; x++)
                        {
                            imageRGBA->red = *(rasterPixels++);
                            imageRGBA->green = *(rasterPixels++);
                            imageRGBA->blue = *(rasterPixels++);
                            imageRGBA->alpha = 0xFF;

                            imageRGBA++;
                        }
                        srcPixels += raster->stride;
                        dstPixels += image->stride;
                    }
                    break;
                }
            case rwRASTERFORMAT8888:
                {
                    RwRGBA             *rasterRGBA;
                    RwUInt8            *dstPixels;
                    RwRGBA             *imageRGBA;

                    dstPixels = image->cpPixels;

                    for (y = 0; y < raster->height; y++)
                    {
                        rasterRGBA = (RwRGBA *) srcPixels;
                        imageRGBA = (RwRGBA *) dstPixels;
                        for (x = 0; x < raster->width; x++)
                        {
                            imageRGBA->red = rasterRGBA->red;
                            imageRGBA->green = rasterRGBA->green;
                            imageRGBA->blue = rasterRGBA->blue;
                            imageRGBA->alpha = rasterRGBA->alpha;

                            imageRGBA++;
                            rasterRGBA++;
                        }
                        srcPixels += raster->stride;
                        dstPixels += raster->stride;
                    }
                    break;
                }
            default:
                {
                    RWERROR((E_RW_INVRASTERFORMAT));
                    result = FALSE;
                }
        }

        if (!alreadyPixelLocked)
        {
            RwRasterUnlock(raster);
        }
        RWRETURN(result);
    }

    RWERROR((E_RW_INVIMAGEFORMAT));
    RWRETURN(FALSE);
}

/****************************************************************************
 NullSkyRasterSetImage

 The raster is only set if it has a valid pixel pointer

 On entry   : Raster (MODIFY)
            : Image
            : Flags
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRasterSetImage(void *pRaster, void *pImage, RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwImage            *ipImage = (RwImage *) pImage;
    RwInt32             nI, nJ;
    RwUInt8            *cpOut = (RwUInt8 *) rpRas->cpPixels;
    RwUInt8            *cpIn = (RwUInt8 *) ipImage->cpPixels;
    RwBool              alreadyPixelLocked = FALSE;
    RwBool              result = TRUE;

    RwRasterFormat      nFormat = RwRasterGetFormat(rpRas);

    RWFUNCTION(RWSTRING("NullSkyRasterSetImage"));

    /* Stop warnings */
    flags = flags;

    if (rpRas->privateFlags & rwRASTERPIXELLOCKEDWRITE)
    {
        alreadyPixelLocked = TRUE;
    }
    else
    {
        if (!RwRasterLock(rpRas, 0, rwRASTERLOCKWRITE))
        {
            RWRETURN(FALSE);
        }
    }

    switch (ipImage->depth)
    {
        case 4:
        case 8:
            {
                RwRGBA             *rpPal = ipImage->palette;

                /* Its a 4 or 8 bit image */

                switch (nFormat & rwRASTERFORMATPIXELFORMATMASK)
                {
                    case rwRASTERFORMAT888:
                        {
                            for (nI = 0; nI < rpRas->height; nI++)
                            {
                                RwUInt8            *npOut =
                                    (RwUInt8 *) cpOut;

                                for (nJ = 0; nJ < rpRas->width; nJ++)
                                {
                                    RwRGBA             *rpIn;

                                    rpIn = &rpPal[cpIn[nJ]];
                                    *(npOut++) = rpIn->red;
                                    *(npOut++) = rpIn->green;
                                    *(npOut++) = rpIn->blue;
                                }
                                cpOut += rpRas->stride;
                                cpIn += ipImage->stride;
                            }
                            break;
                        }
                    case rwRASTERFORMAT8888:
                        {
                            for (nI = 0; nI < rpRas->height; nI++)
                            {
                                RwRGBA             *npOut =
                                    (RwRGBA *) cpOut;

                                for (nJ = 0; nJ < rpRas->width; nJ++)
                                {
                                    RwRGBA             *rpIn;

                                    rpIn = &rpPal[cpIn[nJ]];

                                    /*(*npOut) =
                                     * (((RwUInt32) rpIn->red) << 24) |
                                     * (((RwUInt32) rpIn->green) << 16) |
                                     * (((RwUInt32) rpIn->blue) << 8) |
                                     * (((RwUInt32) rpIn->alpha) << 0); */
                                    *npOut = *rpIn;

                                    /* Next pixel */

                                    npOut++;
                                }

                                cpOut += rpRas->stride;
                                cpIn += ipImage->stride;
                            }

                            break;
                        }
                    default:
                        {
                            RWERROR((E_RW_INVRASTERFORMAT));
                            result = FALSE;
                        }
                }
                break;
            }
        case 32:
            {
                /* Its a 32 bit image */
                switch (nFormat & rwRASTERFORMATPIXELFORMATMASK)
                {
                    case rwRASTERFORMAT888:
                        {
                            for (nI = 0; nI < rpRas->height; nI++)
                            {
                                RwUInt8            *npOut =
                                    (RwUInt8 *) cpOut;
                                RwRGBA             *rpIn =
                                    (RwRGBA *) cpIn;

                                for (nJ = 0; nJ < rpRas->width; nJ++)
                                {
                                    *(npOut++) = rpIn->red;
                                    *(npOut++) = rpIn->green;
                                    *(npOut++) = rpIn->blue;

                                    rpIn++;
                                }
                                cpOut += rpRas->stride;
                                cpIn += ipImage->stride;
                            }
                            break;
                        }
                    case rwRASTERFORMAT8888:
                        {

                            for (nI = 0; nI < rpRas->height; nI++)
                            {
                                RwRGBA             *npOut =
                                    (RwRGBA *) cpOut;
                                RwRGBA             *rpIn =
                                    (RwRGBA *) cpIn;

                                for (nJ = 0; nJ < rpRas->width; nJ++)
                                {
                                    /*(*npOut) =
                                     * (((RwUInt32) rpIn->red) << 24) |
                                     * (((RwUInt32) rpIn->green) << 16) |
                                     * (((RwUInt32) rpIn->blue) << 8) |
                                     * (((RwUInt32) rpIn->alpha) << 0); */
                                    *npOut = *rpIn;

                                    /* Next pixel */

                                    npOut++;
                                    rpIn++;
                                }

                                cpOut += rpRas->stride;
                                cpIn += ipImage->stride;
                            }

                            break;
                        }
                    default:
                        {
                            RWERROR((E_RW_INVRASTERFORMAT));
                            result = FALSE;
                        }
                }
                break;
            }
        default:
            {
                RWERROR((E_RW_INVIMAGEDEPTH));
                result = FALSE;
            }
    }

    if (!alreadyPixelLocked)
    {
        RwRasterUnlock(rpRas);
    }
    RWRETURN(result);
}

/****************************************************************************
 NullSkyTextureSetRaster

 On entry   : Texture
            : Raster
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyTextureSetRaster(void *pTex, void *pRas, RwInt32 nIn)
{
    RwTexture          *tex = (RwTexture *) pTex;
    RwRaster           *rpRas = (RwRaster *) pRas;

    RWFUNCTION(RWSTRING("NullSkyTextureSetRaster"));

    /* Stop warnings */
    nIn = nIn;

    /* Try and set the raster */
    tex->raster = rpRas;

    /* All done */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyGetRasterFormat

 On entry   :
            : Raster
            : Flags
 On exit    :
 */
static              RwBool
NullSkyGetRasterFormat(void *pInOut, void *pRaster, RwInt32 flags)
{
    RwRaster           *rpRas = (RwRaster *) pRaster;
    RwInt32             nFormat = flags & (RwInt32) rwRASTERFORMATMASK;

    RWFUNCTION(RWSTRING("NullSkyGetRasterFormat"));

    /* Stop warnings */
    pInOut = pInOut;

    /* Only 16 bits per pixel supported for Z buffers, 32 bits for all others */

    /* Copy over types */
    rpRas->cType = (RwUInt8) (flags & (RwInt32) rwRASTERTYPEMASK);
    rpRas->cFlags = (RwUInt8) (flags & (RwInt32) (~rwRASTERTYPEMASK));

    /* The types */

    /* If is not a camera buffer, then we need to allocate real memory for it
     */

    switch (rpRas->cType)
    {
        case rwRASTERTYPETEXTURE:
            {
                if ((nFormat & rwRASTERFORMATPIXELFORMATMASK) ==
                    rwRASTERFORMATDEFAULT)
                {
                    nFormat |= rwRASTERFORMAT8888;
                    rpRas->depth = 32;
                }
                else
                {
                    if (nFormat & rwRASTERFORMAT888)
                    {
                        rpRas->depth = 24;
                    }
                    else if (nFormat & rwRASTERFORMAT8888)
                    {
                        rpRas->depth = 32;
                    }
                    else
                    {
                        RWERROR((E_RW_INVRASTERFORMAT));
                        RWRETURN(FALSE);
                    }
                }
                rpRas->cFormat = (RwUInt8) (nFormat >> 8);
                break;
            }
        case rwRASTERTYPENORMAL:
        case rwRASTERTYPECAMERA:
            {
                if (!rpRas->depth)
                {
                    rpRas->depth = 32;
                }
                else if (rpRas->depth != 32)
                {
                    RWRETURN(FALSE);
                }

                /* By default textures are 8888 */
                if (nFormat == (RwInt32) rwRASTERFORMATDEFAULT)
                {
                    nFormat = (RwInt32) rwRASTERFORMAT8888;
                }

                rpRas->cFormat = (RwUInt8) (nFormat >> 8);

                break;
            }
        case rwRASTERTYPEZBUFFER:
            {
                if (!rpRas->depth)
                {
                    rpRas->depth = 16;
                }
                else if (rpRas->depth != 16)
                {
                    RWRETURN(FALSE);
                }

                /* By default, Z buffers of 16 bit */
                if (nFormat == (RwInt32) rwRASTERFORMATDEFAULT)
                {
                    nFormat = (RwInt32) rwRASTERFORMAT16;
                }

                rpRas->cFormat = (RwUInt8) (nFormat >> 8);

                break;
            }
        default:
            {
                RWRETURN(FALSE);
            }
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyRGBToPixel

 On entry   : palette value (OUT)
            : palette entry (IN)
            : 0
 On exit    : TRUE on success
 */
static              RwBool
NullSkyRGBToPixel(void *pPixel, void *pCol, RwInt32 nFormat)
{
    RwRGBA             *rpCol = (RwRGBA *) pCol;

    RWFUNCTION(RWSTRING("NullSkyRGBToPixel"));

    switch (nFormat & (RwInt32) rwRASTERFORMATPIXELFORMATMASK)
    {
        case rwRASTERFORMAT8888:
        case rwRASTERFORMATDEFAULT:
            {
                *((RwUInt32 *) pPixel) =
                    (((RwUInt32) rpCol->red) << 24) |
                    (((RwUInt32) rpCol->green) << 16) |
                    (((RwUInt32) rpCol->blue) << 8) |
                    (((RwUInt32) rpCol->alpha) << 0);

                break;
            }
        case rwRASTERFORMAT888:
            {
                *((RwUInt32 *) pPixel) =
                    (((RwUInt32) rpCol->red) << 16) |
                    (((RwUInt32) rpCol->green) << 8) |
                    (((RwUInt32) rpCol->blue) << 0);
                break;
            }
        default:
            {
                RWERROR((E_RW_INVRASTERFORMAT));
                RWRETURN(FALSE);
            }
    }

    /* All done */
    RWRETURN(TRUE);
}

/****************************************************************************
 NullSkyImageFindFormat

 Finds if an image is or has an alpha channel

 On entry   : Image
            : Raster format (888 if not masked, 8888 otherwise) (OUT)
 On exit    :
 */

static void
NullSkyImageFindFormat(RwImage * image, RwInt32 * format)
{
    RwInt32             x, y;
    RwInt32             width, height, stride, depth;
    RwUInt8            *pixels;

    RWFUNCTION(RWSTRING("NullSkyImageFindFormat"));
    RWASSERT(image);

    width = RwImageGetWidth(image);
    height = RwImageGetHeight(image);
    stride = RwImageGetStride(image);
    depth = RwImageGetDepth(image);
    pixels = RwImageGetPixels(image);

    *format = 0;

    if ((depth == 4) || (depth == 8))
    {
        /* Its a 4 or 8 bit image */
        RwRGBA             *palette = RwImageGetPalette(image);

        for (y = 0; y < height; y++)
        {
            RwUInt8            *currPixel = pixels;

            for (x = 0; x < width; x++)
            {
                if (palette[*currPixel].alpha != 0xff)
                {
                    /* has an alpha channel */
                    (*format) |= rwRASTERFORMAT8888;

                    RWRETURNVOID();
                }

                /* Next pixel */

                currPixel++;
            }

            pixels += stride;
        }

        /* Give the appropriate format */
        (*format) |= rwRASTERFORMAT888;
    }
    else if (depth == 32)
    {
        /* We have an 32 bit image */
        for (y = 0; y < height; y++)
        {
            RwRGBA             *currPixel = (RwRGBA *) pixels;

            for (x = 0; x < width; x++)
            {
                if (currPixel->alpha != 0xff)
                {
                    /* has an alpha channel */
                    (*format) |= rwRASTERFORMAT8888;

                    RWRETURNVOID();
                }

                /* Next pixel */

                currPixel++;
            }

            pixels += stride;
        }

        /* Give the appropriate format */
        (*format) |= rwRASTERFORMAT888;
    }

    RWRETURNVOID();
}

#endif /* (0) */
