/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * texture.c - Functions for managing textures and setting texture states.  *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "..\..\util\regdef.h"
#include "..\..\util\defines.h"
#include "..\..\util\main.h"
#include "..\..\util\cce.h"
#include "texture.h"
#include "cntx3d.h"
#include "memmgr.h"

extern CONTEXT3D gContext3D;
extern DWORD gCommandBuf[];

BOOL gbFlushTextureCache = FALSE;


/****************************************************************************
 * SetTexReg															    *
 *  Function: Write a Rage 128 texture register.                            *
 *    Inputs: reg - register to write to.								    *
 *			  data - bitfield data to be written.						    *	
 *			  shift - bits to shift left data.							    *
 *			  mask - mask for bitfield.									    *
 *   Outputs: none                                                          *
 ****************************************************************************/

static void SetTexReg (DWORD reg, DWORD data, DWORD shift, DWORD mask)
{
    int i = 0;
	DWORD* preg;

    // Set preg to point to the member of 'gContext3D' corresponding to the
    // texture register 'reg'. Members regDST_PITCH_OFFSET_C to
    // regPLANE_3D_MASK_C represent a sequential series of registers.
    // Therefore, the member of 'gContext3D' corresponding to 'reg' may be
    // found by subtracting DST_PITCH_OFFSET_C from 'reg' and using the result
    // as an offset from gContext3D.regDST_PITCH_OFFSET_C.

    preg = (DWORD*) ((DWORD)&(gContext3D.regDST_PITCH_OFFSET_C)
        + (reg - DST_PITCH_OFFSET_C));

	*preg &= ~(mask << shift);
    *preg |= (data << shift);
    gCommandBuf[i++] = CCE_PACKET0 | (reg >> 2);
    gCommandBuf[i++] = *preg;
    R128_CCESubmitPackets (gCommandBuf, i);
}


/****************************************************************************
 * R128_SetTexture												            *
 *  Function: Set the current primary or secondary texture.				    *
 *    Inputs: stage - texture stage assignment for this texture:            *
 *					  0 - primary										    *
 *					  1 - secondary										    *	
 *   Outputs: TRUE - successful.                                            *
 *			  FALSE - unsuccessful.										    *
 ****************************************************************************/

BOOL R128_SetTexture (DWORD stage, LPTEXINFO ptexinfo)
{
	int i;
	DWORD texsize;
	DWORD tex_cntl_reg;

	if (ptexinfo == NULL)
		return FALSE;

	// Set target control register according to texture stage.

    if (stage == 0)
	{
		tex_cntl_reg = PRIM_TEX_CNTL_C;
	}
    else if (stage == 1)
	{
		tex_cntl_reg = SEC_TEX_CNTL_C;
	}
	else
	{
		return FALSE;
	}

	// Validate and set the texture format.

	switch (ptexinfo->Format)
	{
	case TEXFORMAT_VQ:		
	case TEXFORMAT_CI4:		
	case TEXFORMAT_CI8:		
	case TEXFORMAT_ARGB1555:	
	case TEXFORMAT_RGB565:	
	case TEXFORMAT_RGB888:	
	case TEXFORMAT_ARGB8888:	
	case TEXFORMAT_RGB332:	
	case TEXFORMAT_Y8:		
	case TEXFORMAT_RGB8:		
	case TEXFORMAT_CI16:		
	case TEXFORMAT_YUV422:	
	case TEXFORMAT_YUV422_2:	
	case TEXFORMAT_AYUV444:	
	case TEXFORMAT_ARGB4444:	
		break;

	default:
		return FALSE;
	}

	SetTexReg (tex_cntl_reg, (DWORD) ptexinfo->Format, 16, 0x0000000f); 

	//  TEX_SIZE_PITCH_C:

	// Set the TEX_SIZE field to the larger of ptexinfo->Log2X
	// and ptexinfo->Log2Y.

	texsize = ptexinfo->Log2X > ptexinfo->Log2Y ? ptexinfo->Log2X : ptexinfo->Log2Y;

	i = 0;
    gCommandBuf[i++] = CCE_PACKET0 | (TEX_SIZE_PITCH_C >> 2);

    if (stage == 0)
	{
        gContext3D.regTEX_SIZE_PITCH_C &= 0xffff0000;
        gCommandBuf[i++] = gContext3D.regTEX_SIZE_PITCH_C |= (
            ptexinfo->Log2X |
            (texsize << 4) |
            (ptexinfo->Log2Y << 8) |
            (texsize << 12));

		//  PRIM_TEX_0_OFFSET_C:

        gCommandBuf[i++] = gContext3D.regPRIM_TEX_0_OFFSET_C =
            ptexinfo->Offset[0];

		// Send the packet.

		gCommandBuf[0] |= ((i - 2) << 16);
		R128_CCESubmitPackets (gCommandBuf, i);
	}
    else if (stage == 1)
	{
        gContext3D.regTEX_SIZE_PITCH_C &= 0x0000ffff;
        gCommandBuf[i++] = gContext3D.regTEX_SIZE_PITCH_C |= (
            (ptexinfo->Log2X << 16) |
            (texsize << 20) |
            (ptexinfo->Log2Y << 24) |
            (texsize << 28));

		// Send the packet for TEX_SIZE_PITCH_C.

		R128_CCESubmitPackets (gCommandBuf, i);

		i = 0;
        gCommandBuf[i++] = CCE_PACKET0 | (SEC_TEX_0_OFFSET_C >> 2);
        gCommandBuf[i++] = gContext3D.regSEC_TEX_0_OFFSET_C =
            ptexinfo->Offset[0];

		// Send the packet.

		R128_CCESubmitPackets (gCommandBuf, i);
	}
    else
	{
		return FALSE;
	}

	// Set flag to force texture cache flush at the start of the next 
	// primitive.

    gbFlushTextureCache = TRUE;

	return TRUE;
}


/****************************************************************************
 * R128_SetTextureState										                *
 *  Function: set an enumerated texture state.                              *
 *    Inputs: stage - stage identifier:										*
 *					  0 - primary											*
 *					  1 - secondary											*
 *			  eTexState - ETEXSTATE enum of state to be set.				*
 *			  data - state-sepcific data to be set.							*
 *   Outputs: TRUE - successful.                                            *
 *			  FALSE - unsuccessful.											*
 ****************************************************************************/

