Arachnoid GLESv1.1 plugin. Compile and run (a bit glitchy and no frameskip) on the...
[mupen64plus-pandora.git] / source / mupen64plus-video-arachnoid / src / RDP / RDP.cpp
diff --git a/source/mupen64plus-video-arachnoid/src/RDP/RDP.cpp b/source/mupen64plus-video-arachnoid/src/RDP/RDP.cpp
new file mode 100755 (executable)
index 0000000..e000582
--- /dev/null
@@ -0,0 +1,923 @@
+/******************************************************************************
+ * 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 "RDP.h"
+#include "GBIDefs.h"
+#include "GBI.h"
+#include "RSP.h"
+#include "DisplayListParser.h"
+#include "assembler.h"
+#include "OpenGLRenderer.h"
+#include "TextureCache.h"
+#include "VI.h"
+#include "Memory.h"
+#include "OpenGLManager.h"
+#include "OpenGL2DRenderer.h"
+#include "AdvancedCombinerManager.h"
+#include "FogManager.h"
+#include "Logger.h"
+#include "MathLib.h"
+#include "RomDetector.h"
+#include "m64p.h"
+#include "OpenGL.h"
+#include <algorithm>
+using std::max;
+
+//-----------------------------------------------------------------------------
+//! Defines
+//-----------------------------------------------------------------------------
+#define MI_INTR_DP          0x00000020  //!< RDP Interrupt signal
+
+//-----------------------------------------------------------------------------
+//! Static Variables
+//-----------------------------------------------------------------------------
+Memory* RDP::m_memory  = 0;
+
+//-----------------------------------------------------------------------------
+//! Constructor
+//-----------------------------------------------------------------------------
+RDP::RDP()
+{
+    m_graphicsInfo       = 0;    
+    m_changedTiles       = false;
+    m_textureMode        = TM_NORMAL;
+    m_loadType           = LOADTYPE_BLOCK;
+    m_tmemChanged        = false;  
+    m_textureLUT         = 0;   
+    m_texRectWidth       = 1; 
+    m_texRectHeight      = 1;
+    m_displayListParser  = 0;
+    m_primitiveZ         = 0;
+    m_combinerMgr        = 0;
+    m_textureLoader      = 0;
+    m_openGL2DRenderer   = 0;
+    m_screenUpdatePending= false;
+}
+
+//-----------------------------------------------------------------------------
+//! Destructor
+//-----------------------------------------------------------------------------
+RDP::~RDP()
+{
+}
+
+//-----------------------------------------------------------------------------
+//* Initialize
+//! Sets pointers to managers and initializes objects
+//-----------------------------------------------------------------------------
+bool RDP::initialize(GFX_INFO* graphicsInfo, RSP* rsp, Memory* memory, GBI* gbi, TextureCache* textureCache, VI* vi, DisplayListParser* displayListParser, FogManager* fogMgr)
+{
+    //Set pointers
+    m_graphicsInfo      = graphicsInfo;
+    m_rsp               = rsp;
+    m_vi                = vi;
+    m_memory            = memory;
+    m_displayListParser = displayListParser;
+    m_textureCache      = textureCache;
+    m_fogMgr            = fogMgr;
+
+    //Create combiner manager
+    m_combinerMgr = new AdvancedCombinerManager();
+    m_combinerMgr->initialize();
+
+    //Create texture loader
+    m_textureLoader = new TextureLoader();
+    m_textureLoader->initialize(this, m_memory);
+
+    //Create OpenGL 2D Renderer
+    m_openGL2DRenderer = new OpenGL2DRenderer();
+    m_openGL2DRenderer->initialize(vi);
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+//* Dispose
+//! Delets all allocated memory
+//-----------------------------------------------------------------------------
+void RDP::dispose()
+{
+    if ( m_combinerMgr      ) { delete m_combinerMgr;      m_combinerMgr      = 0; }
+    if ( m_textureLoader    ) { delete m_textureLoader;    m_textureLoader    = 0; }
+    if ( m_openGL2DRenderer ) { delete m_openGL2DRenderer; m_openGL2DRenderer = 0; }
+}
+
+//-----------------------------------------------------------------------------
+//* Update States
+//! Sets OpenGL states, updates combiner, activates textures, sets blender
+//-----------------------------------------------------------------------------
+void RDP::updateStates()
+{
+    //Depth Compare
+    if (m_otherMode.depthCompare)
+        glDepthFunc( GL_LEQUAL );
+    else
+        glDepthFunc( GL_ALWAYS );
+
+    //Depth Update
+    if (m_otherMode.depthUpdate)
+        glDepthMask( true );
+    else
+        glDepthMask( false );
+
+    // Depth Mode
+    if (m_otherMode.depthMode == ZMODE_DEC)
+    {
+        glEnable( GL_POLYGON_OFFSET_FILL );
+        glPolygonOffset( -3.0f, -3.0f );
+    }
+    else
+    {
+        glDisable( GL_POLYGON_OFFSET_FILL );
+    }
+
+    // Alpha Compare
+    if ((m_otherMode.alphaCompare == G_AC_THRESHOLD) && !(m_otherMode.alphaCvgSel))
+    {
+        glEnable( GL_ALPHA_TEST );
+        glAlphaFunc( (m_combinerMgr->getBlendColor()[3] > 0.0f) ? GL_GEQUAL : GL_GREATER, m_combinerMgr->getBlendColor()[3] );
+    }
+    // Used in TEX_EDGE and similar render modes
+    else if (m_otherMode.cvgXAlpha)
+    {
+        glEnable( GL_ALPHA_TEST );
+        glAlphaFunc( GL_GEQUAL, 0.5f );  // Arbitrary number -- gives nice results though
+    }
+    else
+        glDisable( GL_ALPHA_TEST );
+
+    //Combiner
+    if ( m_updateCombiner )
+    {
+        if ( m_otherMode.cycleType == G_CYC_COPY)
+        {
+            m_combinerMgr->setMux(72057594037727865LL, m_otherMode.cycleType); //Only normal texturing                                                                    
+            m_combinerMgr->selectCombine(m_otherMode.cycleType);
+        }
+        else if  ( m_otherMode.cycleType == G_CYC_FILL )
+        {
+            m_combinerMgr->setMux( 72057594037828926LL, m_otherMode.cycleType );
+            m_combinerMgr->selectCombine(m_otherMode.cycleType);
+        }
+        else
+        {
+            m_combinerMgr->selectCombine(m_otherMode.cycleType);
+        }
+        m_updateCombiner = false;
+        m_updateCombineColors = true;
+    }
+
+    if ( m_updateCombineColors )
+    {
+        m_combinerMgr->updateCombineColors();
+        m_updateCombineColors = false;
+    }
+
+    //Texturing
+    if ( m_changedTiles || m_tmemChanged || m_rsp->getTexturesChanged() ) 
+    {
+        m_combinerMgr->beginTextureUpdate();
+
+        //Update Texture channel 0
+        if ( m_combinerMgr->getUsesTexture0() )
+        {
+            //Enable texture 0
+            m_textureCache->update(0);
+            m_rsp->setTexturesChanged(false);
+            m_changedTiles = false;
+            m_tmemChanged = false;
+        }
+        else
+        {
+            //Disable texture 0
+            glActiveTextureARB( GL_TEXTURE0_ARB + 0 );
+            glDisable(GL_TEXTURE_2D);  
+        }
+
+        //Update Texture channel 1
+        if (  m_combinerMgr->getUsesTexture1() )
+        {
+            //Enable texture 1
+            m_textureCache->update(1);
+            m_rsp->setTexturesChanged(false);
+            m_changedTiles = false;
+            m_tmemChanged = false;
+        }
+        else
+        {
+            //Disable textureing 1
+            glActiveTextureARB( GL_TEXTURE0_ARB + 1 );
+            glDisable(GL_TEXTURE_2D); 
+        }
+
+        m_combinerMgr->endTextureUpdate();
+    }
+
+    // Blending
+    if (    (m_otherMode.forceBlender) &&    
+            (m_otherMode.cycleType != G_CYC_COPY) &&
+            (m_otherMode.cycleType != G_CYC_FILL) &&
+            !(m_otherMode.alphaCvgSel))
+    {
+        glEnable( GL_BLEND );
+        switch (m_otherMode.l >> 16)
+        {
+            case 0x0448: // Add
+            case 0x055A:
+                glBlendFunc( GL_ONE, GL_ONE );
+                break;
+            case 0x0C08: // 1080 Sky
+            case 0x0F0A: // Used LOTS of places
+                glBlendFunc( GL_ONE, GL_ZERO );
+                break;
+            case 0xC810: // Blends fog
+            case 0xC811: // Blends fog
+            case 0x0C18: // Standard interpolated blend
+            case 0x0C19: // Used for antialiasing
+            case 0x0050: // Standard interpolated blend
+            case 0x0055: // Used for antialiasing
+                glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+                break;
+            case 0x0FA5: // Seems to be doing just blend color - maybe combiner can be used for this?
+            case 0x5055: // Used in Paper Mario intro, I'm not sure if this is right...
+                glBlendFunc( GL_ZERO, GL_ONE );
+                break;
+            default:
+                glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+                break;
+        }
+    }
+    else
+        glDisable( GL_BLEND );
+
+    if (m_otherMode.cycleType == G_CYC_FILL)
+    {
+        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+        glEnable( GL_BLEND );
+    }
+}
+
+//-----------------------------------------------------------------------------
+//* Reset
+//! Resets all states on RDP
+//-----------------------------------------------------------------------------
+void RDP::reset()
+{
+    setTextureFiltering( G_TF_POINT );
+    setRenderMode(0);
+}
+
+//-----------------------------------------------------------------------------
+//* Trigger Interrupt
+//! Tell emulator that the RDP is idle
+//-----------------------------------------------------------------------------
+void RDP::triggerInterrupt()
+{
+    *(m_graphicsInfo->MI_INTR_REG) |= MI_INTR_DP;
+    m_graphicsInfo->CheckInterrupts();
+}
+
+//-----------------------------------------------------------------------------
+//* Set Alpha Compare Mode
+//-----------------------------------------------------------------------------
+void RDP::setAlphaCompareMode(unsigned int mode)
+{
+    m_otherMode.alphaCompare = mode;
+    OpenGLManager::getSingleton().setAlphaTest( m_otherMode.alphaCompare != 0 );
+}
+
+//-----------------------------------------------------------------------------
+//* Set Render Mode
+//-----------------------------------------------------------------------------
+void RDP::setRenderMode(unsigned int w1)
+{
+    unsigned int mode1 = (w1 & 0xCCCCFFFF);
+    unsigned int mode2 = (w1 & 0x3333FFFF);
+
+    m_otherMode.l &= 0x00000007;
+    m_otherMode.l |= mode1 | mode2;
+}
+
+//#############################################################################
+//  UCODE FUNCTIONS:
+//#############################################################################
+
+//*****************************************************************************
+// Combiner Mode
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+//* Set Combine
+//! Sets all combiner variables on combiner that tells it how to combine
+//! the diffrent colors and textures.
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetCombine(MicrocodeArgument* ucode)
+{ 
+    int mux0 = _SHIFTR( ucode->w0, 0, 24 );
+    int mux1 = ucode->w1;
+    m_combinerMgr->setMux(mux0, mux1, (G_CYCLE_TYPE)m_otherMode.cycleType);
+
+    m_updateCombiner = true;    
+}
+
+//*****************************************************************************
+// Colors
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+//* Set Environment Color
+//! Sets Environment Color on combiner
+//! @param r Red component of color (0.0 - 1.0)
+//! @param g Green component of color (0.0 - 1.0)
+//! @param b Blue component of color (0.0 - 1.0)
+//! @param a Alpha component of color (0.0 - 1.0)
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetEnvColor(float r, float g, float b, float a)
+{ 
+    m_combinerMgr->setEnvColor(r, g, b, a);
+    m_updateCombineColors = true;
+}
+
+//-----------------------------------------------------------------------------
+//* Set Prim Color
+//! Sets Prim Color on combiner
+//! @param r Red component of color (0.0 - 1.0)
+//! @param g Green component of color (0.0 - 1.0)
+//! @param b Blue component of color (0.0 - 1.0)
+//! @param a Alpha component of color (0.0 - 1.0)
+//! @param primLodMin
+//! @param primLevel
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetPrimColor(float r, float g, float b, float a, unsigned int primLodMin, unsigned int primLevel)
+{ 
+    int primLodFrac = max(primLevel, primLodMin);
+    m_combinerMgr->setPrimLodMin(primLodMin);
+    m_combinerMgr->setPrimLodFrac(primLodFrac / 255.0f);
+    m_combinerMgr->setPrimColor(r, g, b, a);
+    m_updateCombineColors = true;
+}
+
+//-----------------------------------------------------------------------------
+//* Set Blend Color
+//! Sets Blend Color on combiner
+//! @param r Red component of color (0.0 - 1.0)
+//! @param g Green component of color (0.0 - 1.0)
+//! @param b Blue component of color (0.0 - 1.0)
+//! @param a Alpha component of color (0.0 - 1.0)
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetBlendColor(float r, float g, float b, float a)
+{
+    m_combinerMgr->setBlendColor(r, g, b, a);
+    m_updateCombineColors = true;
+}
+
+//-----------------------------------------------------------------------------
+//* Set Fill Color
+//! Sets Fill Color on combiner
+//! @param r Red component of color (0.0 - 1.0)
+//! @param g Green component of color (0.0 - 1.0)
+//! @param b Blue component of color (0.0 - 1.0)
+//! @param a Alpha component of color (0.0 - 1.0)
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetFillColor(float r, float g, float b, float a)
+{ 
+    m_combinerMgr->setFillColor(r, g, b, a);
+    m_updateCombineColors = true;
+}
+
+//-----------------------------------------------------------------------------
+//* Set Fog Color
+//! Sets fog color used when rendering fog
+//! @param r Red component of color (0.0 - 1.0)
+//! @param g Green component of color (0.0 - 1.0)
+//! @param b Blue component of color (0.0 - 1.0)
+//! @param a Alpha component of color (0.0 - 1.0)
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetFogColor(float r, float g, float b, float a)
+{ 
+    m_fogMgr->setFogColor(r, g, b, a);
+}
+
+//*****************************************************************************
+// Misc
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+//! Set Other Mode
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetOtherMode(MicrocodeArgument* ucode)
+{          
+    unsigned int mode0 = _SHIFTR( ucode->w0, 0, 24 );    
+    unsigned int mode1 = ucode->w1;                    
+
+    m_otherMode.h = mode0;
+    m_otherMode.l = mode1;
+}
+
+//-----------------------------------------------------------------------------
+//! Set Prim Depth
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetPrimDepth(unsigned int dwZ, unsigned int dwDZ)
+{  
+    unsigned int primitiveDepth = dwZ & 0x7FFF;
+
+    //Convert to float
+    m_primitiveZ = (float)(primitiveDepth)/(float)0x8000;
+ }
+
+//-----------------------------------------------------------------------------
+//! Set Scissor
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetScissor(int x0, int y0, int x1, int y1, int mode)
+{  
+    //Get Scale
+    float vsx = OpenGLManager::getSingleton().getViewScaleX();
+    float vsy = OpenGLManager::getSingleton().getViewScaleY();
+    
+    //Get Offset
+    int offset = 0; //TODO: height offset?
+
+    //Set Scissor
+    OpenGLManager::getSingleton().setScissor( 
+               x0 * vsx, 
+               (m_vi->getHeight() - y1) * vsy + offset,
+               (x1 - x0) * vsx, 
+               (y1 - y0) * vsy 
+    );
+}
+
+//-----------------------------------------------------------------------------
+//* Set Full Sync
+//! Called when RDP is finished 
+//-----------------------------------------------------------------------------
+void RDP::RDP_FullSync()
+{ 
+    this->triggerInterrupt();
+}
+
+//*****************************************************************************
+// Rendering
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+//* Fill Rect
+//! Renders a rectangle
+//-----------------------------------------------------------------------------
+void RDP::RDP_FillRect(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1)
+{ 
+    //Logger::getSingleton() << "RDP_FillRect: " << (int)x0 << " " << (int)y0 << " " << (int)x1 << " " << (int)y1 << "\n";
+
+    //Increase rectangle size?
+    if( m_otherMode.cycleType >= G_CYC_COPY )
+    {
+        x1++;
+        y1++;
+    }
+
+    //Clear Depth Buffer?
+    if ( m_depthImageInfo.rdramAddress == m_colorImageInfo.rdramAddress )
+    {
+        //Clear the Z Buffer
+        updateStates();
+        glDepthMask( true );
+        glClear(GL_DEPTH_BUFFER_BIT);
+
+        // Depth update
+        if (m_otherMode.depthUpdate)
+        {
+            glDepthMask(GL_TRUE);
+        }
+        else
+        {
+            glDepthMask(GL_FALSE);
+        }
+
+        return;
+    }
+
+    //Clear Color Buffer?
+    if ( m_otherMode.cycleType == G_CYC_FILL)
+    {
+        if ( x0 == 0 && y0 == 0 && x1 == m_vi->getWidth() && y1 == m_vi->getHeight() )
+        {
+            const float* fillColor = m_combinerMgr->getFillColor();
+            glClearColor(fillColor[0], fillColor[1], fillColor[2], fillColor[3]);
+            bool scissor = OpenGLManager::getSingleton().getScissorEnabled();
+            OpenGLManager::getSingleton().setScissorEnabled(false);
+            glClear(GL_COLOR_BUFFER_BIT);
+            OpenGLManager::getSingleton().setScissorEnabled(scissor);
+            return;
+        }
+    }
+
+    //Update States
+    this->updateStates();   
+
+    //Ignore fill rects?
+    if ( ROMDetector::getSingleton().getIgnoreFillRects() ) 
+    {
+        return;
+    }
+
+    //Disable Scissor
+    glDisable( GL_SCISSOR_TEST );
+
+    //Set Viewport
+    //int oldViewport[4];
+    //glGetIntegerv(GL_VIEWPORT, oldViewport);
+    //glViewport(0, 0, OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() ); 
+    glDepthRange(0.0f, 1.0f);
+
+    //Get depth and color
+    float depth = m_otherMode.depthSource == 1 ? m_primitiveZ : 0;  //TODO: Use RSP viewport nearz?
+    float* color = m_otherMode.cycleType == G_CYC_FILL ? m_combinerMgr->getFillColor() : m_combinerMgr->getPrimColor();
+
+    //Render rectangle
+    m_openGL2DRenderer->renderQuad(color, x0, y0, x1, y1, depth);
+
+    //Reset viewport
+    //glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);     
+
+    //Reset Scissor
+    glEnable( GL_SCISSOR_TEST );
+}
+
+//-----------------------------------------------------------------------------
+// Texture Rectangle Flip
+//-----------------------------------------------------------------------------
+void RDP::RDP_TexRectFlip(unsigned int dwXH, unsigned int dwYH, unsigned int dwXL, unsigned int dwYL, 
+                          unsigned int tileno, unsigned int dwS, unsigned int dwT, int nDSDX, int nDTDY)
+{   
+    Logger::getSingleton().printMsg("RDP_TexRect");
+
+    float fS0 = (float)dwS / 32.0f;
+    float fT0 = (float)dwT / 32.0f;
+
+    float fDSDX = (float)nDSDX / 1024.0f;
+    float fDTDY = (float)nDTDY / 1024.0f;
+
+    if (m_otherMode.cycleType == G_CYC_COPY)
+    {
+        fDSDX /= 4.0f;    // In copy mode 4 pixels are copied at once.
+        dwXH++;
+        dwYH++;
+    }
+    else if (m_otherMode.cycleType == G_CYC_FILL )
+    {
+        dwXH++;
+        dwYH++;
+    }
+
+    float fS1 = fS0 + (fDSDX * (dwYH - dwYL));
+    float fT1 = fT0 + (fDTDY * (dwXH - dwXL));
+
+    //Set Current Texture tiles
+    m_rsp->setTile( m_textureLoader->getTile(tileno), 0);
+    if ( tileno < 7 ) 
+    {
+        m_rsp->setTile( m_textureLoader->getTile(tileno + 1), 1);
+    }
+    else {
+        m_rsp->setTile( m_textureLoader->getTile(tileno), 1);
+    }
+
+    m_texRectWidth = (unsigned int)fS1;
+    m_texRectHeight = (unsigned int)fT1;
+
+    //Update States
+    this->updateStates();
+
+    float t0u0 = 0, t0v0 = 0, t0u1 =0, t0v1 = 0;
+    if ( m_textureCache->getCurrentTexture(0) )
+    {
+        t0u0 = (fS0) * m_textureCache->getCurrentTexture(0)->shiftScaleS - m_textureLoader->getTile(tileno)->uls;
+        t0v0 = (fT0) * m_textureCache->getCurrentTexture(0)->shiftScaleT - m_textureLoader->getTile(tileno)->ult;
+        t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*m_textureCache->getCurrentTexture(0)->shiftScaleS;
+        t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*m_textureCache->getCurrentTexture(0)->shiftScaleT;
+    }
+
+    _textureRectangleFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
+        
+    //Restore RSP Tile
+    int rspTile = m_rsp->getTexture().tile;
+    m_rsp->setTile( m_textureLoader->getTile(tileno), 0);
+    m_rsp->setTile( m_textureLoader->getTile(rspTile < 7 ? rspTile + 1 : rspTile), 1);
+}
+
+//-----------------------------------------------------------------------------
+//* Texture Rect
+//! Not this command use 128bits and not 64 bits wich could cause some
+//! problems with the program counter.
+//-----------------------------------------------------------------------------
+void RDP::RDP_TexRect(unsigned int dwXH, unsigned int dwYH, unsigned int dwXL, unsigned int dwYL, 
+                      unsigned int tileno, unsigned short dwS, unsigned short dwT, unsigned short nDSDX, unsigned short nDTDY)
+{ 
+    Logger::getSingleton().printMsg("RDP_TexRect");    
+
+    glEnable(GL_TEXTURE_2D);
+
+    //Convert to signed
+    short s16S = *(short*)(&dwS);
+    short s16T = *(short*)(&dwT);
+    short s16DSDX  = *(short*)(&nDSDX);
+    short s16DTDY    = *(short*)(&nDTDY);
+
+    //Convert to float
+    float s = s16S / 32.0f;
+    float t = s16T / 32.0f;
+    float dsdx = s16DSDX / 1024.0f;
+    float dtdy = s16DTDY / 1024.0f;
+
+
+    float ulx = (float)dwXH;
+    float uly = (float)dwYH;
+    float lrx = (float)dwXL;
+    float lry = (float)dwYL;
+
+    int tile = tileno;
+
+    _textureRectangle(ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy, false);
+}
+
+//*****************************************************************************
+// Texturing
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+//* Set Color Image
+//! Sets information about color image
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetCImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress)
+{ 
+    m_colorImageInfo.rdramAddress = m_memory->getRDRAMAddress( segmentAddress );
+    m_colorImageInfo.format       = format;
+    m_colorImageInfo.size         = size;
+    m_colorImageInfo.width        = width + 1; //Note: add plus one
+    m_colorImageInfo.bpl          = m_colorImageInfo.width << m_colorImageInfo.size >> 1;
+    
+    if (m_screenUpdatePending)
+    {
+        OpenGLManager::getSingleton().endRendering();
+        m_screenUpdatePending = false;
+    }
+}
+
+//-----------------------------------------------------------------------------
+//* Set Z Image
+//! Sets information about depth image
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetZImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress)
+{ 
+    m_depthImageInfo.rdramAddress = m_memory->getRDRAMAddress( segmentAddress );
+    m_depthImageInfo.format       = format;
+    m_depthImageInfo.size         = size;
+    m_depthImageInfo.width        = width + 1; //Note: add plus one
+    m_depthImageInfo.bpl          = m_colorImageInfo.width << m_colorImageInfo.size >> 1;
+}
+
+//-----------------------------------------------------------------------------
+//* Set Texture Image
+//! Sets information about texture image
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetTImg(unsigned int format, unsigned int size, unsigned int width, unsigned int segmentAddress)
+{ 
+    m_textureLoader->setTextureImage(format, size, width, segmentAddress);
+}
+
+//-----------------------------------------------------------------------------
+// Set Tile
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetTile(int format, int size, int line, int tmem, int tile, 
+                      int palette, int clampS, int clampT, int mirrorS, 
+                      int mirrorT, int maskS, int maskT, int shiftS, int shiftT )
+{ 
+    //Set Tile
+    m_textureLoader->setTile( format, size, line, tmem, tile, palette, 
+                              clampS, clampT, mirrorS, mirrorT, maskS, maskT,
+                              shiftS, shiftT );
+
+    //m_changedTiles = true;    ??? Not needed?
+}
+
+//-----------------------------------------------------------------------------
+//* Load Tile
+//-----------------------------------------------------------------------------
+void RDP::RDP_LoadTile(int tile, int s0, int t0, int s1, int t1)
+{ 
+    //Load Tile
+    m_textureLoader->loadTile(tile, s0, t0, s1, t1);
+
+    m_textureMode = TM_NORMAL;
+    m_loadType    = LOADTYPE_TILE;
+    m_tmemChanged = true;    
+}    
+
+//-----------------------------------------------------------------------------
+// Load Block
+//-----------------------------------------------------------------------------
+void RDP::RDP_LoadBlock(int tile, int s0, int t0, int s1, int t1)
+{  
+    //Load Block
+    m_textureLoader->loadBlock(tile, s0, t0, s1, t1);
+
+    m_textureMode = TM_NORMAL;
+    m_loadType    = LOADTYPE_BLOCK;
+    m_tmemChanged = true;
+}
+
+//-----------------------------------------------------------------------------
+//! Sets the size of tile
+//! @Param tile Index of the tile to set size on
+//! @param s0 Texture Coordinats for first vertex coordinate
+//! @param t0 Texture Coordinats for first vertex coordinate
+//! @param s1 Texture Coordinats for second vertex coordinate
+//! @param t1 Texture Coordinats for second vertex coordinate
+//-----------------------------------------------------------------------------
+void RDP::RDP_SetTileSize(int tile, unsigned int s0, unsigned int t0, unsigned int s1, unsigned int t1)
+{  
+    m_textureLoader->setTileSize( tile, s0, t0, s1, t1);
+
+    m_changedTiles = true;    
+}
+
+//-----------------------------------------------------------------------------
+// Load Texture Look Up Table
+//-----------------------------------------------------------------------------
+void RDP::RDP_LoadTLUT(int tile, int s0, int t0, int s1, int t1)
+{   
+    m_textureLoader->loadTLUT(tile, s0, t0, s1, t1);
+
+    m_tmemChanged = true;
+}
+
+//*****************************************************************************
+// Private Functions
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+// Texture Rectangle
+//-----------------------------------------------------------------------------
+void RDP::_textureRectangle(float ulx, float uly, float lrx, float lry, int tile, float s, float t, float dsdx, float dtdy,bool flip)
+{
+    bool zEnabled = OpenGLManager::getSingleton().getZBufferEnabled();
+    OpenGLManager::getSingleton().setZBufferEnabled(false);
+
+    //Copy Mode
+    if (  m_otherMode.cycleType == G_CYC_COPY )
+    {
+        dsdx = 1.0;
+        lrx += 1.0f;
+        lry += 1.0f;
+    }
+    else if (m_otherMode.cycleType == G_CYC_FILL )
+    {
+        lrx++;
+        lry++;
+    }
+
+    //Set Current Texture tiles
+    m_rsp->setTile( m_textureLoader->getTile(tile), 0);
+    m_rsp->setTile( m_textureLoader->getTile(tile < 7 ? tile + 1 : tile), 1);
+
+
+    float lrs = s + (lrx - ulx - 1) * dsdx;
+    float lrt = t + (lry - uly - 1) * dtdy;
+
+    //Change mode to texture rectangle
+    if ( m_textureMode == TM_NORMAL )
+        m_textureMode = TM_TEXRECT;
+
+    m_texRectWidth  = (unsigned int)(max( lrs, s ) + dsdx);
+    m_texRectHeight = (unsigned int)(max( lrt, t ) + dtdy);
+
+    //Update States
+    this->updateStates();
+
+    //glViewport( 0, 0, OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() );
+
+    glDisable(GL_SCISSOR_TEST);
+
+    if (lrs > s)
+    {
+        if (lrt > t)
+            OpenGLRenderer::getSingleton().renderTexRect( ulx, uly, lrx, lry, s, t, lrs, lrt, flip );
+        else
+            OpenGLRenderer::getSingleton().renderTexRect( ulx, lry, lrx, uly, s, lrt, lrs, t, flip );
+    }
+    else
+    {
+        if (lrt > t)
+            OpenGLRenderer::getSingleton().renderTexRect( lrx, uly, ulx, lry, lrs, t, s, lrt, flip );
+        else
+            OpenGLRenderer::getSingleton().renderTexRect( lrx, lry, ulx, uly, lrs, lrt, s, t, flip );
+    }
+
+    //Restore RSP Tile
+    int rspTile = m_rsp->getTexture().tile;
+    m_rsp->setTile( m_textureLoader->getTile( rspTile ), 0);
+    m_rsp->setTile( m_textureLoader->getTile(rspTile < 7 ? rspTile + 1 : rspTile), 1);
+
+    //glViewport( 0, m_windowMgr->getHeightOffset(), OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() );
+
+    glEnable(GL_SCISSOR_TEST);
+    OpenGLManager::getSingleton().setZBufferEnabled(zEnabled);
+}
+
+//-----------------------------------------------------------------------------
+//* Texture Rectangle Flip
+//! @todo: Clamp Tile
+//-----------------------------------------------------------------------------
+void RDP::_textureRectangleFlip(int nX0, int nY0, int nX1, int nY1, float fS0, float fT0, float fS1, float fT1, int tile)
+{
+    //Disable z buffer
+    bool zEnabled = OpenGLManager::getSingleton().getZBufferEnabled();
+    OpenGLManager::getSingleton().setZBufferEnabled(false);
+
+    float widthDiv = (float)m_textureLoader->getTile( m_rsp->getTexture().tile )->getWidth();
+    float heightDiv = (float)m_textureLoader->getTile( m_rsp->getTexture().tile )->getHeight();
+
+    float t0u0 = fS0 / widthDiv;
+    float t0v0 = fT0 / heightDiv;
+    float t0u1 = (fS1 - fS0)/ widthDiv + t0u0;
+    float t0v1 = (fT1 - fT0)/ heightDiv + t0v0;
+
+    float depth = m_otherMode.depthSource == 1 ? m_primitiveZ : 0;  //TODO: Use RSP viewport nearz?
+
+    static bool warned = false;
+    if( t0u0 >= 0 && t0u1 <= 1 && t0u1 >= t0u0 ) 
+    {
+        //TODO: Clamp Tile
+        if (!warned)
+        {
+            warned = true;
+            Logger::getSingleton().printMsg("_textureRectangleFlip - unimplemented", M64MSG_WARNING);
+        }
+    }
+    if( t0v0 >= 0 && t0v1 <= 1 && t0v1 >= t0v0 ) 
+    {
+        //TODO: Clamp tile
+        if (!warned)
+        {
+            warned = true;
+            Logger::getSingleton().printMsg("_textureRectangleFlip - unimplemented", M64MSG_WARNING);
+        }
+    }
+
+    //HACK 
+    if ( ROMDetector::getSingleton().getRomID() == SUPER_MARIO_64 )
+    {
+        t0u0 *= 0.5f;
+        t0v0 *= 0.5f;    
+        t0u1 *= 0.5f;    
+        t0v1 *= 0.5f;
+    }
+
+    //glViewport( 0, m_windowMgr->getHeightOffset(), OpenGLManager::getSingleton().getWidth(), OpenGLManager::getSingleton().getHeight() );
+
+    //Get Color
+    float color[4] = { 1,1,1,0 }; 
+    this->getCombinerMgr()->getCombinerColor(    &color[0] );
+    float secondaryColor[4] = { 1,1,1,1 };
+
+    if (  m_otherMode.cycleType == G_CYC_COPY )
+    {
+        glActiveTextureARB( GL_TEXTURE0_ARB );
+        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+    }
+
+    //Disable Scissor
+    glDisable( GL_SCISSOR_TEST );
+
+    //Render Quad
+    m_openGL2DRenderer->renderFlippedTexturedQuad( color, secondaryColor,
+                                                   (float)nX0, (float)nY0,
+                                                   (float)nX1, (float)nY1,
+                                                   depth,
+                                                   t0u0, t0v0,
+                                                   t0u1, t0v1, 
+                                                   t0u0, t0v0,
+                                                   t0u1, t0v1 );
+
+    //Restore states
+    glEnable(GL_SCISSOR_TEST);
+    OpenGLManager::getSingleton().setZBufferEnabled(zEnabled);
+}