Arachnoid GLESv1.1 plugin. Compile and run (a bit glitchy and no frameskip) on the...
[mupen64plus-pandora.git] / source / mupen64plus-video-arachnoid / src / texture / TextureCache.cpp
diff --git a/source/mupen64plus-video-arachnoid/src/texture/TextureCache.cpp b/source/mupen64plus-video-arachnoid/src/texture/TextureCache.cpp
new file mode 100755 (executable)
index 0000000..c30e7f1
--- /dev/null
@@ -0,0 +1,627 @@
+/******************************************************************************
+ * Arachnoid Graphics Plugin for Mupen64Plus
+ * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/
+ *
+ * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *****************************************************************************/
+
+#include "TextureCache.h"
+
+#include "RDP.h"
+#include "RSP.h"
+#include "CachedTexture.h"
+#include "MathLib.h"
+#include <algorithm>
+    using std::min;
+#include "m64p.h"
+#include "OpenGL.h"
+#include "Memory.h"
+#include "OpenGLRenderer.h"
+#include "MultiTexturingExt.h"    
+    //gSPBgRect1Cyc
+//gSPBgRectCopy
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_GENERATE_MIPMAP                0x8191
+
+#include "Logger.h"
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+//! Constructor
+//-----------------------------------------------------------------------------
+TextureCache::TextureCache()
+{
+    m_currentTextures[0] = 0;
+    m_currentTextures[1] = 0;
+}
+
+//-----------------------------------------------------------------------------
+//! Destructor
+//-----------------------------------------------------------------------------
+TextureCache::~TextureCache()
+{   
+    dispose();
+}
+
+//-----------------------------------------------------------------------------
+//* Initialize
+//-----------------------------------------------------------------------------
+bool TextureCache::initialize(RSP* rsp, RDP* rdp, Memory* memory, unsigned int textureBitDepth, unsigned int cacheSize)
+{
+    m_rsp = rsp;
+    m_rdp = rdp;
+    m_memory   = memory;
+    m_bitDepth = textureBitDepth;
+    m_maxBytes = cacheSize;
+    
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+//* Update
+//-----------------------------------------------------------------------------
+void TextureCache::update(unsigned int tile)
+{
+    //if (cache.bitDepth != OGL.textureBitDepth)
+    //{
+    //    TextureCache_Destroy();
+    //    TextureCache_Init();
+    //}
+
+    //Special textures?
+    if ( m_rdp->getTextureMode() == TM_BGIMAGE )
+    {
+        return;
+    }
+    else if ( m_rdp->getTextureMode() == TM_FRAMEBUFFER )
+    {
+        return;
+    }
+
+
+    CachedTexture temp;    
+    unsigned int maskWidth = 0, maskHeight = 0;
+    _calculateTextureSize(tile, &temp, maskWidth, maskHeight);
+
+    static int hits = 0;
+    static int misses = 0;
+
+    //For each texture in texture cache
+    for (TextureList::iterator it=m_cachedTextures.begin(); it!=m_cachedTextures.end(); ++it)
+      {
+        CachedTexture* temp2 = (*it);
+
+        if ( *temp2 == temp )
+        {
+            _activateTexture( tile, (*it) );
+            hits++;
+            return;
+        }
+    }
+    misses++;
+
+    // If multitexturing, set the appropriate texture
+    //if (OGL.ARB_multitexture)
+    glActiveTextureARB( GL_TEXTURE0_ARB + tile );
+
+    //Add new texture to cache
+    m_currentTextures[tile] = addTop();
+    m_currentTextures[tile]->activate();
+
+    m_currentTextures[tile]->address     = m_rdp->getTextureImage()->address;
+    m_currentTextures[tile]->crc         = temp.crc;
+    m_currentTextures[tile]->width       = temp.width;
+    m_currentTextures[tile]->height      = temp.height;
+    m_currentTextures[tile]->clampWidth  = temp.clampWidth;
+    m_currentTextures[tile]->clampHeight = temp.clampHeight;
+
+    m_currentTextures[tile]->format = m_rsp->getTile(tile)->format;
+    m_currentTextures[tile]->size =  m_rsp->getTile(tile)->size;
+
+    m_currentTextures[tile]->palette = m_rsp->getTile(tile)->palette;
+/*    m_currentTextures[tile]->fulS = rsp.getTile(tile)->fulS;
+    m_currentTextures[tile]->fulT = rsp.getTile(tile)->fulT;
+    m_currentTextures[tile]->ulS = rsp.getTile(tile)->ulS;
+    m_currentTextures[tile]->ulT = rsp.getTile(tile)->ulT;
+    m_currentTextures[tile]->lrS = rsp.getTile(tile)->lrS;
+    m_currentTextures[tile]->lrT = rsp.getTile(tile)->lrT;*/
+    m_currentTextures[tile]->maskS   = m_rsp->getTile(tile)->masks;
+    m_currentTextures[tile]->maskT   = m_rsp->getTile(tile)->maskt;
+    m_currentTextures[tile]->mirrorS = m_rsp->getTile(tile)->mirrors;
+    m_currentTextures[tile]->mirrorT = m_rsp->getTile(tile)->mirrort;
+    m_currentTextures[tile]->clampS  = m_rsp->getTile(tile)->clamps;
+    m_currentTextures[tile]->clampT  = m_rsp->getTile(tile)->clampt;
+    m_currentTextures[tile]->line    = m_rsp->getTile(tile)->line;
+    m_currentTextures[tile]->tMem    = m_rsp->getTile(tile)->tmem;
+
+
+    
+//    cache.current[tile]->lastDList = RSP.DList;
+//    cache.current[tile]->frameBufferTexture = FALSE;
+
+    //Calculate Real Width
+    if (m_currentTextures[tile]->clampS) 
+    {
+        m_currentTextures[tile]->realWidth = pow2( temp.clampWidth );
+    }
+    else if (m_currentTextures[tile]->mirrorS)
+    {
+        m_currentTextures[tile]->realWidth = maskWidth << 1;
+    }
+    else
+    {
+        m_currentTextures[tile]->realWidth = pow2( temp.width );
+    }
+
+    //Calculate Real Height
+    if (m_currentTextures[tile]->clampT)
+    {
+        m_currentTextures[tile]->realHeight = pow2( temp.clampHeight );
+    }
+    else if (m_currentTextures[tile]->mirrorT)
+    {
+        m_currentTextures[tile]->realHeight = maskHeight << 1;
+    }
+    else
+    {
+        m_currentTextures[tile]->realHeight = pow2( temp.height );
+    }
+
+    //Calculate Scale
+    m_currentTextures[tile]->scaleS = 1.0f / (float)(m_currentTextures[tile]->realWidth);
+    m_currentTextures[tile]->scaleT = 1.0f / (float)(m_currentTextures[tile]->realHeight);
+    m_currentTextures[tile]->shiftScaleS = 1.0f;
+    m_currentTextures[tile]->shiftScaleT= 1.0f;
+    #if 0
+        //m_currentTextures[tile]->offsetS = OGL.enable2xSaI ? 0.25f : 0.5f;
+        //m_currentTextures[tile]->offsetT = OGL.enable2xSaI ? 0.25f : 0.5f;
+    #else
+        m_currentTextures[tile]->offsetS = 0.5f;
+        m_currentTextures[tile]->offsetT = 0.5f;    
+    #endif
+
+    if (m_rsp->getTile(tile)->shifts > 10)
+        m_currentTextures[tile]->shiftScaleS = (float)(1 << (16 - m_rsp->getTile(tile)->shifts));
+    else if (m_rsp->getTile(tile)->shifts > 0)
+        m_currentTextures[tile]->shiftScaleS /= (float)(1 << m_rsp->getTile(tile)->shifts);
+
+    if (m_rsp->getTile(tile)->shiftt > 10)
+        m_currentTextures[tile]->shiftScaleT = (float)(1 << (16 - m_rsp->getTile(tile)->shiftt));
+    else if (m_rsp->getTile(tile)->shiftt > 0)
+        m_currentTextures[tile]->shiftScaleT /= (float)(1 << m_rsp->getTile(tile)->shiftt);
+
+
+
+
+
+    _loadTexture( m_currentTextures[tile] );
+    _activateTexture( tile, m_currentTextures[tile] );
+
+    m_cachedBytes += m_currentTextures[tile]->getTextureSize();
+
+}
+
+//-----------------------------------------------------------------------------
+//* Add Top
+//! Adds a texture to cache
+//-----------------------------------------------------------------------------
+CachedTexture* TextureCache::addTop()
+{
+    //If no memory left, remove old textures from cache
+    while ( m_cachedBytes > m_maxBytes )
+    {
+        this->removeBottom();
+    }
+
+    //Allocate memory
+    CachedTexture* newTexture = new CachedTexture();
+
+    //Generate a texture
+    glGenTextures(1, &newTexture->m_id);
+
+    //Add Texture to cache
+    m_cachedTextures.push_front(newTexture);
+
+    return newTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Remove Bottom
+//-----------------------------------------------------------------------------
+void TextureCache::removeBottom() 
+{
+    //Get Last Texture in list
+    CachedTexture* lastTexture = *(--m_cachedTextures.end());
+
+    //Remove Texture
+    m_cachedTextures.pop_back();
+    m_cachedBytes -= lastTexture->getTextureSize();
+
+    //if (cache.bottom->frameBufferTexture)
+    //    FrameBuffer_RemoveBuffer( cache.bottom->address );
+
+    //Delete texture
+    glDeleteTextures(1, &lastTexture->m_id);
+
+    delete lastTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Remove
+//-----------------------------------------------------------------------------
+void TextureCache::remove( CachedTexture *texture ) 
+{
+
+}
+
+//-----------------------------------------------------------------------------
+//Move Texture to top
+//-----------------------------------------------------------------------------
+void TextureCache::moveToTop( CachedTexture *newtop ) 
+{
+    //Get Texture
+    TextureList::iterator it = std::find( m_cachedTextures.begin(), m_cachedTextures.end(), newtop);
+
+    //Erase Texture
+    if ( it != m_cachedTextures.end() )
+    {
+        m_cachedTextures.erase(it);
+    }
+
+    //Add texture to the front of the list
+    m_cachedTextures.push_front(newtop);
+}
+
+//-----------------------------------------------------------------------------
+// Dispose
+//-----------------------------------------------------------------------------
+void TextureCache::dispose()
+{
+    //For each texture
+    for (TextureList::iterator it=m_cachedTextures.begin(); it!=m_cachedTextures.end(); ++it )
+    {
+        delete (*it);
+    }
+    m_cachedTextures.clear();
+}
+
+//-----------------------------------------------------------------------------
+// Load Texture
+//-----------------------------------------------------------------------------
+void TextureCache::_loadTexture(CachedTexture* texture)
+{
+    //Select Image Type
+    GetTexelFunc getTexelFunc;
+    unsigned int internalFormat;
+    int             imageType;
+    m_formatSelector.detectImageFormat(texture, m_bitDepth, getTexelFunc, internalFormat, imageType, m_rdp->getTextureLUT());
+
+    //Allocate memory
+    unsigned int* dest = new unsigned int[ texture->getTextureSize() ];
+
+    //Get Line Size
+    unsigned short line = (unsigned short)texture->line;
+    if (texture->size == G_IM_SIZ_32b)
+        line <<= 1;
+
+    //
+    //Work Your magic
+    //
+
+    unsigned short mirrorSBit, maskSMask, clampSClamp;
+    unsigned short mirrorTBit, maskTMask, clampTClamp;
+
+    if (texture->maskS)
+    {
+        clampSClamp = (unsigned short)(texture->clampS ? texture->clampWidth - 1 : (texture->mirrorS ? (texture->width << 1) - 1 : texture->width - 1));
+        maskSMask = (1 << texture->maskS) - 1;
+        mirrorSBit = texture->mirrorS ? 1 << texture->maskS : 0;
+    }
+    else
+    {
+        clampSClamp = (unsigned short)min( texture->clampWidth, texture->width ) - 1;
+        maskSMask = 0xFFFF;
+        mirrorSBit = 0x0000;
+    }
+
+    if (texture->maskT)
+    {
+        clampTClamp = (unsigned short)(texture->clampT ? texture->clampHeight - 1 : (texture->mirrorT ? (texture->height << 1) - 1: texture->height - 1));
+        maskTMask = (1 << texture->maskT) - 1;
+        mirrorTBit = texture->mirrorT ?    1 << texture->maskT : 0;
+    }
+    else
+    {
+        clampTClamp = (unsigned short)min( texture->clampHeight, texture->height ) - 1;
+        maskTMask = 0xFFFF;
+        mirrorTBit = 0x0000;
+    }
+
+    // Hack for Zelda warp texture
+    if (((texture->tMem << 3) + (texture->width * texture->height << texture->size >> 1)) > 4096)
+        texture->tMem = 0;
+
+    // limit clamp values to min-0 (Perfect Dark has height=0 textures, making negative clamps)
+    if (clampTClamp & 0x8000)
+        clampTClamp = 0;
+    if (clampSClamp & 0x8000)
+        clampSClamp = 0;
+
+    //
+    //Retrive texture from source (TMEM) and copy it to dest
+    //
+
+    unsigned short x, y, i, j, tx, ty;
+
+    unsigned long long* src;
+
+    j = 0;
+    for (y = 0; y < texture->realHeight; y++)
+    {
+        ty = min(y, clampTClamp) & maskTMask;
+
+        if (y & mirrorTBit) {
+            ty ^= maskTMask;
+        }
+
+        //TODO: remove old if new works
+        //src = m_memory->getTextureMemory(texture->tMem) + line * ty;
+        src = m_memory->getTextureMemory((texture->tMem + line * ty) & 511);
+        
+
+        i = (ty & 1) << 1;
+        for (x = 0; x < texture->realWidth; x++)
+        {
+            tx = min(x, clampSClamp) & maskSMask;
+
+            if (x & mirrorSBit)
+                tx ^= maskSMask;
+
+            if (internalFormat == GL_RGBA8)
+                ((unsigned int*)dest)[j++] = getTexelFunc( src, tx, i, texture->palette );
+            else
+                ((unsigned short*)dest)[j++] = getTexelFunc( src, tx, i, texture->palette );
+        }
+    }
+
+    //Send Texture to OpenGL
+#ifdef HAVE_GLES
+    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texture->realWidth, texture->realHeight, 0, GL_RGBA, imageType, dest );
+#else
+    glTexImage2D( GL_TEXTURE_2D, 0, internalFormat, texture->realWidth, texture->realHeight, 0, GL_RGBA, imageType, dest );
+#endif
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    delete[] dest;
+}
+
+
+void TextureCache::_calculateTextureSize(unsigned int tile, CachedTexture* out, unsigned int& maskWidth, unsigned int& maskHeight )
+{
+    RDPTile* rspTile = m_rsp->getTile(tile);
+
+    //Calculate Tile Size
+    unsigned int tileWidth =  rspTile->getWidth();
+    unsigned int tileHeight = rspTile->getHeight();
+
+    //Get Mask Size
+    maskWidth = 1 << rspTile->masks;
+    maskHeight = 1 << rspTile->maskt;
+
+    //Get Current Tile Size
+    unsigned int loadWidth = m_rdp->getCurrentTile()->getWidth();
+    unsigned int loadHeight = m_rdp->getCurrentTile()->getHeight();
+
+    unsigned int maxTexels = ImageFormatSelector::imageFormats[rspTile->size][rspTile->format].maxTexels;
+
+    //Get Line Width (depending on imageformat)
+    unsigned int lineWidth = rspTile->line << ImageFormatSelector::imageFormats[rspTile->size][rspTile->format].lineShift;
+    unsigned int lineHeight; 
+    if ( lineWidth ) // Don't allow division by zero
+        lineHeight = min( maxTexels / lineWidth, tileHeight );
+    else
+        lineHeight = 0;
+
+    unsigned int width;
+    unsigned int height;
+
+    if ( m_rdp->getTextureMode() == TM_TEXRECT )
+    {
+        unsigned short texRectWidth = (unsigned short)(m_rdp->getTexRectWidth() - rspTile->uls);
+        unsigned short texRectHeight = (unsigned short)(m_rdp->getTexRectHeight() - rspTile->ult);
+
+        if (rspTile->masks && ((maskWidth * maskHeight) <= maxTexels))
+            width = maskWidth;
+        else if ((tileWidth * tileHeight) <= maxTexels)
+            width = tileWidth;
+        else if ((tileWidth * texRectHeight) <= maxTexels)
+            width = tileWidth;
+        else if ((texRectWidth * tileHeight) <= maxTexels)
+            width = m_rdp->getTexRectWidth();
+        else if ((texRectWidth * texRectHeight) <= maxTexels)
+            width = m_rdp->getTexRectWidth();
+        else if (m_rdp->getLoadType() == LOADTYPE_TILE)
+            width = loadWidth;
+        else
+            width = lineWidth;
+
+        if (rspTile->maskt && ((maskWidth * maskHeight) <= maxTexels))
+            height = maskHeight;
+        else if ((tileWidth * tileHeight) <= maxTexels)
+            height = tileHeight;
+        else if ((tileWidth * texRectHeight) <= maxTexels)
+            height = m_rdp->getTexRectHeight();
+        else if ((texRectWidth * tileHeight) <= maxTexels)
+            height = tileHeight;
+        else if ((texRectWidth * texRectHeight) <= maxTexels)
+            height = m_rdp->getTexRectHeight();
+        else if (m_rdp->getLoadType() == LOADTYPE_TILE)
+            height = loadHeight;
+        else
+            height = lineHeight;
+    }
+    else
+    {
+        if (rspTile->masks && ((maskWidth * maskHeight) <= maxTexels))
+            width = maskWidth; // Use mask width if set and valid
+        else if ((tileWidth * tileHeight) <= maxTexels)
+            width = tileWidth; // else use tile width if valid
+        else if (m_rdp->getLoadType() == LOADTYPE_TILE)
+            width = loadWidth; // else use load width if load done with LoadTile
+        else
+            width = lineWidth; // else use line-based width
+
+        if (rspTile->maskt && ((maskWidth * maskHeight) <= maxTexels))
+            height = maskHeight;
+        else if ((tileWidth * tileHeight) <= maxTexels)
+            height = tileHeight;
+        else if (m_rdp->getLoadType() == LOADTYPE_TILE)
+            height = loadHeight;
+        else
+            height = lineHeight;
+    }
+
+     unsigned int clampWidth = rspTile->clamps ? tileWidth : width;
+    unsigned int clampHeight = rspTile->clampt ? tileHeight : height;
+
+    if (clampWidth > 256)
+        rspTile->clamps = 0;
+    if (clampHeight > 256)
+        rspTile->clampt = 0;
+
+    // Make sure masking is valid
+    if (maskWidth > width) 
+    {
+        rspTile->masks = powof( width );
+        maskWidth = 1 << rspTile->masks;
+    }
+
+    if (maskHeight > height)
+    {
+        rspTile->maskt = powof( height );
+        maskHeight = 1 << rspTile->maskt;
+    }
+
+    //Set output data
+    out->width       = width;
+    out->height      = height;
+    out->clampWidth  = clampWidth;
+    out->clampHeight = clampHeight;
+    out->maskS       = m_rsp->getTile(tile)->masks;
+    out->maskT       = m_rsp->getTile(tile)->maskt;
+    out->mirrorS     = m_rsp->getTile(tile)->mirrors;
+    out->mirrorT     = m_rsp->getTile(tile)->mirrort;
+    out->clampS      = m_rsp->getTile(tile)->clamps;
+    out->clampT      = m_rsp->getTile(tile)->clampt;
+    out->format      = m_rsp->getTile(tile)->format;
+    out->size        = m_rsp->getTile(tile)->size; 
+    out->crc         = _calculateCRC(tile, width, height );
+}
+
+unsigned int TextureCache::_calculateCRC(unsigned int t, unsigned int width, unsigned int height)
+{
+    RDPTile* tile = m_rsp->getTile(t);
+
+    unsigned int crc;
+    unsigned int y, bpl, line;
+    unsigned long long *src;
+
+    //TODO: remove if new works
+    //src = m_memory->getTextureMemory(tile->tmem);
+    bpl = width << tile->size >> 1;
+
+    line = tile->line;
+     if (tile->size == G_IM_SIZ_32b)
+        line <<= 1;
+
+    crc = 0xFFFFFFFF;
+     for (y=0; y<height; ++y)
+    {
+        src = m_memory->getTextureMemory((tile->tmem + (y * line)) & 511);
+        crc = m_crcCalculator.calcCRC( crc, src, bpl );
+        //TODO: remove if new works
+        //src += line;
+    }
+
+       if ( tile->format == G_IM_FMT_CI )
+    {
+        if ( tile->size == G_IM_SIZ_4b )
+            crc = m_crcCalculator.calcCRC( crc, &m_rdp->m_paletteCRC16[tile->palette], 4 );
+        else if (tile->size == G_IM_SIZ_8b)
+            crc = m_crcCalculator.calcCRC( crc, &m_rdp->m_paletteCRC256, 4 );
+    }
+    return crc;
+}
+
+void TextureCache::_activateTexture( unsigned int t, CachedTexture *texture )
+{
+    // If multitexturing, set the appropriate texture
+    //if (OGL.ARB_multitexture)
+        glActiveTextureARB( GL_TEXTURE0_ARB + t );
+
+    // Bind the cached texture
+    texture->activate();
+
+    // Set filter mode. Almost always bilinear, but check anyways
+    unsigned int textureFiltering = m_rdp->getTextureFiltering();
+    if ( textureFiltering == G_TF_BILERP || textureFiltering == G_TF_AVERAGE )
+    {
+        if( m_mipmap > 0 )
+        {
+            // Set Mipmap
+            if(m_mipmap == 1)    // nearest
+            {
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+            }
+            else if(m_mipmap == 2)    // bilinear
+            {
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+            }
+            else if(m_mipmap == 3)    // trilinear
+            {
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+            }
+            
+            // Tell to hardware to generate mipmap (himself) when glTexImage2D is called
+            glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+        }
+        else    // no mipmapping
+        {
+            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+            glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
+        }
+        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+        
+    }
+    else
+    {
+        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+    }
+
+    
+
+    // Set clamping modes
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture->clampS ? GL_CLAMP_TO_EDGE : GL_REPEAT );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture->clampT ? GL_CLAMP_TO_EDGE : GL_REPEAT );
+
+    //texture->lastDList = RSP.DList;
+
+    moveToTop( texture );
+
+    m_currentTextures[t] = texture;
+}