BOOL R128_SetTextureState (DWORD stage, ETEXSTATE eTexState, DWORD data)
{
	DWORD tex_cntl_reg, tex_comb_cntl_reg;

	switch (stage)
	{
	case 0:
		tex_cntl_reg = PRIM_TEX_CNTL_C;
		tex_comb_cntl_reg = PRIM_TEXTURE_COMBINE_CNTL_C;
		break;

	case 1:
		tex_cntl_reg = SEC_TEX_CNTL_C;
        tex_comb_cntl_reg = SEC_TEX_COMBINE_CNTL_C;
		break;

	default:
		return FALSE;
	}

	switch (eTexState)
	{

	// Enable texture mapping.

	case TEXSTATE_ENABLE:

		// Set TEX_EN field.
		
		SetTexReg (TEX_CNTL_C, (data & 1), 4, 0x00000001);

		break;

	// Enable secondary texture.

	case TEXSTATE_SEC_ENABLE:

		// Set SECONDARY_TEX_EN field.
		
		SetTexReg (TEX_CNTL_C, (data & 1), 5, 0x00000001);

		break;

	// Enable texture chroma key.

	case TEXSTATE_CHROMAKEY_ENABLE:

		// Set TEX_CHROMA_KEY_EN field.
		
		SetTexReg (TEX_CNTL_C, (data & 1), 12, 0x00000001);

		break;

	// Enable alpha masking.

	case TEXSTATE_ALPHAMASK_ENABLE:

		// Set TEX_AMASK_EN field.
		
		SetTexReg (TEX_CNTL_C, (data & 1), 13, 0x00000001);

		break;

	// Select S,T set for secondary texture.

	case TEXSTATE_SELECTST:

		if (stage != 1) return FALSE;

		switch ((ESELECTST)data)
		{
		case SELECTST_PRIM:
		case SELECTST_SEC:
			break;

		default:
			return FALSE;
		}

		// Set SEC_SRC_SEL_ST field.

		SetTexReg (tex_cntl_reg, data, 0, 0x00000001);

		break;

	// Select W for  secondary texture.

    case TEXSTATE_SELECTW:

		if (stage != 1) return FALSE;

        switch ((ESELECTW)data)
		{
        case SELECTW_PRIM:
        case SELECTW_SEC:
			break;

		default:
			return FALSE;
		}

        // Set SEC_SRC_SEL_W field.

        SetTexReg (tex_cntl_reg, data, 15, 0x00000001);

		break;

	// Set minification texture filtering state.

	case TEXSTATE_MINBLEND:

		switch ((EMINBLEND)data)
		{
		case MINBLEND_NEAREST:
		case MINBLEND_BILINEAR:
		case MINBLEND_MIPNEAREST:
		case MINBLEND_MIPLINEAR:
		case MINBLEND_1X1:
		case MINBLEND_TRILINEAR:
			break;

		default:
			return FALSE;
		}

		// Set [PRIM|SEC]_MIN_BLEND_FCN field.

		SetTexReg (tex_cntl_reg, data, 1, 0x00000007);

		break;

	// Set magnification texture filtering state.

	case TEXSTATE_MAGBLEND:

		switch ((EMAGBLEND)data)
		{
		case MAGBLEND_NEAREST:
		case MAGBLEND_BILINEAR:
			break;

		default:
			return FALSE;
		}

		// Set [PRIM|SEC]_MAG_BLEND_FCN field.

		SetTexReg (tex_cntl_reg, data, 4, 0x00000007);

		break;

	// Enable mipmapping.

	case TEXSTATE_MIMAP_ENABLE:

		// Set [PRIM|SEC]_MIP_MAP_DIS field.

		if (data == FALSE)
			SetTexReg (tex_cntl_reg, 1, 7, 0x00000001);
		else
			SetTexReg (tex_cntl_reg, 0, 7, 0x00000001);
		break;

	// Set S coordinate clamp state.

	case TEXSTATE_SCLAMP_MODE:

		switch ((ECLAMP)data)
		{
		case CLAMP_WRAP:
		case CLAMP_MIRROR:
		case CLAMP_CLAMP:
		case CLAMP_BORDER_COLOR:
			break;

		default:
			return FALSE;
		}

		// Set [PRIM|SEC]_TEXTURE_CLAMP_MODE_S field.

		SetTexReg (tex_cntl_reg, data, 8, 0x00000003);

		break;

	// Set S coordinate wrap state.

	case TEXSTATE_SWRAP_MODE:

		// Set [PRIM|SEC]_TEX_WRAP_S field.

		SetTexReg (tex_cntl_reg, (data & 0x00000001), 10, 0x00000001);

		break;

	// Set T coordinate clamp state.

	case TEXSTATE_TCLAMP_MODE:

		switch ((ECLAMP)data)
		{
		case CLAMP_WRAP:
		case CLAMP_MIRROR:
		case CLAMP_CLAMP:
		case CLAMP_BORDER_COLOR:
			break;

		default:
			return FALSE;
		}

		// Set [PRIM|SEC]_TEXTURE_CLAMP_MODE_T field.

		SetTexReg (tex_cntl_reg, data, 11, 0x00000003);

		break;

	// Set T coordinate wrap state.

    case TEXSTATE_TWRAP_MODE:

		// Set [PRIM|SEC]_TEX_WRAP_T field.

		SetTexReg (tex_cntl_reg, (data & 0x00000001), 13, 0x00000001);

		break;

	// Enable perspective correction.

	case TEXSTATE_PERSP_CORR_ENABLE:

		// Set [PRIM|SEC]_TEX_PERSPECTIVE_DIS field.

		if (data == FALSE)
			SetTexReg (tex_cntl_reg, 1, 14, 0x00000001);
		else
			SetTexReg (tex_cntl_reg, 0, 14, 0x00000001);
		break;

	// Texture palette.

	case TEXSTATE_PAL_OFF:

		switch ((EPALETTE)data)
		{
		case PALETTE_EITHER:
		case PALETTE_1:
		case PALETTE_2:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_PALETTE_OFF field.

		SetTexReg (tex_cntl_reg, data, 20, 0x0000000f);

		break;

	// Psuedo color.

	case TEXSTATE_PSUEDO_DATATYPE:

		switch ((EPSUEDOCOLOR)data)
		{
		case PSUEDOCOLOR_RGB565:
		case PSUEDOCOLOR_RGBA1555:
		case PSUEDOCOLOR_RGBA4444:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_PSUEDO_DATATYPE field.

		SetTexReg (tex_cntl_reg, data, 24, 0x00000003);

		break;

	// Set color combine function.

	case TEXSTATE_COMB_FNC:

		switch ((ETEXCOMBFNC)data)
		{
        case TEXCOMBFNC_DISABLE:
		case TEXCOMBFNC_COPY:
		case TEXCOMBFNC_COPYINPUT:
		case TEXCOMBFNC_MODULATE:
		case TEXCOMBFNC_MODULATE2X:
		case TEXCOMBFNC_MODULATE4X:
		case TEXCOMBFNC_ADD:
		case TEXCOMBFNC_ADDSIGNED:
		case TEXCOMBFNC_BLEND_VERTEX:
		case TEXCOMBFNC_BLEND_TEXTURE:
		case TEXCOMBFNC_BLEND_CONSTANT:
		case TEXCOMBFNC_BLEND_PREMULTIPLY:
		case TEXCOMBFNC_BLEND_PREVIOUS:
		case TEXCOMBFNC_BLEND_PREMULTIPLY_INVERSE:
		case TEXCOMBFNC_ADDSIGNED2X:
		case TEXCOMBFNC_BLEND_CONSTANTCOLOR:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_COMB_FCN field.

		SetTexReg (tex_comb_cntl_reg, data, 0, 0x0000000f);

		break;

	// Set color factor.

	case TEXSTATE_COLOR_FACTOR:

		switch ((EFACTOR)data)
		{
		case FACTOR_TEXTURECOLOR:
		case FACTOR_NTEXTURECOLOR:
		case FACTOR_TEXTUREALPHA:
		case FACTOR_NTEXTUREALPHA:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_COLOR_FACTOR field.

		SetTexReg (tex_comb_cntl_reg, data, 4, 0x0000000f);

		break;

	// Set color input factor.

	case TEXSTATE_INPUT_FACTOR:

		switch((EINPUTFACTOR) data)
		{
		case INPUTFACTOR_CONSTANTCOLOR:
		case INPUTFACTOR_CONSTANTALPHA:
		case INPUTFACTOR_INTERPCOLOR:
		case INPUTFACTOR_INTERPALPHA:
			break;

		case INPUTFACTOR_PREVCOLOR:
		case INPUTFACTOR_PREVALPHA:
			if (stage == 0) 
				return FALSE;
			break;


		default:
            return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_INPUT_FACTOR field.

		SetTexReg (tex_comb_cntl_reg, data, 10, 0x00000007);

		break;

	// Set alpha combine function.

	case TEXSTATE_COMB_FNC_ALPHA:

		switch ((ETEXCOMBFNC)data)
		{
        case TEXCOMBFNC_DISABLE:
        case TEXCOMBFNC_COPY:
        case TEXCOMBFNC_COPYINPUT:
        case TEXCOMBFNC_MODULATE:
        case TEXCOMBFNC_MODULATE2X:
        case TEXCOMBFNC_MODULATE4X:
        case TEXCOMBFNC_ADD:
        case TEXCOMBFNC_ADDSIGNED:
        case TEXCOMBFNC_ADDSIGNED2X:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_COMB_FCN_ALPHA field.

		SetTexReg (tex_comb_cntl_reg, data, 14, 0x0000000f);

		break;

	// Set alpha factor.

	case TEXSTATE_ALPHA_FACTOR:

		switch ((EFACTOR)data)
		{
		case FACTOR_TEXTUREALPHA:
		case FACTOR_NTEXTUREALPHA:
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_ALPHA_FACTOR field.

		SetTexReg (tex_comb_cntl_reg, data, 18, 0x0000000f);

		break;

	// Set input alpha factor.

	case TEXSTATE_INPUT_FACTOR_ALPHA:

		switch ((EINPUTFACTORALPHA) data)
		{
		case INPUTFACTORALPHA_CONSTANTALPHA:
		case INPUTFACTORALPHA_INTERPALPHA:
			break;

		case INPUTFACTORALPHA_PREVALPHA:
			if (stage == 0)
				return FALSE;
			break;

		default:
			return FALSE;
		}

		// Set [PRIMARY|SECONDARY]_INPUT_FACTOR_ALPHA field.

		SetTexReg (tex_comb_cntl_reg, data, 25, 0x00000007);

		break;

	// Set border color.

	case TEXSTATE_BORDER_COLOR:

		if (stage == 0)
		{
			SetTexReg (PRIM_TEXTURE_BORDER_COLOR_C, data, 0, 0xffffffff);
		}
		else if (stage == 1)
		{
			SetTexReg (SEC_TEXTURE_BORDER_COLOR_C, data, 0, 0xffffffff);
		}

		break;

	// Set post multi-texture color lighting function.

	case TEXSTATE_TEX_LIGHT_FCN:

		switch ((ETEXCOMBFNC)data)
		{
        case TEXCOMBFNC_DISABLE:
		case TEXCOMBFNC_COPY:
		case TEXCOMBFNC_COPYINPUT:
		case TEXCOMBFNC_MODULATE:
		case TEXCOMBFNC_MODULATE2X:
		case TEXCOMBFNC_MODULATE4X:
		case TEXCOMBFNC_ADD:
		case TEXCOMBFNC_ADDSIGNED:
		case TEXCOMBFNC_BLEND_VERTEX:
		case TEXCOMBFNC_BLEND_TEXTURE:
		case TEXCOMBFNC_BLEND_CONSTANT:
		case TEXCOMBFNC_BLEND_PREVIOUS:
			break;

		default:
			return FALSE;
		}

		// Set TEX_LIGHT_FCN field.

        SetTexReg (TEX_CNTL_C, data, 14, 0x0000000f);

		break;

	// Set post multi-texture alpha lighting function.

	case TEXSTATE_ALPHA_LIGHT_FCN:

		switch ((ETEXCOMBFNC)data)
		{
        case TEXCOMBFNC_DISABLE:
		case TEXCOMBFNC_COPY:
		case TEXCOMBFNC_COPYINPUT:
		case TEXCOMBFNC_MODULATE:
		case TEXCOMBFNC_MODULATE2X:
		case TEXCOMBFNC_MODULATE4X:
		case TEXCOMBFNC_ADD:
		case TEXCOMBFNC_ADDSIGNED:
			break;

		default:
			return FALSE;
		}

		// Set ALPHA_LIGHT_FCN field.

        SetTexReg (TEX_CNTL_C, data, 18, 0x00000007);

		break;

	default:
		return FALSE;
	}// switch

    return TRUE;
}


/****************************************************************************
 * R128_LoadTextureBMP_ARGB8888                                             *
 *  Function: Loads a BITMAP image into video memory in ARGB8888 format and *
 *			  sets its TEXINFO structure. Note that two versions of the     *
 *            function are presented. The first loads texture data through  *
 *            a Type-3 HOSTDATA_BLT packet. This allows the data load to be *
 *            synched up with the drawing stream. The second method,        *
 *            enabled by defining LOAD_TEXTURE_NO_HOSTDATA_BLT, copies the  *
 *            bitmap data directly into memory using the linear apperture.  *
 *    Inputs: texfile - texture bitmap file name.                           *
 *			  ptexinfo - pointer to TEXINFO struct to be filled.			*
 *   Outputs: TRUE - successful.                                            *
 *			  FALSE - unsuccessful.											*
 ****************************************************************************/

#ifndef LOAD_TEXTURE_NO_HOSTDATA_BLT

BOOL R128_LoadTextureBMP_ARGB8888 (const char* texfile, LPTEXINFO ptexinfo)
{
	FILE* fp = NULL;
	BITMAPINFOHEADER bmih;
	BITMAPFILEHEADER bmfh;
    char* scanlinebuf;
	int i, x, y, scanlinesize;
	DWORD Log2X, Log2Y;
	DWORD texoffset;
	BOOL retcode = FALSE;
	DWORD* HostdataBltPacket = NULL; 
	int datawriteindex;
	DWORD data;
    DWORD savepcguictlstat, savepcguimode;

	// Validate argument.

	if ((texfile == NULL) || (ptexinfo == NULL))
		goto exit_load_bmp_argb_8888;

	// Validate texture filename extension.

	if (_strnicmp (&texfile[strlen(texfile)-4], ".bmp", 4) != 0)
		goto exit_load_bmp_argb_8888;

	// Attempt to open the texture bitmap file.

    if ((fp = fopen (texfile, "rb")) == NULL)
		goto exit_load_bmp_argb_8888;

	// Read the BITMAPFILEHEADER struct.

	fread (&bmfh, sizeof (bmfh), 1, fp);

	// Verify it's of type BM.

	if (bmfh.bfType != 0x4d42) //BM
		goto exit_load_bmp_argb_8888;

	// Read BITMAPFILEHEADER struct.
	
	fread (&bmih, sizeof (bmih), 1, fp);

	// Verify dimensions are power of two.

	// Width:

	for (Log2X=1; Log2X <= 10; Log2X++)
		if ((1 << Log2X) == bmih.biWidth) break;

	if (Log2X == 11)
		goto exit_load_bmp_argb_8888;

	// Height:

	for (Log2Y=1; Log2Y <= 10; Log2Y++)
		if ((1 << Log2Y) == bmih.biHeight) break;

	if (Log2Y == 11)
		goto exit_load_bmp_argb_8888;

	// Make sure compression type is B_RGB

	if (bmih.biCompression != BI_RGB)
		goto exit_load_bmp_argb_8888;

	// Current restriction: we only process 24 bpp. May add support
	// for CI8 in the future.

	if (!((bmih.biBitCount == 24) && (bmih.biPlanes == 1)))
		goto exit_load_bmp_argb_8888;


	// Allocate a buffer to read one scal line ata a time
	// from the bitmap file. First, compute the size.

	if (bmih.biSizeImage != 0)
		scanlinesize = bmih.biSizeImage / bmih.biHeight;
	else
		scanlinesize = (bmih.biBitCount >> 3) * bmih.biWidth;

	scanlinebuf = (char*) malloc (scanlinesize);
	if (scanlinebuf == NULL)
		goto exit_load_bmp_argb_8888;

	// Allocate a block of video memory for this texture.

    texoffset = R128_AllocBuffer (bmih.biWidth * 4 * bmih.biHeight);
	if (texoffset == 0xffffffff)
		goto exit_load_bmp_argb_8888;

	// Allocate memory for HOSTDATA_BLT packet. size will be...
	x = ((bmih.biBitCount + 8) >> 3) * bmih.biWidth;
	x += (12 << 2); // for header and itbody

	HostdataBltPacket = (DWORD*) malloc (x);
	if (!HostdataBltPacket) 
		goto exit_load_bmp_argb_8888;

	// Setup a HOST_BLT packet

    R128_WaitForFifo(2);
    savepcguimode = regr(PC_GUI_MODE);
    savepcguictlstat = regr(PC_GUI_CTLSTAT);

    i = 0;

	// The read cache needs to be invalidated, and the ignore UNIFY hint
	// set, to avoid a hardware hang that may occur when mixing the host 
	// blit with other PIO access to the frame buffer. Flushing the pixel
	// cache is also necessary to work around a hardware bug in AGP host 
	// writes.

    // Set UNIFY ignore bit in PC_GUI_MODE.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_MODE >> 2);
    gCommandBuf[i++] = savepcguimode | (0x1 << 5);

    // Flush pixel cache and set read invalid status.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[i++] = savepcguictlstat | (0x1 << 2) | (0x3);

    R128_CCESubmitPackets (gCommandBuf, i);

    i = 0;

    HostdataBltPacket[i++] = CCE_PACKET3_CNTL_HOSTDATA_BLT |
        ((6 + bmih.biWidth) << 16); // size of IT_BODY - 1

	HostdataBltPacket[i++] = 
		GMC_SRC_PITCH_OFFSET_DEFAULT |
        GMC_DST_PITCH_OFFSET_LEAVE |
        GMC_SRC_CLIP_DEFAULT |
        GMC_DST_CLIP_DEFAULT |
        (0xf << 4) |
        GMC_DST_32BPP | // changed
        GMC_SRC_DSTCOLOR |
        GMC_BYTE_ORDER_MSB_TO_LSB |
        GMC_DP_CONVERSION_TEMP_6500 |
        ROP3_SRCCOPY |
        GMC_DP_SRC_HOST | // changed
        GMC_3D_FCN_EN_CLR | // changed
        GMC_DST_CLR_CMP_FCN_CLEAR |
        GMC_AUX_CLIP_CLEAR |
        GMC_WRITE_MASK_SET;

	// Setup body

    HostdataBltPacket[i++] =  // DST_PITCH_OFFSET
         (texoffset >> 5) |
         ((bmih.biWidth >> 3) << 21);

	// Data block

    HostdataBltPacket[i++] = 0xffffffff;  // FRGD_COLOUR
    HostdataBltPacket[i++] = 0xffffffff;  // BKGD_COLOUR

	datawriteindex = i;

	// Copy bitmap data to offscreen local video memory.

    for (y = (bmih.biHeight - 1); y >= 0; y--)
	{
		i = datawriteindex;

        HostdataBltPacket[i++] = y << 16;  // BaseY BaseX. x implicit 0
        HostdataBltPacket[i++] = (1 << 16) |  bmih.biWidth;  // Height Width
        HostdataBltPacket[i++] = bmih.biWidth;  // Number

		// Read a scanline from the bitmap file.

		fread (scanlinebuf, sizeof (char), scanlinesize, fp);

		// Copy the scanline to memory.

		for (x = 0; x < bmih.biWidth; x++)
		{
            data = 
				scanlinebuf[(x*3)] | 
				(scanlinebuf[(x*3)+1] << 8) |
				(scanlinebuf[(x*3)+2] << 16) |
				0xff000000;

			HostdataBltPacket[i++] = data;
		}

        // Submit scanline to the ring buffer.

	    R128_CCESubmitPackets (HostdataBltPacket, i);
	}

	// Restore DST_PITCH_OFFSET_C and DP_GUI_MASTER_CNTL.

	i = 0;
    gCommandBuf[i++] = CCE_PACKET0 | (DST_PITCH_OFFSET_C >> 2);
	gCommandBuf[i++] = gContext3D.regDST_PITCH_OFFSET_C;
	gCommandBuf[i++] = gContext3D.regDP_GUI_MASTER_CNTL;
    gCommandBuf[0] |= ((i - 2) << 16);
    R128_CCESubmitPackets (gCommandBuf, i);

    i = 0;
    gCommandBuf[i++] = CCE_PACKET0 | (SCALE_3D_CNTL >> 2);
    gCommandBuf[i++] = gContext3D.regSCALE_3D_CNTL;

	//  Flush pixel cache to force all data into memory before texel reads.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[i++] = savepcguictlstat | 0x3;

    // Restore PC_GUI_MODE

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_MODE >> 2);
    gCommandBuf[i++] = savepcguimode;

    R128_CCESubmitPackets (gCommandBuf, i);

	// Fill the texture's TEXINFO structure.

	strcpy (ptexinfo->filename, texfile);
    ptexinfo->Format = TEXFORMAT_ARGB8888;
	ptexinfo->Flags = 0; 
	ptexinfo->Log2X = Log2X;
	ptexinfo->Log2Y = Log2Y;
    ptexinfo->Pitch = bmih.biWidth * 4;
    ptexinfo->Offset[0] = texoffset;
    memset (&(ptexinfo->Offset[1]), 0, sizeof (DWORD) * 10);

	// Return success.

	retcode = TRUE;

exit_load_bmp_argb_8888:

	// Free resources.

	if (scanlinebuf)
		free (scanlinebuf);

	if (HostdataBltPacket) 
		free (HostdataBltPacket); 

	if (fp)
		fclose (fp);

	return (retcode);
}

#else // LOAD_TEXTURE_NO_HOSTDATA_BLT

BOOL R128_LoadTextureBMP_ARGB8888 (const char* texfile, LPTEXINFO ptexinfo)
{
	FILE* fp = NULL;
	BITMAPINFOHEADER bmih;
	BITMAPFILEHEADER bmfh;
	char* scanlinebuf, *pwrite;
	int x, y, scanlinesize;
	DWORD Log2X, Log2Y;
	DWORD texoffset;
	BOOL retcode = FALSE;

	// Validate argument.

	if ((texfile == NULL) || (ptexinfo == NULL))
		goto exit_load_bmp_argb_8888;

	// Validate texture filename extension.

	if (_strnicmp (&texfile[strlen(texfile)-4], ".bmp", 4) != 0)
		goto exit_load_bmp_argb_8888;

	// Attempt to open the texture bitmap file.

    if ((fp = fopen (texfile, "rb")) == NULL)
		goto exit_load_bmp_argb_8888;

	// Read the BITMAPFILEHEADER struct.

	fread (&bmfh, sizeof (bmfh), 1, fp);

	// Verify it's of type BM.

	if (bmfh.bfType != 0x4d42) //BM
		goto exit_load_bmp_argb_8888;

	// Read BITMAPFILEHEADER struct.
	
	fread (&bmih, sizeof (bmih), 1, fp);

	// Verify dimensions are power of two.

	// Width:

	for (Log2X=1; Log2X <= 10; Log2X++)
		if ((1 << Log2X) == bmih.biWidth) break;

	if (Log2X == 11)
		goto exit_load_bmp_argb_8888;

	// Height:

	for (Log2Y=1; Log2Y <= 10; Log2Y++)
		if ((1 << Log2Y) == bmih.biHeight) break;

	if (Log2Y == 11)
		goto exit_load_bmp_argb_8888;

	// Make sure compression type is B_RGB

	if (bmih.biCompression != BI_RGB)
		goto exit_load_bmp_argb_8888;

	// Current restriction: we only process 24 bpp. May add support
	// for CI8 in the future.

	if (!((bmih.biBitCount == 24) && (bmih.biPlanes == 1)))
		goto exit_load_bmp_argb_8888;


	// Allocate a buffer to read one scal line ata a time
	// from the bitmap file. First, compute the size.

	if (bmih.biSizeImage != 0)
		scanlinesize = bmih.biSizeImage / bmih.biHeight;
	else
		scanlinesize = (bmih.biBitCount >> 3) * bmih.biWidth * bmih.biHeight;

	scanlinebuf = (char*) malloc (scanlinesize);
	if (scanlinebuf == NULL)
		goto exit_load_bmp_argb_8888;

	// Allocate a block of video memory for this texture.

    texoffset = R128_AllocBuffer (bmih.biWidth * 4 * bmih.biHeight);
	if (texoffset == 0xffffffff)
		goto exit_load_bmp_argb_8888;

	// Copy bitmap data to offscreen local video memory.

    for (y = (bmih.biHeight - 1); y >= 0; y--)
	{
		// Set the write pointer to the start of the scanline.

        pwrite = (char*)(R128_AdapterInfo.virtual_MEM_BASE +
            texoffset + ((bmih.biWidth * 4) * y));

		// Read a scanline from the bitmap file.

		fread (scanlinebuf, sizeof (char), scanlinesize, fp);

		// Copy the scanline to memory.

		for (x = 0; x < bmih.biWidth; x++)
		{
            *pwrite++ = scanlinebuf[(x*3)];
            *pwrite++ = scanlinebuf[(x*3)+1];
            *pwrite++ = scanlinebuf[(x*3)+2];
            *pwrite++ = 255;
		}
	}

	//  Flush pixel cache to force all data into memory before texel reads.

	R128_WaitForFifo(1);
	y=regr(PC_GUI_CTLSTAT);
	x=0;
    gCommandBuf[x++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[x++] = y | 0x3;
    gCommandBuf[0] |= ((x - 2) << 16);
    R128_CCESubmitPackets (gCommandBuf, x);

	// Fill the texture's TEXINFO structure.

	strcpy (ptexinfo->filename, texfile);
    ptexinfo->Format = TEXFORMAT_ARGB8888;
	ptexinfo->Flags = 0; 
	ptexinfo->Log2X = Log2X;
	ptexinfo->Log2Y = Log2Y;
    ptexinfo->Pitch = bmih.biWidth * 4;
    ptexinfo->Offset[0] = texoffset;
    memset (&(ptexinfo->Offset[1]), 0, sizeof (DWORD) * 10);

	// Return success.

	retcode = TRUE;

exit_load_bmp_argb_8888:

	// Free resources.

	if (scanlinebuf)
		free (scanlinebuf);

	if (fp)
		fclose (fp);

	return (retcode);
}

#endif // LOAD_TEXTURE_NO_HOSTDATA_BLT


/****************************************************************************
 * R128_LoadTextureTGA_ARGB8888                                             *
 *  Function: Loads a Targa image into video memory in ARGB8888 format and  *
 *			  sets its TEXINFO structure.Note that two versions of the      *
 *            function are presented. The first loads texture data through  *
 *            a Type-3 HOSTDATA_BLT packet. This allows the data load to be *
 *            synched up with the drawing stream. The second method,        *
 *            enabled by defining LOAD_TEXTURE_NO_HOSTDATA_BLT, copies the  *
 *            bitmap data directly into memory using the linear apperture.  *
 *    Inputs: texfile - texture bitmap file name.                           *
 *			  ptexinfo - pointer to TEXINFO struct to be filled.			*
 *   Outputs: TRUE - successful.                                            *
 *			  FALSE - unsuccessful.											*
 ****************************************************************************/

#ifndef LOAD_TEXTURE_NO_HOSTDATA_BLT

BOOL R128_LoadTextureTGA_ARGB8888 (const char* texfile, LPTEXINFO ptexinfo)
{
    FILE *fp = NULL;
	TGAHEADERINFO* ptgainfo = NULL;
	DWORD Log2X, Log2Y;
	DWORD texoffset;
    DWORD i, x, y, scanlinesize, pitch;
	char *scanlinebuf = NULL;;
    char *lpSrc;
	BOOL retcode = FALSE;
	DWORD* HostdataBltPacket = NULL; 
	int datawriteindex;
	DWORD data;
    DWORD savepcguictlstat, savepcguimode;

	// Validate argument.

	if ((texfile == NULL) || (ptexinfo == NULL))
		goto exit_load_tga_argb_8888;

	// Validate texture filename extension.

	if (_strnicmp (&texfile[strlen(texfile)-4], ".tga", 4) != 0)
		goto exit_load_tga_argb_8888;

	ptgainfo = (TGAHEADERINFO*) malloc (sizeof (TGAHEADERINFO));
	if (ptgainfo == NULL)
        goto exit_load_tga_argb_8888;

	//Open texture map file for binary data reading.

	if ((fp = fopen (texfile, "rb")) == NULL)
	{
        goto exit_load_tga_argb_8888;
	}

	// Read TARGA header.

    fread (ptgainfo, sizeof (TGAHEADERINFO), 1, fp);

	// Verify dimensions are power of two.

	// Width:

	for (Log2X=1; Log2X <= 10; Log2X++)
		if ((1 << Log2X) == ptgainfo->imwidth) break;

	if (Log2X == 11)
		goto exit_load_tga_argb_8888;

	// Height:

	for (Log2Y=1; Log2Y <= 10; Log2Y++)
		if ((1 << Log2Y) == ptgainfo->imheight) break;

	if (Log2Y == 11)
		goto exit_load_tga_argb_8888;

	
	// Skip descriptive bytes at end of header, idlen specifies the number.

	if (fseek (fp, ptgainfo->idlen, SEEK_CUR) != 0)
	{
		goto exit_load_tga_argb_8888;
	}

	// Compute size of bitmap image scanline.

	scanlinesize = ptgainfo->imwidth * (int)(ptgainfo->imdepth / 8);

    // Compute video memory texture pitch.

    pitch = ptgainfo->imwidth * 4;

	// Allocate system meory buffer for scanline.

	scanlinebuf = (char*) malloc (scanlinesize);
	if (scanlinebuf == NULL)
		goto exit_load_tga_argb_8888;

	// Allocate a block of video memory for this texture.

    texoffset = R128_AllocBuffer (pitch * ptgainfo->imheight);
	if (texoffset == 0xffffffff)
		goto exit_load_tga_argb_8888;

	// Allocate memory for HOSTDATA_BLT packet. size will be...
    x = ptgainfo->imwidth << 2;
	x += (12 << 2); // for header and itbody

	HostdataBltPacket = (DWORD*) malloc (x);
	if (!HostdataBltPacket) 
        goto exit_load_tga_argb_8888;

    // Setup a HOSTDATA_BLT packet

    R128_WaitForFifo(2);
    savepcguimode = regr(PC_GUI_MODE);
    savepcguictlstat = regr(PC_GUI_CTLSTAT);

    i = 0;

	// The read cache needs to be invalidated, and the ignore UNIFY hint
	// set, to avoid a hardware hang that may occur when mixing the host 
	// blit with other PIO access to the frame buffer. Flushing the pixel
	// cache is also necessary to work around a hardware bug in AGP host 
	// writes.

    // Set UNIFY ignore bit in PC_GUI_MODE.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_MODE >> 2);
    gCommandBuf[i++] = savepcguimode | (0x1 << 5);

    // Flush pixel cache and set read invalid status.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[i++] = savepcguictlstat | (0x1 << 2) | (0x3);

    R128_CCESubmitPackets (gCommandBuf, i);

    i = 0;

    HostdataBltPacket[i++] = CCE_PACKET3_CNTL_HOSTDATA_BLT |
        ((6 + ptgainfo->imwidth) << 16); // size of IT_BODY - 1

	HostdataBltPacket[i++] = 
		GMC_SRC_PITCH_OFFSET_DEFAULT |
        GMC_DST_PITCH_OFFSET_LEAVE |
        GMC_SRC_CLIP_DEFAULT |
        GMC_DST_CLIP_DEFAULT |
        (0xf << 4) |
        GMC_DST_32BPP | // changed
        GMC_SRC_DSTCOLOR |
        GMC_BYTE_ORDER_MSB_TO_LSB |
        GMC_DP_CONVERSION_TEMP_6500 |
        ROP3_SRCCOPY |
        GMC_DP_SRC_HOST | // changed
        GMC_3D_FCN_EN_CLR | // changed
        GMC_DST_CLR_CMP_FCN_CLEAR |
        GMC_AUX_CLIP_CLEAR |
        GMC_WRITE_MASK_SET;

	// Setup body

    HostdataBltPacket[i++] =  // DST_PITCH_OFFSET
         (texoffset >> 5) |
         ((ptgainfo->imwidth >> 3) << 21);

	// Data block

    HostdataBltPacket[i++] = 0xffffffff;  // FRGD_COLOUR
    HostdataBltPacket[i++] = 0xffffffff;  // BKGD_COLOUR

	datawriteindex = i;

	// Copy data to video memory.

    for (y = 0; y < ptgainfo->imheight; y++)
	{
		i = datawriteindex;

        HostdataBltPacket[i++] = (ptgainfo->imheight - y - 1)
            << 16;  // BaseY BaseX. x implicit 0
        HostdataBltPacket[i++] = (1 << 16) | ptgainfo->imwidth;// Height Width
        HostdataBltPacket[i++] = ptgainfo->imwidth;  // Number

		// Read a scanline.

		fread (scanlinebuf, sizeof (char), scanlinesize, fp);
		lpSrc = scanlinebuf;

		// Copy scanline to video memory.

		for (x = 0; x < ptgainfo->imwidth; x++)
		{
			if(ptgainfo->imdepth == 32)
            {
                memcpy (&data, lpSrc, 4);
                lpSrc += 4;

                HostdataBltPacket[i++] = data;
            }
			else
            {
                data = 
                    scanlinebuf[(x*3)] | 
                    (scanlinebuf[(x*3)+1] << 8) |
                    (scanlinebuf[(x*3)+2] << 16) |
                    0xff000000;

                HostdataBltPacket[i++] = data;
            }
		}

        // Submit scanline to the ring buffer.

	    R128_CCESubmitPackets (HostdataBltPacket, i);
	}

	// Restore DST_PITCH_OFFSET_C and DP_GUI_MASTER_CNTL.

	i = 0;
    gCommandBuf[i++] = CCE_PACKET0 | (DST_PITCH_OFFSET_C >> 2);
	gCommandBuf[i++] = gContext3D.regDST_PITCH_OFFSET_C;
	gCommandBuf[i++] = gContext3D.regDP_GUI_MASTER_CNTL;
    gCommandBuf[0] |= ((i - 2) << 16);
    R128_CCESubmitPackets (gCommandBuf, i);

    i = 0;
    gCommandBuf[i++] = CCE_PACKET0 | (SCALE_3D_CNTL >> 2);
    gCommandBuf[i++] = gContext3D.regSCALE_3D_CNTL;

	//  Flush pixel cache to force all data into memory before texel reads.

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[i++] = savepcguictlstat | 0x3;

    // Restore PC_GUI_MODE

    gCommandBuf[i++] = CCE_PACKET0 | (PC_GUI_MODE >> 2);
    gCommandBuf[i++] = savepcguimode;

    R128_CCESubmitPackets (gCommandBuf, i);

	// Fill the texture's TEXINFO structure.

	strcpy (ptexinfo->filename, texfile);
    ptexinfo->Format = TEXFORMAT_ARGB8888;
	ptexinfo->Flags = 0; 
	ptexinfo->Log2X = Log2X;
	ptexinfo->Log2Y = Log2Y;
    ptexinfo->Pitch = ptgainfo->imwidth * 4;
    ptexinfo->Offset[0] = texoffset;
    memset (&(ptexinfo->Offset[1]), 0, sizeof (DWORD) * 10);

	// Return success.

	retcode = TRUE;

exit_load_tga_argb_8888:

	// Free resources.

	if (fp)
		fclose (fp);

	if (ptgainfo)
		free (ptgainfo);

	if (scanlinebuf)
		free (scanlinebuf);

	if (HostdataBltPacket) 
		free (HostdataBltPacket); 

	return (retcode);
}

#else // LOAD_TEXTURE_NO_HOSTDATA_BLT

BOOL R128_LoadTextureTGA_ARGB8888 (const char* texfile, LPTEXINFO ptexinfo)
{
    FILE *fp = NULL;
	TGAHEADERINFO* ptgainfo = NULL;
	DWORD Log2X, Log2Y;
	DWORD texoffset;
    DWORD x, y, scanlinesize, pitch;
	char *scanlinebuf = NULL;;
	char *lpDstLine, *lpDst, *lpSrc;
	BOOL retcode = FALSE;

	// Validate argument.

	if ((texfile == NULL) || (ptexinfo == NULL))
		goto exit_load_tga_argb_8888;

	// Validate texture filename extension.

	if (_strnicmp (&texfile[strlen(texfile)-4], ".tga", 4) != 0)
		goto exit_load_tga_argb_8888;

	ptgainfo = (TGAHEADERINFO*) malloc (sizeof (TGAHEADERINFO));
	if (ptgainfo == NULL)
        goto exit_load_tga_argb_8888;

	//Open texture map file for binary data reading.

	if ((fp = fopen (texfile, "rb")) == NULL)
	{
        goto exit_load_tga_argb_8888;
	}

	// Read TARGA header.

    fread (ptgainfo, sizeof (TGAHEADERINFO), 1, fp);

	// Verify dimensions are power of two.

	// Width:

	for (Log2X=1; Log2X <= 10; Log2X++)
		if ((1 << Log2X) == ptgainfo->imwidth) break;

	if (Log2X == 11)
		goto exit_load_tga_argb_8888;

	// Height:

	for (Log2Y=1; Log2Y <= 10; Log2Y++)
		if ((1 << Log2Y) == ptgainfo->imheight) break;

	if (Log2Y == 11)
		goto exit_load_tga_argb_8888;

	
	// Skip descriptive bytes at end of header, idlen specifies the number.

	if (fseek (fp, ptgainfo->idlen, SEEK_CUR) != 0)
	{
		goto exit_load_tga_argb_8888;
	}

	// Compute size of bitmap image scanline.

	scanlinesize = ptgainfo->imwidth * (int)(ptgainfo->imdepth / 8);

    // Compute video memory texture pitch.

    pitch = ptgainfo->imwidth * 4;

	// Allocate system meory buffer for scanline.

	scanlinebuf = (char*) malloc (scanlinesize);
	if (scanlinebuf == NULL)
		goto exit_load_tga_argb_8888;

	// Allocate a block of video memory for this texture.

    texoffset = R128_AllocBuffer (pitch * ptgainfo->imheight);
	if (texoffset == 0xffffffff)
		goto exit_load_tga_argb_8888;

	// Set pointers for copying data to video memory.

    lpDstLine = lpDst = (char*)(R128_AdapterInfo.virtual_MEM_BASE +
        texoffset + ((ptgainfo->imheight-1) * pitch));

	// Copy data to video memory.

	for (y = 0; y < ptgainfo->imheight; y++)
	{
		// Read a scanline.

		fread (scanlinebuf, sizeof (char), scanlinesize, fp);
		lpSrc = scanlinebuf;

		// Copy scanline to video memory.

		for (x = 0; x < ptgainfo->imwidth; x++)
		{
			memcpy(lpDst, lpSrc, 3);
			lpDst += 3;
			lpSrc += 3;
			if(ptgainfo->imdepth == 32)
				*lpDst++ = *lpSrc++;
			else
                *lpDst++ = 255;
		}
        lpDstLine -= pitch;
		lpDst = lpDstLine;
	}

	//  Flush pixel cache to force all data into memory before texel reads.

	R128_WaitForFifo(1);
	y=regr(PC_GUI_CTLSTAT);
	x=0;
    gCommandBuf[x++] = CCE_PACKET0 | (PC_GUI_CTLSTAT >> 2);
    gCommandBuf[x++] = y | 0x3;
    gCommandBuf[0] |= ((x - 2) << 16);
    R128_CCESubmitPackets (gCommandBuf, x);

    R128_CCESubmitPackets (gCommandBuf, i);

	// Fill the texture's TEXINFO structure.

	strcpy (ptexinfo->filename, texfile);
    ptexinfo->Format = TEXFORMAT_ARGB8888;
	ptexinfo->Flags = 0; 
	ptexinfo->Log2X = Log2X;
	ptexinfo->Log2Y = Log2Y;
    ptexinfo->Pitch = ptgainfo->imwidth * 4;
    ptexinfo->Offset[0] = texoffset;
    memset (&(ptexinfo->Offset[1]), 0, sizeof (DWORD) * 10);

	// Return success.

	retcode = TRUE;

exit_load_tga_argb_8888:

	// Free resources.

	if (fp)
		fclose (fp);

	if (ptgainfo)
		free (ptgainfo);

	if (scanlinebuf)
		free (scanlinebuf);

	return (retcode);
}

#endif // LOAD_TEXTURE_NO_HOSTDATA_BLT


/****************************************************************************
 * R128_FreeTexture													        *
 *  Function: Frees resources allocated to this texture.                    *
 *    Inputs: ptexinfo - pointer to this textures's TEXINFO struct.         *
 *   Outputs: TRUE - successful.                                            *
 *			  FALSE - unsuccessful.											*
 ****************************************************************************/

BOOL R128_FreeTexture (LPTEXINFO ptexinfo)
{
	// Validate pointer.

	if (ptexinfo == FALSE)
		return FALSE;

	// Free the video memory buffer.

	if (R128_FreeBuffer (ptexinfo->Offset[0]) == FALSE)
		return FALSE;

	// zero out the TEXINFO struct.

    memset (ptexinfo, 0, sizeof (TEXINFO));

	return TRUE;
}


/****************************************************************************
 * FlushTextureCache                                                        *
 *  Function: Flush texture cache at the start of the next primitive.       *
 *    Inputs: none.                                                         *
 *   Outputs: none.                                                         *
 ****************************************************************************/

void FlushTextureCache (void)
{
    int i = 0;

    // Set TEX_CNTL_C:TEX_CACHE_FLUSH field.

    gCommandBuf[i++] = CCE_PACKET0 | (TEX_CNTL_C >> 2);
    gCommandBuf[i++] = gContext3D.regTEX_CNTL_C | (0x00000001 << 23);                       
    R128_CCESubmitPackets (gCommandBuf, i);
}
	
