Add {G,S}etRenderState and {G,S}etTextureStageState support, and
ensure the stateblock is fully populated at device startup.

diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 9e4b808..186609c 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -374,15 +374,12 @@
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_SetRenderState(LPDIRECT3DDEVICE9 iface, D3DRENDERSTATETYPE State, DWORD Value) {
     IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
-    FIXME("(%p) : stub\n", This);
-    return D3D_OK;
+    return IWineD3DDevice_SetRenderState(This->WineD3DDevice, State, Value);
 }
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_GetRenderState(LPDIRECT3DDEVICE9 iface, D3DRENDERSTATETYPE State, DWORD* pValue) {
     IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
-    TRACE("(%p) for State %d = %ld\n", This, State, This->UpdateStateBlock->renderstate[State]);
-    *pValue = This->StateBlock->renderstate[State];
-    return D3D_OK;
+    return IWineD3DDevice_GetRenderState(This->WineD3DDevice, State, pValue);
 }
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_SetClipStatus(LPDIRECT3DDEVICE9 iface, CONST D3DCLIPSTATUS9* pClipStatus) {
@@ -411,15 +408,12 @@
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_GetTextureStageState(LPDIRECT3DDEVICE9 iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
     IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
-    TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->UpdateStateBlock->texture_state[Stage][Type]);
-    *pValue = This->UpdateStateBlock->texture_state[Stage][Type];
-    return D3D_OK;
+    return IWineD3DDevice_GetTextureStageState(This->WineD3DDevice, Stage, Type, pValue);
 }
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_SetTextureStageState(LPDIRECT3DDEVICE9 iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
     IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface;
-    FIXME("(%p) : stub\n", This);
-    return D3D_OK;
+    return IWineD3DDevice_SetTextureStageState(This->WineD3DDevice, Stage, Type, Value);
 }
 
 HRESULT  WINAPI  IDirect3DDevice9Impl_GetSamplerState(LPDIRECT3DDEVICE9 iface, DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) {
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 1ddc657..4524ae3 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -124,6 +124,79 @@
     glPopMatrix();
 }
 
+/* Apply the current values to the specified texture stage */
+void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Stage, DWORD Flags) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    int i = 0;
+    float col[4];
+    BOOL changeTexture = TRUE;
+
+    TRACE("-----------------------> Updating the texture at stage %ld to have new texture state information\n", Stage);
+    for (i = 1; i < HIGHEST_TEXTURE_STATE; i++) {
+
+        BOOL skip = FALSE;
+
+        switch (i) {
+        /* Performance: For texture states where multiples effect the outcome, only bother
+              applying the last one as it will pick up all the other values                */
+        case D3DTSS_COLORARG0:  /* Will be picked up when setting color op */
+        case D3DTSS_COLORARG1:  /* Will be picked up when setting color op */
+        case D3DTSS_COLORARG2:  /* Will be picked up when setting color op */
+        case D3DTSS_ALPHAARG0:  /* Will be picked up when setting alpha op */
+        case D3DTSS_ALPHAARG1:  /* Will be picked up when setting alpha op */
+        case D3DTSS_ALPHAARG2:  /* Will be picked up when setting alpha op */
+           skip = TRUE;
+           break;
+
+        /* Performance: If the texture states only impact settings for the texture unit 
+             (compared to the texture object) then there is no need to reapply them. The
+             only time they need applying is the first time, since we cheat and put the  
+             values into the stateblock without applying.                                
+             Per-texture unit: texture function (eg. combine), ops and args
+                               texture env color                                               
+                               texture generation settings                               
+           Note: Due to some special conditions there may be a need to do particular ones
+             of these, which is what the Flags allows                                     */
+        case D3DTSS_COLOROP:       
+        case D3DTSS_TEXCOORDINDEX:
+            if (!(Flags == REAPPLY_ALL)) skip=TRUE;
+            break;
+
+        case D3DTSS_ALPHAOP:       
+            if (!(Flags & REAPPLY_ALPHAOP)) skip=TRUE;
+            break;
+
+        default:
+            skip = FALSE;
+        }
+
+        if (skip == FALSE) {
+           /* Performance: Only change to this texture if we have to */
+           if (changeTexture) {
+               /* Make appropriate texture active */
+               if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+                   GL_ACTIVETEXTURE(Stage);
+                } else if (Stage > 0) {
+                    FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
+                }
+                changeTexture = FALSE;
+           }
+
+           /* Now apply the change */
+           IWineD3DDevice_SetTextureStageState(iface, Stage, i, This->stateBlock->textureState[Stage][i]);
+        }
+    }
+
+    /* Note the D3DRS value applies to all textures, but GL has one
+     *  per texture, so apply it now ready to be used!
+     */
+    D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[D3DRS_TEXTUREFACTOR], col);
+    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
+    checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
+
+    TRACE("-----------------------> Updated the texture at stage %ld to have new texture state information\n", Stage);
+}
+
 /**********************************************************
  * IWineD3DDevice implementation follows
  **********************************************************/
@@ -347,7 +420,7 @@
             GL_ACTIVETEXTURE(tex);
 #if 0 /* TODO: */
             set_texture_matrix((float *)lpmatrix, 
-                               This->updateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]);
+                               This->updateStateBlock->textureState[tex][D3DTSS_TEXTURETRANSFORMFLAGS]);
 #endif
         }
 
@@ -992,13 +1065,10 @@
     checkGLcall("glMaterialfv");
 
     /* Only change material color if specular is enabled, otherwise it is set to black */
-#if 0 /* TODO */
-    if (This->stateBlock->renderstate[D3DRS_SPECULARENABLE]) {
-       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular);
+    if (This->stateBlock->renderState[D3DRS_SPECULARENABLE]) {
+       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
        checkGLcall("glMaterialfv");
     } else {
-#endif
-    {
        float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
        checkGLcall("glMaterialfv");
@@ -1108,6 +1178,1418 @@
 }
 
 /*****
+ * Get / Set Render States
+ * TODO: Verify against dx9 definitions
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
+
+    IWineD3DDeviceImpl  *This     = (IWineD3DDeviceImpl *)iface;
+    DWORD                OldValue = This->stateBlock->renderState[State];
+    
+    /* Simple way of refering to either a DWORD or a 4 byte float */
+    union {
+        DWORD d;
+        float f;
+    } tmpvalue;
+        
+    TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
+    This->updateStateBlock->changed.renderState[State] = TRUE;
+    This->updateStateBlock->set.renderState[State] = TRUE;
+    This->updateStateBlock->renderState[State] = Value;
+
+    /* Handle recording of state blocks */
+    if (This->isRecordingState) {
+        TRACE("Recording... not performing anything\n");
+        return D3D_OK;
+    }
+
+    ENTER_GL();
+
+    switch (State) {
+    case D3DRS_FILLMODE                  :
+        switch ((D3DFILLMODE) Value) {
+        case D3DFILL_POINT               : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
+        case D3DFILL_WIREFRAME           : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
+        case D3DFILL_SOLID               : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
+        default:
+            FIXME("Unrecognized D3DRS_FILLMODE value %ld\n", Value);
+        }
+        checkGLcall("glPolygonMode (fillmode)");
+        break;
+
+    case D3DRS_LIGHTING                  :
+        if (Value) {
+            glEnable(GL_LIGHTING);
+            checkGLcall("glEnable GL_LIGHTING");
+        } else {
+            glDisable(GL_LIGHTING);
+            checkGLcall("glDisable GL_LIGHTING");
+        }
+        break;
+
+    case D3DRS_ZENABLE                   :
+        switch ((D3DZBUFFERTYPE) Value) {
+        case D3DZB_FALSE:
+            glDisable(GL_DEPTH_TEST);
+            checkGLcall("glDisable GL_DEPTH_TEST");
+            break;
+        case D3DZB_TRUE:
+            glEnable(GL_DEPTH_TEST);
+            checkGLcall("glEnable GL_DEPTH_TEST");
+            break;
+        case D3DZB_USEW:
+            glEnable(GL_DEPTH_TEST);
+            checkGLcall("glEnable GL_DEPTH_TEST");
+            FIXME("W buffer is not well handled\n");
+            break;
+        default:
+            FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
+        }
+        break;
+
+    case D3DRS_CULLMODE                  :
+
+        /* If we are culling "back faces with clockwise vertices" then
+           set front faces to be counter clockwise and enable culling  
+           of back faces                                               */
+        switch ((D3DCULL) Value) {
+        case D3DCULL_NONE:
+            glDisable(GL_CULL_FACE);
+            checkGLcall("glDisable GL_CULL_FACE");
+            break;
+        case D3DCULL_CW:
+            glEnable(GL_CULL_FACE);
+            checkGLcall("glEnable GL_CULL_FACE");
+            if (This->renderUpsideDown) {
+                glFrontFace(GL_CW);
+                checkGLcall("glFrontFace GL_CW");
+            } else {
+                glFrontFace(GL_CCW);
+                checkGLcall("glFrontFace GL_CCW");
+            }
+            glCullFace(GL_BACK);
+            break;
+        case D3DCULL_CCW:
+            glEnable(GL_CULL_FACE);
+            checkGLcall("glEnable GL_CULL_FACE");
+            if (This->renderUpsideDown) {
+                glFrontFace(GL_CCW); 
+                checkGLcall("glFrontFace GL_CCW");
+            } else {
+                glFrontFace(GL_CW);
+                checkGLcall("glFrontFace GL_CW");
+            }
+            glCullFace(GL_BACK);
+            break;
+        default:
+            FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
+        }
+        break;
+
+    case D3DRS_SHADEMODE                 :
+        switch ((D3DSHADEMODE) Value) {
+        case D3DSHADE_FLAT:
+            glShadeModel(GL_FLAT);
+            checkGLcall("glShadeModel");
+            break;
+        case D3DSHADE_GOURAUD:
+            glShadeModel(GL_SMOOTH);
+            checkGLcall("glShadeModel");
+            break;
+        case D3DSHADE_PHONG:
+            FIXME("D3DSHADE_PHONG isn't supported?\n");
+
+            LEAVE_GL();
+            return D3DERR_INVALIDCALL;
+        default:
+            FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
+        }
+        break;
+
+    case D3DRS_DITHERENABLE              :
+        if (Value) {
+            glEnable(GL_DITHER);
+            checkGLcall("glEnable GL_DITHER");
+        } else {
+            glDisable(GL_DITHER);
+            checkGLcall("glDisable GL_DITHER");
+        }
+        break;
+
+    case D3DRS_ZWRITEENABLE              :
+        if (Value) {
+            glDepthMask(1);
+            checkGLcall("glDepthMask");
+        } else {
+            glDepthMask(0);
+            checkGLcall("glDepthMask");
+        }
+        break;
+
+    case D3DRS_ZFUNC                     :
+        {
+            int glParm = GL_LESS;
+
+            switch ((D3DCMPFUNC) Value) {
+            case D3DCMP_NEVER:         glParm=GL_NEVER; break;
+            case D3DCMP_LESS:          glParm=GL_LESS; break;
+            case D3DCMP_EQUAL:         glParm=GL_EQUAL; break;
+            case D3DCMP_LESSEQUAL:     glParm=GL_LEQUAL; break;
+            case D3DCMP_GREATER:       glParm=GL_GREATER; break;
+            case D3DCMP_NOTEQUAL:      glParm=GL_NOTEQUAL; break;
+            case D3DCMP_GREATEREQUAL:  glParm=GL_GEQUAL; break;
+            case D3DCMP_ALWAYS:        glParm=GL_ALWAYS; break;
+            default:
+                FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
+            }
+            glDepthFunc(glParm);
+            checkGLcall("glDepthFunc");
+        }
+        break;
+
+    case D3DRS_AMBIENT                   :
+        {
+            float col[4];
+            D3DCOLORTOGLFLOAT4(Value, col);
+            TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
+            glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
+            checkGLcall("glLightModel for MODEL_AMBIENT");
+
+        }
+        break;
+
+    case D3DRS_ALPHABLENDENABLE          :
+        if (Value) {
+            glEnable(GL_BLEND);
+            checkGLcall("glEnable GL_BLEND");
+        } else {
+            glDisable(GL_BLEND);
+            checkGLcall("glDisable GL_BLEND");
+        };
+        break;
+
+    case D3DRS_SRCBLEND                  :
+    case D3DRS_DESTBLEND                 :
+        {
+            int newVal = GL_ZERO;
+            switch (Value) {
+            case D3DBLEND_ZERO               : newVal = GL_ZERO;  break;
+            case D3DBLEND_ONE                : newVal = GL_ONE;  break;
+            case D3DBLEND_SRCCOLOR           : newVal = GL_SRC_COLOR;  break;
+            case D3DBLEND_INVSRCCOLOR        : newVal = GL_ONE_MINUS_SRC_COLOR;  break;
+            case D3DBLEND_SRCALPHA           : newVal = GL_SRC_ALPHA;  break;
+            case D3DBLEND_INVSRCALPHA        : newVal = GL_ONE_MINUS_SRC_ALPHA;  break;
+            case D3DBLEND_DESTALPHA          : newVal = GL_DST_ALPHA;  break;
+            case D3DBLEND_INVDESTALPHA       : newVal = GL_ONE_MINUS_DST_ALPHA;  break;
+            case D3DBLEND_DESTCOLOR          : newVal = GL_DST_COLOR;  break;
+            case D3DBLEND_INVDESTCOLOR       : newVal = GL_ONE_MINUS_DST_COLOR;  break;
+            case D3DBLEND_SRCALPHASAT        : newVal = GL_SRC_ALPHA_SATURATE;  break;
+
+            case D3DBLEND_BOTHSRCALPHA       : newVal = GL_SRC_ALPHA;
+                This->srcBlend = newVal;
+                This->dstBlend = newVal;
+                break;
+
+            case D3DBLEND_BOTHINVSRCALPHA    : newVal = GL_ONE_MINUS_SRC_ALPHA;
+                This->srcBlend = newVal;
+                This->dstBlend = newVal;
+                break;
+            default:
+                FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
+            }
+
+            if (State == D3DRS_SRCBLEND) This->srcBlend = newVal;
+            if (State == D3DRS_DESTBLEND) This->dstBlend = newVal;
+            TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
+            glBlendFunc(This->srcBlend, This->dstBlend);
+
+            checkGLcall("glBlendFunc");
+        }
+        break;
+
+    case D3DRS_ALPHATESTENABLE           :
+        if (Value) {
+            glEnable(GL_ALPHA_TEST);
+            checkGLcall("glEnable GL_ALPHA_TEST");
+        } else {
+            glDisable(GL_ALPHA_TEST);
+            checkGLcall("glDisable GL_ALPHA_TEST");
+        }
+        break;
+
+    case D3DRS_ALPHAFUNC                 :
+        {
+            int glParm = GL_LESS;
+            float ref = ((float) This->stateBlock->renderState[D3DRS_ALPHAREF]) / 255.0f;
+
+            switch ((D3DCMPFUNC) Value) {
+            case D3DCMP_NEVER:         glParm = GL_NEVER; break;
+            case D3DCMP_LESS:          glParm = GL_LESS; break;
+            case D3DCMP_EQUAL:         glParm = GL_EQUAL; break;
+            case D3DCMP_LESSEQUAL:     glParm = GL_LEQUAL; break;
+            case D3DCMP_GREATER:       glParm = GL_GREATER; break;
+            case D3DCMP_NOTEQUAL:      glParm = GL_NOTEQUAL; break;
+            case D3DCMP_GREATEREQUAL:  glParm = GL_GEQUAL; break;
+            case D3DCMP_ALWAYS:        glParm = GL_ALWAYS; break;
+            default:
+                FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
+            }
+            TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref);
+            glAlphaFunc(glParm, ref);
+            This->alphafunc = glParm;
+            checkGLcall("glAlphaFunc");
+        }
+        break;
+
+    case D3DRS_ALPHAREF                  :
+        {
+            int glParm = This->alphafunc;
+            float ref = 1.0f;
+
+            ref = ((float) Value) / 255.0f;
+            TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref);
+            glAlphaFunc(glParm, ref);
+            checkGLcall("glAlphaFunc");
+        }
+        break;
+
+    case D3DRS_CLIPPLANEENABLE           :
+    case D3DRS_CLIPPING                  :
+        {
+            /* Ensure we only do the changed clip planes */
+            DWORD enable  = 0xFFFFFFFF;
+            DWORD disable = 0x00000000;
+            
+            /* If enabling / disabling all */
+            if (State == D3DRS_CLIPPING) {
+                if (Value) {
+                    enable  = This->stateBlock->renderState[D3DRS_CLIPPLANEENABLE];
+                    disable = 0x00;
+                } else {
+                    disable = This->stateBlock->renderState[D3DRS_CLIPPLANEENABLE];
+                    enable  = 0x00;
+                }
+            } else {
+                enable =   Value & ~OldValue;
+                disable = ~Value &  OldValue;
+            }
+            
+            if (enable & D3DCLIPPLANE0)  { glEnable(GL_CLIP_PLANE0);  checkGLcall("glEnable(clip plane 0)"); }
+            if (enable & D3DCLIPPLANE1)  { glEnable(GL_CLIP_PLANE1);  checkGLcall("glEnable(clip plane 1)"); }
+            if (enable & D3DCLIPPLANE2)  { glEnable(GL_CLIP_PLANE2);  checkGLcall("glEnable(clip plane 2)"); }
+            if (enable & D3DCLIPPLANE3)  { glEnable(GL_CLIP_PLANE3);  checkGLcall("glEnable(clip plane 3)"); }
+            if (enable & D3DCLIPPLANE4)  { glEnable(GL_CLIP_PLANE4);  checkGLcall("glEnable(clip plane 4)"); }
+            if (enable & D3DCLIPPLANE5)  { glEnable(GL_CLIP_PLANE5);  checkGLcall("glEnable(clip plane 5)"); }
+            
+            if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
+            if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
+            if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
+            if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
+            if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
+            if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
+
+            /** update clipping status */
+            if (enable) {
+              This->stateBlock->clip_status.ClipUnion = 0;
+              This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
+            } else {
+              This->stateBlock->clip_status.ClipUnion = 0;
+              This->stateBlock->clip_status.ClipIntersection = 0;
+            }
+        }
+        break;
+
+    case D3DRS_BLENDOP                   :
+        {
+            int glParm = GL_FUNC_ADD;
+
+            switch ((D3DBLENDOP) Value) {
+            case D3DBLENDOP_ADD              : glParm = GL_FUNC_ADD;              break;
+            case D3DBLENDOP_SUBTRACT         : glParm = GL_FUNC_SUBTRACT;         break;
+            case D3DBLENDOP_REVSUBTRACT      : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
+            case D3DBLENDOP_MIN              : glParm = GL_MIN;                   break;
+            case D3DBLENDOP_MAX              : glParm = GL_MAX;                   break;
+            default:
+                FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
+            }
+            TRACE("glBlendEquation(%x)\n", glParm);
+            glBlendEquation(glParm);
+            checkGLcall("glBlendEquation");
+        }
+        break;
+
+    case D3DRS_TEXTUREFACTOR             :
+        {
+            unsigned int i;
+
+            /* Note the texture color applies to all textures whereas 
+               GL_TEXTURE_ENV_COLOR applies to active only */
+            float col[4];
+            D3DCOLORTOGLFLOAT4(Value, col);
+            /* Set the default alpha blend color */
+            glBlendColor(col[0], col[1], col[2], col[3]);
+            checkGLcall("glBlendColor");
+
+            /* And now the default texture color as well */
+            for (i = 0; i < GL_LIMITS(textures); i++) {
+
+                /* Note the D3DRS value applies to all textures, but GL has one
+                   per texture, so apply it now ready to be used!               */
+                if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+                    GL_ACTIVETEXTURE(i);
+                } else if (i>0) {
+                    FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
+                }
+
+                glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
+                checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
+            }
+        }
+        break;
+
+    case D3DRS_SPECULARENABLE            : 
+        {
+            /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
+               and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
+               specular color. This is wrong:
+               Separate specular color means the specular colour is maintained separately, whereas
+               single color means it is merged in. However in both cases they are being used to
+               some extent.
+               To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
+               NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
+                  running 1.4 yet!
+             */
+              if (Value) {
+                glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
+                checkGLcall("glMaterialfv");
+                if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
+                  glEnable(GL_COLOR_SUM_EXT);
+                } else {
+                  TRACE("Specular colors cannot be enabled in this version of opengl\n");
+                }
+                checkGLcall("glEnable(GL_COLOR_SUM)");
+              } else {
+                float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+                /* for the case of enabled lighting: */
+                glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
+                checkGLcall("glMaterialfv");
+
+                /* for the case of disabled lighting: */
+                if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
+                  glDisable(GL_COLOR_SUM_EXT);
+                } else {
+                  TRACE("Specular colors cannot be disabled in this version of opengl\n");
+                }
+                checkGLcall("glDisable(GL_COLOR_SUM)");
+              }
+        }
+        break;
+
+    case D3DRS_STENCILENABLE             :
+        if (Value) {
+            glEnable(GL_STENCIL_TEST);
+            checkGLcall("glEnable GL_STENCIL_TEST");
+        } else {
+            glDisable(GL_STENCIL_TEST);
+            checkGLcall("glDisable GL_STENCIL_TEST");
+        }
+        break;
+
+    case D3DRS_STENCILFUNC               :
+        {
+           int glParm = GL_ALWAYS;
+           int ref = This->stateBlock->renderState[D3DRS_STENCILREF];
+           GLuint mask = This->stateBlock->renderState[D3DRS_STENCILMASK];
+
+           switch ((D3DCMPFUNC) Value) {
+           case D3DCMP_NEVER:         glParm=GL_NEVER; break;
+           case D3DCMP_LESS:          glParm=GL_LESS; break;
+           case D3DCMP_EQUAL:         glParm=GL_EQUAL; break;
+           case D3DCMP_LESSEQUAL:     glParm=GL_LEQUAL; break;
+           case D3DCMP_GREATER:       glParm=GL_GREATER; break;
+           case D3DCMP_NOTEQUAL:      glParm=GL_NOTEQUAL; break;
+           case D3DCMP_GREATEREQUAL:  glParm=GL_GEQUAL; break;
+           case D3DCMP_ALWAYS:        glParm=GL_ALWAYS; break;
+           default:
+               FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
+           }
+           TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
+           This->stencilfunc = glParm;
+           glStencilFunc(glParm, ref, mask);
+           checkGLcall("glStencilFunc");
+        }
+        break;
+
+    case D3DRS_STENCILREF                :
+        {
+           int glParm = This->stencilfunc;
+           int ref = 0;
+           GLuint mask = This->stateBlock->renderState[D3DRS_STENCILMASK];
+
+           ref = Value;
+           TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
+           glStencilFunc(glParm, ref, mask);
+           checkGLcall("glStencilFunc");
+        }
+        break;
+
+    case D3DRS_STENCILMASK               :
+        {
+           int glParm = This->stencilfunc;
+           int ref = This->stateBlock->renderState[D3DRS_STENCILREF];
+           GLuint mask = Value;
+
+           TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
+           glStencilFunc(glParm, ref, mask);
+           checkGLcall("glStencilFunc");
+        }
+        break;
+
+    case D3DRS_STENCILFAIL               :
+        {
+            GLenum fail  ; 
+            GLenum zpass ; 
+            GLenum zfail ; 
+
+            fail = StencilOp(Value);
+            glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);
+            checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);");
+            glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);
+            checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);");
+
+            TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
+            glStencilOp(fail, zfail, zpass);
+            checkGLcall("glStencilOp(fail, zfail, zpass);");
+        }
+        break;
+    case D3DRS_STENCILZFAIL              :
+        {
+            GLenum fail  ; 
+            GLenum zpass ; 
+            GLenum zfail ; 
+
+            glGetIntegerv(GL_STENCIL_FAIL, &fail);
+            checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);");
+            glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);
+            checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);");
+            zfail = StencilOp(Value);
+
+            TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
+            glStencilOp(fail, zfail, zpass);
+            checkGLcall("glStencilOp(fail, zfail, zpass);");
+        }
+        break;
+    case D3DRS_STENCILPASS               :
+        {
+            GLenum fail  ; 
+            GLenum zpass ; 
+            GLenum zfail ; 
+
+            glGetIntegerv(GL_STENCIL_FAIL, &fail);
+            checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);");
+            zpass = StencilOp(Value);
+            glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);
+            checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);");
+
+            TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
+            glStencilOp(fail, zfail, zpass);
+            checkGLcall("glStencilOp(fail, zfail, zpass);");
+        }
+        break;
+
+    case D3DRS_STENCILWRITEMASK          :
+        {
+            glStencilMask(Value);
+            TRACE("glStencilMask(%lu)\n", Value);
+            checkGLcall("glStencilMask");
+        }
+        break;
+
+    case D3DRS_FOGENABLE                 :
+        {
+          if (Value/* && This->stateBlock->renderState[D3DRS_FOGTABLEMODE] != D3DFOG_NONE*/) {
+               glEnable(GL_FOG);
+               checkGLcall("glEnable GL_FOG");
+            } else {
+               glDisable(GL_FOG);
+               checkGLcall("glDisable GL_FOG");
+            }
+        }
+        break;
+
+    case D3DRS_RANGEFOGENABLE            :
+        {
+            if (Value) {
+              TRACE("Enabled RANGEFOG");
+            } else {
+              TRACE("Disabled RANGEFOG");
+            }
+        }
+        break;
+
+    case D3DRS_FOGCOLOR                  :
+        {
+            float col[4];
+            D3DCOLORTOGLFLOAT4(Value, col);
+            /* Set the default alpha blend color */
+            glFogfv(GL_FOG_COLOR, &col[0]);
+            checkGLcall("glFog GL_FOG_COLOR");
+        }
+        break;
+
+    case D3DRS_FOGTABLEMODE              :
+        { 
+          glHint(GL_FOG_HINT, GL_NICEST);
+          switch (Value) {
+          case D3DFOG_NONE:    /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; 
+          case D3DFOG_EXP:     glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; 
+          case D3DFOG_EXP2:    glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; 
+          case D3DFOG_LINEAR:  glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; 
+          default:
+            FIXME("Unsupported Value(%lu) for D3DRS_FOGTABLEMODE!\n", Value);
+          }
+          if (GL_SUPPORT(NV_FOG_DISTANCE)) {
+            glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
+          }
+        }
+        break;
+
+    case D3DRS_FOGVERTEXMODE             :
+        { 
+          glHint(GL_FOG_HINT, GL_FASTEST);
+          switch (Value) {
+          case D3DFOG_NONE:    /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; 
+          case D3DFOG_EXP:     glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; 
+          case D3DFOG_EXP2:    glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; 
+          case D3DFOG_LINEAR:  glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; 
+          default:
+            FIXME("Unsupported Value(%lu) for D3DRS_FOGTABLEMODE!\n", Value);
+          }
+          if (GL_SUPPORT(NV_FOG_DISTANCE)) {
+            glFogi(GL_FOG_DISTANCE_MODE_NV, This->stateBlock->renderState[D3DRS_RANGEFOGENABLE] ? GL_EYE_RADIAL_NV : GL_EYE_PLANE_ABSOLUTE_NV);
+          }
+        }
+        break;
+
+    case D3DRS_FOGSTART                  :
+        {
+            tmpvalue.d = Value;
+            glFogfv(GL_FOG_START, &tmpvalue.f);
+            checkGLcall("glFogf(GL_FOG_START, (float) Value)");
+            TRACE("Fog Start == %f\n", tmpvalue.f);
+        }
+        break;
+
+    case D3DRS_FOGEND                    :
+        {
+            tmpvalue.d = Value;
+            glFogfv(GL_FOG_END, &tmpvalue.f);
+            checkGLcall("glFogf(GL_FOG_END, (float) Value)");
+            TRACE("Fog End == %f\n", tmpvalue.f);
+        }
+        break;
+
+    case D3DRS_FOGDENSITY                :
+        {
+            tmpvalue.d = Value;
+            glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
+            checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
+        }
+        break;
+
+    case D3DRS_VERTEXBLEND               :
+        {
+          This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
+          TRACE("Vertex Blending state to %ld\n",  Value);
+        }
+        break;
+
+    case D3DRS_TWEENFACTOR               :
+        {
+          tmpvalue.d = Value;
+          This->updateStateBlock->tween_factor = tmpvalue.f;
+          TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
+        }
+        break;
+
+    case D3DRS_INDEXEDVERTEXBLENDENABLE  :
+        {
+          TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
+        }
+        break;
+
+    case D3DRS_COLORVERTEX               :
+    case D3DRS_DIFFUSEMATERIALSOURCE     :
+    case D3DRS_SPECULARMATERIALSOURCE    :
+    case D3DRS_AMBIENTMATERIALSOURCE     :
+    case D3DRS_EMISSIVEMATERIALSOURCE    :
+        {
+            GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
+
+            if (This->stateBlock->renderState[D3DRS_COLORVERTEX]) {
+                TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
+                      This->stateBlock->renderState[D3DRS_DIFFUSEMATERIALSOURCE],
+                      This->stateBlock->renderState[D3DRS_AMBIENTMATERIALSOURCE],
+                      This->stateBlock->renderState[D3DRS_EMISSIVEMATERIALSOURCE],
+                      This->stateBlock->renderState[D3DRS_SPECULARMATERIALSOURCE]);
+
+                if (This->stateBlock->renderState[D3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
+                    if (This->stateBlock->renderState[D3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
+                        Parm = GL_AMBIENT_AND_DIFFUSE;
+                    } else {
+                        Parm = GL_DIFFUSE;
+                    }
+                } else if (This->stateBlock->renderState[D3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
+                    Parm = GL_AMBIENT;
+                } else if (This->stateBlock->renderState[D3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
+                    Parm = GL_EMISSION;
+                } else if (This->stateBlock->renderState[D3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
+                    Parm = GL_SPECULAR;
+                } else {
+                    Parm = -1;
+                }
+
+                if (Parm == -1) {
+                    if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
+                } else {
+                    This->tracking_color = NEEDS_TRACKING;
+                    This->tracking_parm  = Parm;
+                }
+
+            } else {
+                if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
+            }
+        }
+        break; 
+
+    case D3DRS_LINEPATTERN               :
+        {
+            union {
+                DWORD                 d;
+                D3DLINEPATTERN        lp;
+            } tmppattern;
+            tmppattern.d = Value;
+
+            TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
+
+            if (tmppattern.lp.wRepeatFactor) {
+                glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
+                checkGLcall("glLineStipple(repeat, linepattern)");
+                glEnable(GL_LINE_STIPPLE);
+                checkGLcall("glEnable(GL_LINE_STIPPLE);");
+            } else {
+                glDisable(GL_LINE_STIPPLE);
+                checkGLcall("glDisable(GL_LINE_STIPPLE);");
+            }
+        }
+        break;
+
+    case D3DRS_ZBIAS                     :
+        {
+            if (Value) {
+                tmpvalue.d = Value;
+                TRACE("ZBias value %f\n", tmpvalue.f);
+                glPolygonOffset(0, -tmpvalue.f);
+                checkGLcall("glPolygonOffset(0, -Value)");
+                glEnable(GL_POLYGON_OFFSET_FILL);
+                checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
+                glEnable(GL_POLYGON_OFFSET_LINE);
+                checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
+                glEnable(GL_POLYGON_OFFSET_POINT);
+                checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
+            } else {
+                glDisable(GL_POLYGON_OFFSET_FILL);
+                checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
+                glDisable(GL_POLYGON_OFFSET_LINE);
+                checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
+                glDisable(GL_POLYGON_OFFSET_POINT);
+                checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
+            }
+        }
+        break;
+
+    case D3DRS_NORMALIZENORMALS          :
+        if (Value) {
+            glEnable(GL_NORMALIZE);
+            checkGLcall("glEnable(GL_NORMALIZE);");
+        } else {
+            glDisable(GL_NORMALIZE);
+            checkGLcall("glDisable(GL_NORMALIZE);");
+        }
+        break;
+
+    case D3DRS_POINTSIZE                 :
+        tmpvalue.d = Value;
+        TRACE("Set point size to %f\n", tmpvalue.f);
+        glPointSize(tmpvalue.f);
+        checkGLcall("glPointSize(...);");
+        break;
+
+    case D3DRS_POINTSIZE_MIN             :
+        if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
+          tmpvalue.d = Value;
+          GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
+          checkGLcall("glPointParameterfEXT(...);");
+        } else {
+          FIXME("D3DRS_POINTSIZE_MIN not supported on this opengl\n");
+        }
+        break;
+
+    case D3DRS_POINTSIZE_MAX             :
+        if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
+          tmpvalue.d = Value;
+          GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
+          checkGLcall("glPointParameterfEXT(...);");
+        } else {
+          FIXME("D3DRS_POINTSIZE_MAX not supported on this opengl\n");
+        }
+        break;
+
+    case D3DRS_POINTSCALE_A              :
+    case D3DRS_POINTSCALE_B              :
+    case D3DRS_POINTSCALE_C              :
+    case D3DRS_POINTSCALEENABLE          :
+        {
+            /* If enabled, supply the parameters, otherwise fall back to defaults */
+            if (This->stateBlock->renderState[D3DRS_POINTSCALEENABLE]) {
+                GLfloat att[3] = {1.0f, 0.0f, 0.0f};
+                att[0] = *((float*)&This->stateBlock->renderState[D3DRS_POINTSCALE_A]);
+                att[1] = *((float*)&This->stateBlock->renderState[D3DRS_POINTSCALE_B]);
+                att[2] = *((float*)&This->stateBlock->renderState[D3DRS_POINTSCALE_C]);
+
+                if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
+                  GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
+                  checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...);");
+                } else {
+                  TRACE("D3DRS_POINTSCALEENABLE not supported on this opengl\n");
+                }
+            } else {
+                GLfloat att[3] = {1.0f, 0.0f, 0.0f};
+                if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
+                  GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
+                  checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...);");
+                } else {
+                  TRACE("D3DRS_POINTSCALEENABLE not supported, but not on either\n");
+                }
+            }
+            break;
+        }
+
+    case D3DRS_COLORWRITEENABLE          :
+      {
+        TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n", 
+              Value & D3DCOLORWRITEENABLE_RED   ? 1 : 0,
+              Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
+              Value & D3DCOLORWRITEENABLE_BLUE  ? 1 : 0,
+              Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0); 
+        glColorMask(Value & D3DCOLORWRITEENABLE_RED   ? GL_TRUE : GL_FALSE, 
+                    Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
+                    Value & D3DCOLORWRITEENABLE_BLUE  ? GL_TRUE : GL_FALSE, 
+                    Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
+        checkGLcall("glColorMask(...)");
+      }
+      break;
+
+    case D3DRS_LOCALVIEWER               :
+      {
+        GLint state = (Value) ? 1 : 0;
+        TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);        
+        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
+      }
+      break;
+
+    case D3DRS_LASTPIXEL                 :
+      {
+        if (Value) {
+          TRACE("Last Pixel Drawing Enabled\n");  
+        } else {
+          FIXME("Last Pixel Drawing Disabled, not handled yet\n");  
+        }
+      }
+      break;
+
+    case D3DRS_SOFTWAREVERTEXPROCESSING  :
+      {
+        if (Value) {
+          TRACE("Software Processing Enabled\n");  
+        } else {
+          TRACE("Software Processing Disabled\n");  
+        }
+      }
+      break;
+
+      /** not supported */
+    case D3DRS_ZVISIBLE                  :
+      {
+        LEAVE_GL();
+        return D3DERR_INVALIDCALL;
+      }
+
+        /* Unhandled yet...! */
+    case D3DRS_EDGEANTIALIAS             :
+    case D3DRS_WRAP0                     :
+    case D3DRS_WRAP1                     :
+    case D3DRS_WRAP2                     :
+    case D3DRS_WRAP3                     :
+    case D3DRS_WRAP4                     :
+    case D3DRS_WRAP5                     :
+    case D3DRS_WRAP6                     :
+    case D3DRS_WRAP7                     :
+    case D3DRS_POINTSPRITEENABLE         :
+    case D3DRS_MULTISAMPLEANTIALIAS      :
+    case D3DRS_MULTISAMPLEMASK           :
+    case D3DRS_PATCHEDGESTYLE            :
+    case D3DRS_PATCHSEGMENTS             :
+    case D3DRS_DEBUGMONITORTOKEN         :
+    case D3DRS_POSITIONORDER             :
+    case D3DRS_NORMALORDER               :
+        /*Put back later: FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value); */
+        FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value);
+        break;
+    default:
+        FIXME("(%p)->(%d,%ld) unrecognized\n", This, State, Value);
+    }
+
+    LEAVE_GL();
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
+    *pValue = This->stateBlock->renderState[State];
+    return D3D_OK;
+}
+
+
+/*****
+ * Get / Set Texture Stage States
+ * TODO: Verify against dx9 definitions
+ *****/
+HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    union {
+        float f;
+        DWORD d;
+    } tmpvalue;
+
+    /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
+   
+    TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
+
+    /* Reject invalid texture units */
+    if (Stage >= GL_LIMITS(textures)) {
+        TRACE("Attempt to access invalid texture rejected\n");
+        return D3DERR_INVALIDCALL;
+    }
+
+    This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
+    This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
+    This->updateStateBlock->textureState[Stage][Type] = Value;
+
+    /* Handle recording of state blocks */
+    if (This->isRecordingState) {
+        TRACE("Recording... not performing anything\n");
+        return D3D_OK;
+    }
+
+    ENTER_GL();
+
+    /* Make appropriate texture active */
+    VTRACE(("Activating appropriate texture state %ld\n", Stage));
+    if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+        GL_ACTIVETEXTURE(Stage);
+    } else if (Stage > 0) {
+        FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
+    }
+
+    switch (Type) {
+
+    case D3DTSS_MINFILTER             :
+    case D3DTSS_MIPFILTER             :
+        {
+            DWORD ValueMIN = This->stateBlock->textureState[Stage][D3DTSS_MINFILTER];
+            DWORD ValueMIP = This->stateBlock->textureState[Stage][D3DTSS_MIPFILTER];
+            GLint realVal = GL_LINEAR;
+
+            if (ValueMIN == D3DTEXF_NONE) {
+              /* Doesn't really make sense - Windows just seems to disable
+                 mipmapping when this occurs                              */
+              FIXME("Odd - minfilter of none, just disabling mipmaps\n");
+              realVal = GL_LINEAR;
+            } else if (ValueMIN == D3DTEXF_POINT) {
+                /* GL_NEAREST_* */
+              if (ValueMIP == D3DTEXF_NONE) {
+                    realVal = GL_NEAREST;
+                } else if (ValueMIP == D3DTEXF_POINT) {
+                    realVal = GL_NEAREST_MIPMAP_NEAREST;
+                } else if (ValueMIP == D3DTEXF_LINEAR) {
+                    realVal = GL_NEAREST_MIPMAP_LINEAR;
+                } else {
+                    FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP);
+                    realVal = GL_NEAREST;
+                }
+            } else if (ValueMIN == D3DTEXF_LINEAR) {
+                /* GL_LINEAR_* */
+                if (ValueMIP == D3DTEXF_NONE) {
+                    realVal = GL_LINEAR;
+                } else if (ValueMIP == D3DTEXF_POINT) {
+                    realVal = GL_LINEAR_MIPMAP_NEAREST;
+                } else if (ValueMIP == D3DTEXF_LINEAR) {
+                    realVal = GL_LINEAR_MIPMAP_LINEAR;
+                } else {
+                    FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP);
+                    realVal = GL_LINEAR;
+                }
+            } else if (ValueMIN == D3DTEXF_ANISOTROPIC) {
+              if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
+                if (ValueMIP == D3DTEXF_NONE) {
+                  realVal = GL_LINEAR_MIPMAP_LINEAR;                  
+                } else if (ValueMIP == D3DTEXF_POINT) {
+                  realVal = GL_LINEAR_MIPMAP_NEAREST;
+                } else if (ValueMIP == D3DTEXF_LINEAR) {
+                    realVal = GL_LINEAR_MIPMAP_LINEAR;
+                } else {
+                  FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP);
+                  realVal = GL_LINEAR;
+                }
+              } else {
+                WARN("Trying to use ANISOTROPIC_FILTERING for D3DTSS_MINFILTER. But not supported by OpenGL driver\n");
+                realVal = GL_LINEAR;
+              }
+            } else {
+                FIXME("Unhandled D3DTSS_MINFILTER value of %ld\n", ValueMIN);
+                realVal = GL_LINEAR_MIPMAP_LINEAR;
+            }
+
+            TRACE("ValueMIN=%ld, ValueMIP=%ld, setting MINFILTER to %x\n", ValueMIN, ValueMIP, realVal);
+            glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_MIN_FILTER, realVal);
+            checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");
+            /**
+             * if we juste choose to use ANISOTROPIC filtering, refresh openGL state
+             */
+            if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && D3DTEXF_ANISOTROPIC == ValueMIN) {
+              glTexParameteri(This->stateBlock->textureDimensions[Stage], 
+                              GL_TEXTURE_MAX_ANISOTROPY_EXT, 
+                              This->stateBlock->textureState[Stage][D3DTSS_MAXANISOTROPY]);
+              checkGLcall("glTexParameter GL_TEXTURE_MAX_ANISOTROPY_EXT, ...");
+            }
+        }
+        break;
+
+    case D3DTSS_MAGFILTER             :
+      {
+        DWORD ValueMAG = This->stateBlock->textureState[Stage][D3DTSS_MAGFILTER];
+        GLint realVal = GL_NEAREST;
+
+        if (ValueMAG == D3DTEXF_POINT) {
+          realVal = GL_NEAREST;
+        } else if (ValueMAG == D3DTEXF_LINEAR) {
+          realVal = GL_LINEAR;
+        } else if (ValueMAG == D3DTEXF_ANISOTROPIC) {
+          if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
+            realVal = GL_LINEAR;
+          } else {
+            FIXME("Trying to use ANISOTROPIC_FILTERING for D3DTSS_MAGFILTER. But not supported by current OpenGL driver\n");
+            realVal = GL_NEAREST;
+          }
+        } else {
+          FIXME("Unhandled D3DTSS_MAGFILTER value of %ld\n", ValueMAG);
+          realVal = GL_NEAREST;
+        }
+        TRACE("ValueMAG=%ld setting MAGFILTER to %x\n", ValueMAG, realVal);
+        glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_MAG_FILTER, realVal);
+        checkGLcall("glTexParameter GL_TEXTURE_MAG_FILTER, ...");
+        /**
+         * if we juste choose to use ANISOTROPIC filtering, refresh openGL state
+         */
+        if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && D3DTEXF_ANISOTROPIC == ValueMAG) {
+          glTexParameteri(This->stateBlock->textureDimensions[Stage], 
+                          GL_TEXTURE_MAX_ANISOTROPY_EXT, 
+                          This->stateBlock->textureState[Stage][D3DTSS_MAXANISOTROPY]);
+          checkGLcall("glTexParameter GL_TEXTURE_MAX_ANISOTROPY_EXT, ...");
+        }
+      }
+      break;
+
+    case D3DTSS_MAXMIPLEVEL           :
+      {
+        /**
+         * Not really the same, but the more apprioprate than nothing
+         */
+        glTexParameteri(This->stateBlock->textureDimensions[Stage], 
+                        GL_TEXTURE_BASE_LEVEL, 
+                        This->stateBlock->textureState[Stage][D3DTSS_MAXMIPLEVEL]);
+        checkGLcall("glTexParameteri GL_TEXTURE_BASE_LEVEL ...");
+      }
+      break;
+
+    case D3DTSS_MAXANISOTROPY         :
+      {        
+        if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) {
+          glTexParameteri(This->stateBlock->textureDimensions[Stage], 
+                          GL_TEXTURE_MAX_ANISOTROPY_EXT, 
+                          This->stateBlock->textureState[Stage][D3DTSS_MAXANISOTROPY]);
+          checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ...");
+        }
+      }
+      break;
+
+    case D3DTSS_MIPMAPLODBIAS         :
+      {        
+        if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
+          tmpvalue.d = Value;
+          glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, 
+                    GL_TEXTURE_LOD_BIAS_EXT,
+                    tmpvalue.f);
+          checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
+        }
+      }
+      break;
+
+    case D3DTSS_ALPHAOP               :
+    case D3DTSS_COLOROP               :
+        {
+
+            if ((Value == D3DTOP_DISABLE) && (Type == D3DTSS_COLOROP)) {
+                /* TODO: Disable by making this and all later levels disabled */
+                glDisable(GL_TEXTURE_1D);
+                checkGLcall("Disable GL_TEXTURE_1D");
+                glDisable(GL_TEXTURE_2D);
+                checkGLcall("Disable GL_TEXTURE_2D");
+                glDisable(GL_TEXTURE_3D);
+                checkGLcall("Disable GL_TEXTURE_3D");
+                break; /* Don't bother setting the texture operations */
+            } else {
+                /* Enable only the appropriate texture dimension */
+                if (Type == D3DTSS_COLOROP) {
+                    if (This->stateBlock->textureDimensions[Stage] == GL_TEXTURE_1D) {
+                        glEnable(GL_TEXTURE_1D);
+                        checkGLcall("Enable GL_TEXTURE_1D");
+                    } else {
+                        glDisable(GL_TEXTURE_1D);
+                        checkGLcall("Disable GL_TEXTURE_1D");
+                    } 
+                    if (This->stateBlock->textureDimensions[Stage] == GL_TEXTURE_2D) {
+                      if (GL_SUPPORT(NV_TEXTURE_SHADER) && This->texture_shader_active) {
+                        glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
+                        checkGLcall("Enable GL_TEXTURE_2D");
+                      } else {
+                        glEnable(GL_TEXTURE_2D);
+                        checkGLcall("Enable GL_TEXTURE_2D");
+                      }
+                    } else {
+                        glDisable(GL_TEXTURE_2D);
+                        checkGLcall("Disable GL_TEXTURE_2D");
+                    }
+                    if (This->stateBlock->textureDimensions[Stage] == GL_TEXTURE_3D) {
+                        glEnable(GL_TEXTURE_3D);
+                        checkGLcall("Enable GL_TEXTURE_3D");
+                    } else {
+                        glDisable(GL_TEXTURE_3D);
+                        checkGLcall("Disable GL_TEXTURE_3D");
+                    }
+                    if (This->stateBlock->textureDimensions[Stage] == GL_TEXTURE_CUBE_MAP_ARB) {
+                        glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+                        checkGLcall("Enable GL_TEXTURE_CUBE_MAP");
+                    } else {
+                        glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+                        checkGLcall("Disable GL_TEXTURE_CUBE_MAP");
+                    }
+                }
+            }
+            /* Drop through... (Except disable case) */
+        case D3DTSS_COLORARG0             :
+        case D3DTSS_COLORARG1             :
+        case D3DTSS_COLORARG2             :
+        case D3DTSS_ALPHAARG0             :
+        case D3DTSS_ALPHAARG1             :
+        case D3DTSS_ALPHAARG2             :
+            {
+                BOOL isAlphaArg = (Type == D3DTSS_ALPHAOP || Type == D3DTSS_ALPHAARG1 || 
+                                   Type == D3DTSS_ALPHAARG2 || Type == D3DTSS_ALPHAARG0);
+                if (isAlphaArg) {
+                    set_tex_op(iface, TRUE, Stage, This->stateBlock->textureState[Stage][D3DTSS_ALPHAOP],
+                               This->stateBlock->textureState[Stage][D3DTSS_ALPHAARG1], 
+                               This->stateBlock->textureState[Stage][D3DTSS_ALPHAARG2], 
+                               This->stateBlock->textureState[Stage][D3DTSS_ALPHAARG0]);
+                } else {
+                    set_tex_op(iface, FALSE, Stage, This->stateBlock->textureState[Stage][D3DTSS_COLOROP],
+                               This->stateBlock->textureState[Stage][D3DTSS_COLORARG1], 
+                               This->stateBlock->textureState[Stage][D3DTSS_COLORARG2], 
+                               This->stateBlock->textureState[Stage][D3DTSS_COLORARG0]);
+                }
+            }
+            break;
+        }
+
+    case D3DTSS_ADDRESSU              :
+    case D3DTSS_ADDRESSV              :
+    case D3DTSS_ADDRESSW              :
+        {
+            GLint wrapParm = GL_REPEAT;
+
+            switch (Value) {
+            case D3DTADDRESS_WRAP:   wrapParm = GL_REPEAT; break;
+            case D3DTADDRESS_CLAMP:  wrapParm = GL_CLAMP_TO_EDGE; break;      
+            case D3DTADDRESS_BORDER: 
+              {
+                if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) {
+                  wrapParm = GL_CLAMP_TO_BORDER_ARB; 
+                } else {
+                  /* FIXME: Not right, but better */
+                  FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
+                  wrapParm = GL_REPEAT; 
+                }
+              }
+              break;
+            case D3DTADDRESS_MIRROR: 
+              {
+                if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) {
+                  wrapParm = GL_MIRRORED_REPEAT_ARB;
+                } else {
+                  /* Unsupported in OpenGL pre-1.4 */
+                  FIXME("Unsupported D3DTADDRESS_MIRROR (needs GL_ARB_texture_mirrored_repeat) state %d\n", Type);
+                  wrapParm = GL_REPEAT;
+                }
+              }
+              break;
+            case D3DTADDRESS_MIRRORONCE: 
+              {
+                if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) {
+                  wrapParm = GL_MIRROR_CLAMP_TO_EDGE_ATI;
+                } else {
+                  FIXME("Unsupported D3DTADDRESS_MIRRORONCE (needs GL_ATI_texture_mirror_once) state %d\n", Type);
+                  wrapParm = GL_REPEAT; 
+                }
+              }
+              break;
+
+            default:
+                FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
+                wrapParm = GL_REPEAT; 
+            }
+
+            switch (Type) {
+            case D3DTSS_ADDRESSU:
+                TRACE("Setting WRAP_S to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
+                glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_S, wrapParm);
+                checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_S, wrapParm)");
+                break;
+            case D3DTSS_ADDRESSV:
+                TRACE("Setting WRAP_T to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
+                glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_T, wrapParm);
+                checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_T, wrapParm)");
+                break;
+            case D3DTSS_ADDRESSW:
+                TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
+                glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
+                checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
+                break;
+            default: /* nop */
+                      break; /** stupic compilator */
+            }
+        }
+        break;
+
+    case D3DTSS_BORDERCOLOR           :
+        {
+            float col[4];
+            D3DCOLORTOGLFLOAT4(Value, col);
+            TRACE("Setting border color for %x to %lx\n", This->stateBlock->textureDimensions[Stage], Value); 
+            glTexParameterfv(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_BORDER_COLOR, &col[0]);
+            checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)");
+        }
+        break;
+
+    case D3DTSS_TEXCOORDINDEX         :
+        {
+            /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
+
+            /* FIXME: From MSDN: The D3DTSS_TCI_* flags are mutually exclusive. If you include 
+                  one flag, you can still specify an index value, which the system uses to 
+                  determine the texture wrapping mode.  
+                  eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
+                  means use the vertex position (camera-space) as the input texture coordinates 
+                  for this texture stage, and the wrap mode set in the D3DRS_WRAP1 render 
+                  state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
+                  to the TEXCOORDINDEX value */
+          
+            /** 
+             * Be careful the value of the mask 0xF0000 come from d3d8types.h infos 
+             */
+            switch (Value & 0xFFFF0000) {
+            case D3DTSS_TCI_PASSTHRU:
+              /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
+              glDisable(GL_TEXTURE_GEN_S);
+              glDisable(GL_TEXTURE_GEN_T);
+              glDisable(GL_TEXTURE_GEN_R);
+              checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R)");
+              break;
+
+            case D3DTSS_TCI_CAMERASPACEPOSITION:
+              /* CameraSpacePosition means use the vertex position, transformed to camera space, 
+                 as the input texture coordinates for this stage's texture transformation. This 
+                 equates roughly to EYE_LINEAR                                                  */
+              {
+                float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
+                float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
+                float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
+                float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
+                TRACE("D3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
+
+                glMatrixMode(GL_MODELVIEW);
+                glPushMatrix();
+                glLoadIdentity();
+                glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
+                glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
+                glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
+                glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
+                glPopMatrix();
+                
+                TRACE("D3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
+                glEnable(GL_TEXTURE_GEN_S);
+                checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
+                glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+                checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
+                glEnable(GL_TEXTURE_GEN_T);
+                checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
+                glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+                checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
+                glEnable(GL_TEXTURE_GEN_R);
+                checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
+                glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+                checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
+              }
+              break;
+
+            case D3DTSS_TCI_CAMERASPACENORMAL:
+              {
+                if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
+                  float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
+                  float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
+                  float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
+                  float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
+                  TRACE("D3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
+
+                  glMatrixMode(GL_MODELVIEW);
+                  glPushMatrix();
+                  glLoadIdentity();
+                  glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
+                  glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
+                  glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
+                  glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
+                  glPopMatrix();
+                  
+                  glEnable(GL_TEXTURE_GEN_S);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
+                  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
+                  checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
+                  glEnable(GL_TEXTURE_GEN_T);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
+                  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
+                  checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
+                  glEnable(GL_TEXTURE_GEN_R);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
+                  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
+                  checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
+                }
+              }
+              break;
+
+            case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
+              {
+                if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
+                  float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
+                  float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
+                  float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
+                  float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
+                  TRACE("D3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
+                  
+                  glMatrixMode(GL_MODELVIEW);
+                  glPushMatrix();
+                  glLoadIdentity();
+                  glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
+                  glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
+                  glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
+                  glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
+                  glPopMatrix();
+                  
+                  glEnable(GL_TEXTURE_GEN_S);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
+                  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
+                  checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
+                  glEnable(GL_TEXTURE_GEN_T);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
+                  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
+                  checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
+                  glEnable(GL_TEXTURE_GEN_R);
+                  checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
+                  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
+                  checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
+                }
+              }
+              break;
+
+            /* Unhandled types: */
+            default:
+                /* Todo: */
+                /* ? disable GL_TEXTURE_GEN_n ? */ 
+                glDisable(GL_TEXTURE_GEN_S);
+                glDisable(GL_TEXTURE_GEN_T);
+                glDisable(GL_TEXTURE_GEN_R);
+                FIXME("Unhandled D3DTSS_TEXCOORDINDEX %lx\n", Value);
+                break;
+            }
+        }
+        break;
+
+        /* Unhandled */
+    case D3DTSS_TEXTURETRANSFORMFLAGS :
+        set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value);
+        break; 
+
+    case D3DTSS_BUMPENVMAT00          :
+    case D3DTSS_BUMPENVMAT01          :
+        TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - D3DTSS_BUMPENVMAT00, Stage, Type, Value);
+        break;
+    case D3DTSS_BUMPENVMAT10          :
+    case D3DTSS_BUMPENVMAT11          :
+        TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - D3DTSS_BUMPENVMAT10, Stage, Type, Value);
+        break;
+
+    case D3DTSS_BUMPENVLSCALE         :
+      TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
+      break;
+
+    case D3DTSS_BUMPENVLOFFSET        :
+      TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
+      break;
+
+    case D3DTSS_RESULTARG             :
+      TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
+      break;
+
+    default:
+        /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
+        TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
+    }
+
+    LEAVE_GL();
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+    TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
+    *pValue = This->updateStateBlock->textureState[Stage][Type];
+    return D3D_OK;
+}
+
+/*****
  * Scene related functions
  *****/
 HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
@@ -1290,11 +2772,17 @@
     IWineD3DDeviceImpl_GetIndices,
     IWineD3DDeviceImpl_SetViewport,
     IWineD3DDeviceImpl_GetViewport,
+    IWineD3DDeviceImpl_SetRenderState,
+    IWineD3DDeviceImpl_GetRenderState,
+    IWineD3DDeviceImpl_SetTextureStageState,
+    IWineD3DDeviceImpl_GetTextureStageState,
 
     IWineD3DDeviceImpl_BeginScene,
 
     IWineD3DDeviceImpl_DrawPrimitive,
     IWineD3DDeviceImpl_DrawIndexedPrimitive,
     IWineD3DDeviceImpl_DrawPrimitiveUP,
-    IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
+    IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
+
+    IWineD3DDeviceImpl_SetupTextureStates
 };
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index a2fa093..5b7fcd8 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -1565,7 +1565,7 @@
        vp.Height = *(pPresentationParameters->BackBufferHeight);
        vp.MinZ   = 0.0f;
        vp.MaxZ   = 1.0f;
-       /* TODO: IWineD3DDevice_SetViewport((LPDIRECT3DDEVICE9) object, &vp); */
+       IWineD3DDevice_SetViewport((IWineD3DDevice *)object, &vp);
     }
 
     /* Initialize the current view state */
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 7a23b45..ec6fccc 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -202,14 +202,10 @@
         checkGLcall("glMaterialfv");
         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
         checkGLcall("glMaterialfv");
-#if 0 /* TODO */
-        if (This->stateBlock->renderstate[D3DRS_SPECULARENABLE]) {
+        if (This->stateBlock->renderState[D3DRS_SPECULARENABLE]) {
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
            checkGLcall("glMaterialfv");
         } else {
-#else
-        {
-#endif
            float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
            checkGLcall("glMaterialfv");
@@ -429,7 +425,7 @@
         }
 
         /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
-        /** do we have to Check This->updateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
+        /** do we have to Check This->updateStateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
         numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 + 
                     ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1);    /* WARNING can be < 0 because -2 */
         if (numBlends > 0) {
@@ -1502,7 +1498,7 @@
 
     	useHW = (((vs_mode == VS_HW) && GL_SUPPORT(ARB_VERTEX_PROGRAM)) &&
                  This->devType != D3DDEVTYPE_REF &&
-	         !This->stateBlock->renderstate[D3DRS_SOFTWAREVERTEXPROCESSING] &&
+	         !This->stateBlock->renderState[D3DRS_SOFTWAREVERTEXPROCESSING] &&
 		 vertex_shader->usage != D3DUSAGE_SOFTWAREPROCESSING);
 
         /** init Constants */
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 61d1fbd..2117a3f 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -34,6 +34,16 @@
 
 HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock* iface) {
     IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface;
+    IWineD3DDeviceImpl     *ThisDevice = (IWineD3DDeviceImpl *)(This->wineD3DDevice);
+    union {
+        D3DLINEPATTERN lp;
+        DWORD d;
+    } lp;
+    union {
+        float f;
+        DWORD d;
+    } tmpfloat;
+    unsigned int i;
 
     /* Note this may have a large overhead but it should only be executed
        once, in order to initialize the complete state of the device and 
@@ -41,6 +51,205 @@
     TRACE("-----------------------> Setting up device defaults...\n");
     This->blockType = D3DSBT_ALL;
 
+    /* FIXME: Set some of the defaults for lights, transforms etc */
+    memcpy(&This->transforms[D3DTS_PROJECTION], &identity, sizeof(identity));
+    memcpy(&This->transforms[D3DTS_VIEW], &identity, sizeof(identity));
+    for (i = 0; i < 256; ++i) {
+      memcpy(&This->transforms[D3DTS_WORLDMATRIX(i)], &identity, sizeof(identity));
+    }
+ 
+    /* Render states: */
+    if (ThisDevice->presentParms.EnableAutoDepthStencil) {
+       IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZENABLE, D3DZB_TRUE);
+    } else {
+       IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZENABLE, D3DZB_FALSE);
+    }
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FILLMODE, D3DFILL_SOLID);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
+
+    lp.lp.wRepeatFactor = 0; lp.lp.wLinePattern = 0;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_LINEPATTERN, lp.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZWRITEENABLE, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ALPHATESTENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_LASTPIXEL, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_SRCBLEND, D3DBLEND_ONE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_DESTBLEND, D3DBLEND_ZERO);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_CULLMODE, D3DCULL_CCW);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ALPHAREF, 0xff); /*??*/
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_DITHERENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ALPHABLENDENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_SPECULARENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZVISIBLE, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGCOLOR, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGTABLEMODE, D3DFOG_NONE);
+    tmpfloat.f = 0.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGSTART, tmpfloat.d);
+    tmpfloat.f = 1.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGEND, tmpfloat.d);
+    tmpfloat.f = 1.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGDENSITY, tmpfloat.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_EDGEANTIALIAS, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_ZBIAS, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_RANGEFOGENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
+
+    /* Setting stencil func also uses values for stencil ref/mask, so manually set defaults
+     * so only a single call performed (and ensure defaults initialized before making that call)    
+     *
+     * IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILREF, 0);
+     * IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILMASK, 0xFFFFFFFF);
+     */
+    This->renderState[D3DRS_STENCILREF] = 0;
+    This->renderState[D3DRS_STENCILMASK] = 0xFFFFFFFF;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_STENCILWRITEMASK, 0xFFFFFFFF);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_TEXTUREFACTOR, 0xFFFFFFFF);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP0, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP1, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP2, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP3, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP4, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP5, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP6, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_WRAP7, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_CLIPPING, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_LIGHTING, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_AMBIENT, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_COLORVERTEX, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_LOCALVIEWER, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_NORMALIZENORMALS, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR2);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_CLIPPLANEENABLE, 0);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_SOFTWAREVERTEXPROCESSING, FALSE);
+    tmpfloat.f = 1.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSIZE, tmpfloat.d);
+    tmpfloat.f = 0.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSIZE_MIN, tmpfloat.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSPRITEENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSCALEENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSCALE_A, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSCALE_B, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSCALE_C, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE);
+    tmpfloat.f = 1.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_PATCHSEGMENTS, tmpfloat.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_DEBUGMONITORTOKEN, D3DDMT_DISABLE);
+    tmpfloat.f = 64.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POINTSIZE_MAX, tmpfloat.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_COLORWRITEENABLE, 0x0000000F);
+    tmpfloat.f = 0.0f;
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_TWEENFACTOR, tmpfloat.d);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_BLENDOP, D3DBLENDOP_ADD);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_POSITIONORDER, D3DORDER_CUBIC);
+    IWineD3DDevice_SetRenderState(This->wineD3DDevice, D3DRS_NORMALORDER, D3DORDER_LINEAR);
+
+    /** clipping status */
+    This->clip_status.ClipUnion = 0;
+    This->clip_status.ClipIntersection = 0xFFFFFFFF;
+        
+    /* Texture Stage States - Put directly into state block, we will call function below */
+    for (i = 0; i < GL_LIMITS(textures); i++) {
+        TRACE("Setting up default texture states for texture Stage %d\n", i);
+        memcpy(&This->transforms[D3DTS_TEXTURE0 + i], &identity, sizeof(identity));
+        This->textureState[i][D3DTSS_COLOROP               ] = (i==0)? D3DTOP_MODULATE :  D3DTOP_DISABLE;
+        This->textureState[i][D3DTSS_COLORARG1             ] = D3DTA_TEXTURE;
+        This->textureState[i][D3DTSS_COLORARG2             ] = D3DTA_CURRENT;
+        This->textureState[i][D3DTSS_ALPHAOP               ] = (i==0)? D3DTOP_SELECTARG1 :  D3DTOP_DISABLE;
+        This->textureState[i][D3DTSS_ALPHAARG1             ] = D3DTA_TEXTURE;
+        This->textureState[i][D3DTSS_ALPHAARG2             ] = D3DTA_CURRENT;
+        This->textureState[i][D3DTSS_BUMPENVMAT00          ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_BUMPENVMAT01          ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_BUMPENVMAT10          ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_BUMPENVMAT11          ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_TEXCOORDINDEX         ] = i;
+        This->textureState[i][D3DTSS_ADDRESSU              ] = D3DTADDRESS_WRAP;
+        This->textureState[i][D3DTSS_ADDRESSV              ] = D3DTADDRESS_WRAP;
+        This->textureState[i][D3DTSS_BORDERCOLOR           ] = 0x00;
+        This->textureState[i][D3DTSS_MAGFILTER             ] = D3DTEXF_POINT;
+        This->textureState[i][D3DTSS_MINFILTER             ] = D3DTEXF_POINT;
+        This->textureState[i][D3DTSS_MIPFILTER             ] = D3DTEXF_NONE;
+        This->textureState[i][D3DTSS_MIPMAPLODBIAS         ] = 0;
+        This->textureState[i][D3DTSS_MAXMIPLEVEL           ] = 0;
+        This->textureState[i][D3DTSS_MAXANISOTROPY         ] = 1;
+        This->textureState[i][D3DTSS_BUMPENVLSCALE         ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_BUMPENVLOFFSET        ] = (DWORD) 0.0;
+        This->textureState[i][D3DTSS_TEXTURETRANSFORMFLAGS ] = D3DTTFF_DISABLE;
+        This->textureState[i][D3DTSS_ADDRESSW              ] = D3DTADDRESS_WRAP;
+        This->textureState[i][D3DTSS_COLORARG0             ] = D3DTA_CURRENT;
+        This->textureState[i][D3DTSS_ALPHAARG0             ] = D3DTA_CURRENT;
+        This->textureState[i][D3DTSS_RESULTARG             ] = D3DTA_CURRENT;
+    }
+
+    /* Under DirectX you can have texture stage operations even if no texture is
+       bound, whereas opengl will only do texture operations when a valid texture is
+       bound. We emulate this by creating dummy textures and binding them to each
+       texture stage, but disable all stages by default. Hence if a stage is enabled
+       then the default texture will kick in until replaced by a SetTexture call     */
+
+    ENTER_GL();
+
+    for (i = 0; i < GL_LIMITS(textures); i++) {
+        GLubyte white = 255;
+
+        /* Note this avoids calling settexture, so pretend it has been called */
+        This->set.textures[i] = TRUE;
+        This->changed.textures[i] = TRUE;
+        This->textures[i] = NULL;
+
+        /* Make appropriate texture active */
+        if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+            GL_ACTIVETEXTURE(i);
+        } else if (i > 0) {
+            FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
+        }
+
+        /* Generate an opengl texture name */
+        glGenTextures(1, &ThisDevice->dummyTextureName[i]);
+        checkGLcall("glGenTextures");
+        TRACE("Dummy Texture %d given name %d\n", i, ThisDevice->dummyTextureName[i]);
+
+        /* Generate a dummy 1d texture */
+        This->textureDimensions[i] = GL_TEXTURE_1D;
+        glBindTexture(GL_TEXTURE_1D, ThisDevice->dummyTextureName[i]);
+        checkGLcall("glBindTexture");
+
+        glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white); 
+        checkGLcall("glTexImage1D");
+
+        /* Reapply all the texture state information to this texture */
+        IWineD3DDevice_SetupTextureStates(This->wineD3DDevice, i, REAPPLY_ALL);
+    }
+
+    LEAVE_GL();
+
+#if 0 /* TODO: Palette support */
+    /* defaulting palettes */
+    for (i = 0; i < MAX_PALETTES; ++i) {
+      int j;
+      for (j = 0; j < 256; ++j) {
+        This->palettes[i][j].peRed   = 0xFF;
+        This->palettes[i][j].peGreen = 0xFF;
+        This->palettes[i][j].peBlue  = 0xFF;
+        This->palettes[i][j].peFlags = 0xFF;
+      }
+    }
+    This->currentPalette = 0;
+#endif /* TODO: Palette support */
+
     TRACE("-----------------------> Device defaults now set up...\n");
     return D3D_OK;
 }
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index d4a6332..0e0223d 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -25,6 +25,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
+/*****************************************************************************
+ * Trace formatting of useful values
+ */
 const char* debug_d3dformat(D3DFORMAT fmt) {
   switch (fmt) {
 #define FMT_TO_STR(fmt) case fmt: return #fmt
@@ -140,3 +143,1379 @@
     return "unrecognized";
   }
 }
+
+const char* debug_d3drenderstate(DWORD state) {
+  switch (state) {
+#define D3DSTATE_TO_STR(u) case u: return #u
+    D3DSTATE_TO_STR(D3DRS_ZENABLE                   );
+    D3DSTATE_TO_STR(D3DRS_FILLMODE                  );
+    D3DSTATE_TO_STR(D3DRS_SHADEMODE                 );
+    D3DSTATE_TO_STR(D3DRS_LINEPATTERN               );
+    D3DSTATE_TO_STR(D3DRS_ZWRITEENABLE              );
+    D3DSTATE_TO_STR(D3DRS_ALPHATESTENABLE           );
+    D3DSTATE_TO_STR(D3DRS_LASTPIXEL                 );
+    D3DSTATE_TO_STR(D3DRS_SRCBLEND                  );
+    D3DSTATE_TO_STR(D3DRS_DESTBLEND                 );
+    D3DSTATE_TO_STR(D3DRS_CULLMODE                  );
+    D3DSTATE_TO_STR(D3DRS_ZFUNC                     );
+    D3DSTATE_TO_STR(D3DRS_ALPHAREF                  );
+    D3DSTATE_TO_STR(D3DRS_ALPHAFUNC                 );
+    D3DSTATE_TO_STR(D3DRS_DITHERENABLE              );
+    D3DSTATE_TO_STR(D3DRS_ALPHABLENDENABLE          );
+    D3DSTATE_TO_STR(D3DRS_FOGENABLE                 );
+    D3DSTATE_TO_STR(D3DRS_SPECULARENABLE            );
+    D3DSTATE_TO_STR(D3DRS_ZVISIBLE                  );
+    D3DSTATE_TO_STR(D3DRS_FOGCOLOR                  );
+    D3DSTATE_TO_STR(D3DRS_FOGTABLEMODE              );
+    D3DSTATE_TO_STR(D3DRS_FOGSTART                  );
+    D3DSTATE_TO_STR(D3DRS_FOGEND                    );
+    D3DSTATE_TO_STR(D3DRS_FOGDENSITY                );
+    D3DSTATE_TO_STR(D3DRS_EDGEANTIALIAS             );
+    D3DSTATE_TO_STR(D3DRS_ZBIAS                     );
+    D3DSTATE_TO_STR(D3DRS_RANGEFOGENABLE            );
+    D3DSTATE_TO_STR(D3DRS_STENCILENABLE             );
+    D3DSTATE_TO_STR(D3DRS_STENCILFAIL               );
+    D3DSTATE_TO_STR(D3DRS_STENCILZFAIL              );
+    D3DSTATE_TO_STR(D3DRS_STENCILPASS               );
+    D3DSTATE_TO_STR(D3DRS_STENCILFUNC               );
+    D3DSTATE_TO_STR(D3DRS_STENCILREF                );
+    D3DSTATE_TO_STR(D3DRS_STENCILMASK               );
+    D3DSTATE_TO_STR(D3DRS_STENCILWRITEMASK          );
+    D3DSTATE_TO_STR(D3DRS_TEXTUREFACTOR             );
+    D3DSTATE_TO_STR(D3DRS_WRAP0                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP1                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP2                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP3                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP4                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP5                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP6                     );
+    D3DSTATE_TO_STR(D3DRS_WRAP7                     );
+    D3DSTATE_TO_STR(D3DRS_CLIPPING                  );
+    D3DSTATE_TO_STR(D3DRS_LIGHTING                  );
+    D3DSTATE_TO_STR(D3DRS_AMBIENT                   );
+    D3DSTATE_TO_STR(D3DRS_FOGVERTEXMODE             );
+    D3DSTATE_TO_STR(D3DRS_COLORVERTEX               );
+    D3DSTATE_TO_STR(D3DRS_LOCALVIEWER               );
+    D3DSTATE_TO_STR(D3DRS_NORMALIZENORMALS          );
+    D3DSTATE_TO_STR(D3DRS_DIFFUSEMATERIALSOURCE     );
+    D3DSTATE_TO_STR(D3DRS_SPECULARMATERIALSOURCE    );
+    D3DSTATE_TO_STR(D3DRS_AMBIENTMATERIALSOURCE     );
+    D3DSTATE_TO_STR(D3DRS_EMISSIVEMATERIALSOURCE    );
+    D3DSTATE_TO_STR(D3DRS_VERTEXBLEND               );
+    D3DSTATE_TO_STR(D3DRS_CLIPPLANEENABLE           );
+    D3DSTATE_TO_STR(D3DRS_SOFTWAREVERTEXPROCESSING  );
+    D3DSTATE_TO_STR(D3DRS_POINTSIZE                 );
+    D3DSTATE_TO_STR(D3DRS_POINTSIZE_MIN             );
+    D3DSTATE_TO_STR(D3DRS_POINTSPRITEENABLE         );
+    D3DSTATE_TO_STR(D3DRS_POINTSCALEENABLE          );
+    D3DSTATE_TO_STR(D3DRS_POINTSCALE_A              );
+    D3DSTATE_TO_STR(D3DRS_POINTSCALE_B              );
+    D3DSTATE_TO_STR(D3DRS_POINTSCALE_C              );
+    D3DSTATE_TO_STR(D3DRS_MULTISAMPLEANTIALIAS      );
+    D3DSTATE_TO_STR(D3DRS_MULTISAMPLEMASK           );
+    D3DSTATE_TO_STR(D3DRS_PATCHEDGESTYLE            );
+    D3DSTATE_TO_STR(D3DRS_PATCHSEGMENTS             );
+    D3DSTATE_TO_STR(D3DRS_DEBUGMONITORTOKEN         );
+    D3DSTATE_TO_STR(D3DRS_POINTSIZE_MAX             );
+    D3DSTATE_TO_STR(D3DRS_INDEXEDVERTEXBLENDENABLE  );
+    D3DSTATE_TO_STR(D3DRS_COLORWRITEENABLE          );
+    D3DSTATE_TO_STR(D3DRS_TWEENFACTOR               );
+    D3DSTATE_TO_STR(D3DRS_BLENDOP                   );
+    D3DSTATE_TO_STR(D3DRS_POSITIONORDER             );
+    D3DSTATE_TO_STR(D3DRS_NORMALORDER               );
+#undef D3DSTATE_TO_STR
+  default:
+    FIXME("Unrecognized %lu render state!\n", state);
+    return "unrecognized";
+  }
+}
+
+const char* debug_d3dtexturestate(DWORD state) {
+  switch (state) {
+#define D3DSTATE_TO_STR(u) case u: return #u
+    D3DSTATE_TO_STR(D3DTSS_COLOROP               );
+    D3DSTATE_TO_STR(D3DTSS_COLORARG1             );
+    D3DSTATE_TO_STR(D3DTSS_COLORARG2             );
+    D3DSTATE_TO_STR(D3DTSS_ALPHAOP               );
+    D3DSTATE_TO_STR(D3DTSS_ALPHAARG1             );
+    D3DSTATE_TO_STR(D3DTSS_ALPHAARG2             );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVMAT00          );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVMAT01          );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVMAT10          );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVMAT11          );
+    D3DSTATE_TO_STR(D3DTSS_TEXCOORDINDEX         );
+    D3DSTATE_TO_STR(D3DTSS_ADDRESSU              );
+    D3DSTATE_TO_STR(D3DTSS_ADDRESSV              );
+    D3DSTATE_TO_STR(D3DTSS_BORDERCOLOR           );
+    D3DSTATE_TO_STR(D3DTSS_MAGFILTER             );
+    D3DSTATE_TO_STR(D3DTSS_MINFILTER             );
+    D3DSTATE_TO_STR(D3DTSS_MIPFILTER             );
+    D3DSTATE_TO_STR(D3DTSS_MIPMAPLODBIAS         );
+    D3DSTATE_TO_STR(D3DTSS_MAXMIPLEVEL           );
+    D3DSTATE_TO_STR(D3DTSS_MAXANISOTROPY         );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVLSCALE         );
+    D3DSTATE_TO_STR(D3DTSS_BUMPENVLOFFSET        );
+    D3DSTATE_TO_STR(D3DTSS_TEXTURETRANSFORMFLAGS );
+    D3DSTATE_TO_STR(D3DTSS_ADDRESSW              );
+    D3DSTATE_TO_STR(D3DTSS_COLORARG0             );
+    D3DSTATE_TO_STR(D3DTSS_ALPHAARG0             );
+    D3DSTATE_TO_STR(D3DTSS_RESULTARG             );
+#undef D3DSTATE_TO_STR
+  case 12:
+    /* Note D3DTSS are not consecutive, so skip these */
+    return "unused";
+    break;
+  default:
+    FIXME("Unrecognized %lu texture state!\n", state);
+    return "unrecognized";
+  }
+}
+
+/*****************************************************************************
+ * Useful functions mapping GL <-> D3D values
+ */
+GLenum StencilOp(DWORD op) {
+    switch(op) {                
+    case D3DSTENCILOP_KEEP    : return GL_KEEP;
+    case D3DSTENCILOP_ZERO    : return GL_ZERO;
+    case D3DSTENCILOP_REPLACE : return GL_REPLACE;
+    case D3DSTENCILOP_INCRSAT : return GL_INCR;
+    case D3DSTENCILOP_DECRSAT : return GL_DECR;
+    case D3DSTENCILOP_INVERT  : return GL_INVERT; 
+    case D3DSTENCILOP_INCR    : return GL_INCR_WRAP_EXT;
+    case D3DSTENCILOP_DECR    : return GL_DECR_WRAP_EXT;
+    default:
+        FIXME("Invalid stencil op %ld\n", op);
+        return GL_ALWAYS;
+    }
+}
+
+/* Set texture operations up - The following avoids lots of ifdefs in this routine!*/
+#if defined (GL_VERSION_1_3)
+# define useext(A) A
+# define combine_ext 1
+#elif defined (GL_EXT_texture_env_combine)
+# define useext(A) A##_EXT
+# define combine_ext 1
+#elif defined (GL_ARB_texture_env_combine)
+# define useext(A) A##_ARB
+# define combine_ext 1
+#else
+# undef combine_ext
+#endif
+
+#if !defined(combine_ext)
+void set_tex_op(LPDIRECT3DDEVICE8 iface, BOOL isAlpha, int Stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3)
+{ 
+        FIXME("Requires opengl combine extensions to work\n");
+        return;
+}
+#else
+/* Setup the texture operations texture stage states */
+void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3)
+{
+        #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
+        GLenum src1, src2, src3;
+        GLenum opr1, opr2, opr3;
+        GLenum comb_target;
+        GLenum src0_target, src1_target, src2_target;
+        GLenum opr0_target, opr1_target, opr2_target;
+        GLenum scal_target;
+        GLenum opr=0, invopr, src3_target, opr3_target;
+        BOOL Handled = FALSE;
+        IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+
+        TRACE("Alpha?(%d), Stage:%d Op(%d), a1(%ld), a2(%ld), a3(%ld)\n", isAlpha, Stage, op, arg1, arg2, arg3);
+
+        ENTER_GL();
+
+        /* Note: Operations usually involve two ars, src0 and src1 and are operations of
+           the form (a1 <operation> a2). However, some of the more complex operations
+           take 3 parameters. Instead of the (sensible) addition of a3, Microsoft added  
+           in a third parameter called a0. Therefore these are operations of the form
+           a0 <operation> a1 <operation> a2, ie the new parameter goes to the front.
+           
+           However, below we treat the new (a0) parameter as src2/opr2, so in the actual
+           functions below, expect their syntax to differ slightly to those listed in the
+           manuals, ie replace arg1 with arg3, arg2 with arg1 and arg3 with arg2
+           This affects D3DTOP_MULTIPLYADD and D3DTOP_LERP                               */
+           
+        if (isAlpha) {
+                comb_target = useext(GL_COMBINE_ALPHA);
+                src0_target = useext(GL_SOURCE0_ALPHA);
+                src1_target = useext(GL_SOURCE1_ALPHA);
+                src2_target = useext(GL_SOURCE2_ALPHA);
+                opr0_target = useext(GL_OPERAND0_ALPHA);
+                opr1_target = useext(GL_OPERAND1_ALPHA);
+                opr2_target = useext(GL_OPERAND2_ALPHA);
+                scal_target = GL_ALPHA_SCALE;
+        }
+        else {
+                comb_target = useext(GL_COMBINE_RGB);
+                src0_target = useext(GL_SOURCE0_RGB);
+                src1_target = useext(GL_SOURCE1_RGB);
+                src2_target = useext(GL_SOURCE2_RGB);
+                opr0_target = useext(GL_OPERAND0_RGB);
+                opr1_target = useext(GL_OPERAND1_RGB);
+                opr2_target = useext(GL_OPERAND2_RGB);
+                scal_target = useext(GL_RGB_SCALE);
+        }
+
+        /* From MSDN (D3DTSS_ALPHAARG1) : 
+           The default argument is D3DTA_TEXTURE. If no texture is set for this stage, 
+                   then the default argument is D3DTA_DIFFUSE.
+                   FIXME? If texture added/removed, may need to reset back as well?    */
+        if (isAlpha && This->stateBlock->textures[Stage] == NULL && arg1 == D3DTA_TEXTURE) {
+            GetSrcAndOpFromValue(D3DTA_DIFFUSE, isAlpha, &src1, &opr1);  
+        } else {
+            GetSrcAndOpFromValue(arg1, isAlpha, &src1, &opr1);
+        }
+        GetSrcAndOpFromValue(arg2, isAlpha, &src2, &opr2);
+        GetSrcAndOpFromValue(arg3, isAlpha, &src3, &opr3);
+        
+        TRACE("ct(%x), 1:(%x,%x), 2:(%x,%x), 3:(%x,%x)\n", comb_target, src1, opr1, src2, opr2, src3, opr3);
+
+        Handled = TRUE; /* Assume will be handled */
+
+        /* Other texture operations require special extensions: */
+        if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
+          if (isAlpha) {
+            opr = GL_SRC_ALPHA;
+            invopr = GL_ONE_MINUS_SRC_ALPHA;
+            src3_target = GL_SOURCE3_ALPHA_NV;
+            opr3_target = GL_OPERAND3_ALPHA_NV;
+          } else {
+            opr = GL_SRC_COLOR;
+            invopr = GL_ONE_MINUS_SRC_COLOR;
+            src3_target = GL_SOURCE3_RGB_NV;
+            opr3_target = GL_OPERAND3_RGB_NV;
+          }
+          switch (op) {
+          case D3DTOP_DISABLE: /* Only for alpha */
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);    
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);              
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO);             
+            checkGLcall("GL_TEXTURE_ENV, src2_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr");  
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);             
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr");  
+            break;
+          case D3DTOP_SELECTARG1:                                          /* = a1 * 1 + 0 * 0 */
+          case D3DTOP_SELECTARG2:                                          /* = a2 * 1 + 0 * 0 */
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            if (op == D3DTOP_SELECTARG1) {
+              glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);                
+              checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+              glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);        
+              checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");  
+            } else {
+              glTexEnvi(GL_TEXTURE_ENV, src0_target, src2);                
+              checkGLcall("GL_TEXTURE_ENV, src0_target, src2");
+              glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr2);        
+              checkGLcall("GL_TEXTURE_ENV, opr0_target, opr2");  
+            }
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);             
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);              
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO);             
+            checkGLcall("GL_TEXTURE_ENV, src2_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr");  
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);             
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr");  
+            break;
+            
+          case D3DTOP_MODULATE:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);    
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);      
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); 
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MODULATE2X:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);    
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);      
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); 
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 2);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 2");
+            break;
+          case D3DTOP_MODULATE4X:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);    
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);      
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); 
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 4);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 4");
+            break;
+
+          case D3DTOP_ADD:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+
+          case D3DTOP_ADDSIGNED:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED));
+            checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+
+          case D3DTOP_ADDSIGNED2X:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED));
+            checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 2);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 2");
+            break;
+
+          case D3DTOP_ADDSMOOTH:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, src1");
+            switch (opr1) {
+            case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break;
+            case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+
+          case D3DTOP_BLENDDIFFUSEALPHA:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, useext(GL_PRIMARY_COLOR));
+            checkGLcall("GL_TEXTURE_ENV, src1_target, useext(GL_PRIMARY_COLOR)");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, useext(GL_PRIMARY_COLOR));
+            checkGLcall("GL_TEXTURE_ENV, src3_target, useext(GL_PRIMARY_COLOR)");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_BLENDTEXTUREALPHA:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_TEXTURE);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_TEXTURE");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_TEXTURE);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_TEXTURE");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_BLENDFACTORALPHA:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, useext(GL_CONSTANT));
+            checkGLcall("GL_TEXTURE_ENV, src1_target, useext(GL_CONSTANT)");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, useext(GL_CONSTANT));
+            checkGLcall("GL_TEXTURE_ENV, src3_target, useext(GL_CONSTANT)");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_BLENDTEXTUREALPHAPM:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_TEXTURE);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_TEXTURE");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MODULATEALPHA_ADDCOLOR:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");  /* Add = a0*a1 + a2*a3 */
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);        /*   a0 = src1/opr1    */
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");    /*   a1 = 1 (see docs) */
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);      
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");  
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);        /*   a2 = arg2         */
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");     /*  a3 = src1 alpha   */
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, src1");
+            switch (opr) {
+            case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MODULATECOLOR_ADDALPHA:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src1");
+            switch (opr1) {
+            case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, src1");
+            switch (opr1) {
+            case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+            case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            switch (opr1) {
+            case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break;
+            case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src1");
+            switch (opr1) {
+            case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+            case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+            }
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+          case D3DTOP_MULTIPLYADD:
+            glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+            checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+            glTexEnvi(GL_TEXTURE_ENV, src0_target, src3);
+            checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+            glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr3);
+            checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+            glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO);
+            checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO");
+            glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr);
+            checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr");
+            glTexEnvi(GL_TEXTURE_ENV, src2_target, src1);
+            checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+            glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr1);
+            checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+            glTexEnvi(GL_TEXTURE_ENV, src3_target, src2);
+            checkGLcall("GL_TEXTURE_ENV, src3_target, src3");
+            glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr2);
+            checkGLcall("GL_TEXTURE_ENV, opr3_target, opr3");
+            glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+            checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+            break;
+            
+          case D3DTOP_BUMPENVMAP:
+            {
+              if (GL_SUPPORT(NV_TEXTURE_SHADER)) {
+                /*
+                  texture unit 0: GL_TEXTURE_2D
+                  texture unit 1: GL_DOT_PRODUCT_NV
+                  texture unit 2: GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV
+                  texture unit 3: GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV
+                */
+                float m[2][2];
+                
+                union {
+                  float f;
+                  DWORD d;
+                } tmpvalue;
+                
+                tmpvalue.d = This->stateBlock->textureState[Stage][D3DTSS_BUMPENVMAT00];
+                m[0][0] = tmpvalue.f;
+                tmpvalue.d = This->stateBlock->textureState[Stage][D3DTSS_BUMPENVMAT01];
+                m[0][1] = tmpvalue.f;
+                tmpvalue.d = This->stateBlock->textureState[Stage][D3DTSS_BUMPENVMAT10];
+                m[1][0] = tmpvalue.f;
+                tmpvalue.d = This->stateBlock->textureState[Stage][D3DTSS_BUMPENVMAT11];
+                m[1][1] = tmpvalue.f;
+                
+                /*FIXME("Stage %d matrix is (%.2f,%.2f),(%.2f,%.2f)\n", Stage, m[0][0], m[0][1], m[1][0], m[1][0]);*/
+
+                if (FALSE == This->texture_shader_active) {
+                  This->texture_shader_active = TRUE;
+                  glEnable(GL_TEXTURE_SHADER_NV);
+                }
+
+                /*
+                glEnable(GL_REGISTER_COMBINERS_NV);
+                glCombinerParameteriNV (GL_NUM_GENERAL_COMBINERS_NV, 1);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_SIGNED_IDENTITY_NV, GL_RGB);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_NONE, GL_UNSIGNED_INVERT_NV, GL_RGB);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE2_ARB, GL_SIGNED_IDENTITY_NV, GL_RGB);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_NONE, GL_UNSIGNED_INVERT_NV, GL_RGB);
+                glCombinerOutputNV (GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_PRIMARY_COLOR_NV, 0, 0, 0, 0, 0);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_SIGNED_IDENTITY_NV, GL_ALPHA);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_NONE, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_TEXTURE2_ARB, GL_SIGNED_IDENTITY_NV, GL_ALPHA);
+                glCombinerInputNV (GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_NONE, GL_UNSIGNED_INVERT_NV, GL_ALPHA);
+                glCombinerOutputNV (GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_PRIMARY_COLOR_NV, 0, 0, 0, 0, 0);
+                glDisable (GL_PER_STAGE_CONSTANTS_NV);
+                glCombinerParameteriNV (GL_COLOR_SUM_CLAMP_NV, 0);
+                glFinalCombinerInputNV (GL_VARIABLE_A_NV, 0, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_B_NV, 0, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_C_NV, 0, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_D_NV, GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_E_NV, 0, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_F_NV, 0, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
+                glFinalCombinerInputNV (GL_VARIABLE_G_NV, GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
+                */
+                /*
+                int i;
+                for (i = 0; i < Stage; i++) {
+                  if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+                    GL_ACTIVETEXTURE(i);
+                    glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
+                    checkGLcall("Activate texture..");
+                  } else if (i>0) {
+                    FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
+                  }
+                }
+                */
+                /*
+                  GL_ACTIVETEXTURE(Stage - 1);
+                  glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
+                */
+                /*
+                GL_ACTIVETEXTURE(Stage);
+                checkGLcall("Activate texture.. to update const color");
+                glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
+                checkGLcall("glTexEnv");
+                glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + Stage - 1);
+                checkGLcall("glTexEnv");
+                glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, (float*)&m[0]);
+                checkGLcall("glTexEnv");
+                */
+                LEAVE_GL();
+                return;
+                break;            
+              }
+            }
+
+          case D3DTOP_BUMPENVMAPLUMINANCE:
+
+          default:
+            Handled = FALSE;
+          }
+          if (Handled) {
+            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV);
+            checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV");
+            
+            LEAVE_GL();
+            return;
+          }
+        } /* GL_NV_texture_env_combine4 */
+        
+        Handled = TRUE; /* Again, assume handled */
+        switch (op) {
+        case D3DTOP_DISABLE: /* Only for alpha */
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_SELECTARG1:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_SELECTARG2:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_MODULATE:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_MODULATE2X:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 2);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 2");
+                break;
+        case D3DTOP_MODULATE4X:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 4);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 4");
+                break;
+        case D3DTOP_ADD:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_ADDSIGNED:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext((GL_ADD_SIGNED)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_ADDSIGNED2X:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 2);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 2");
+                break;
+        case D3DTOP_SUBTRACT:
+          if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE)) {
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_SUBTRACT);
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_SUBTRACT)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+          } else {
+                FIXME("This version of opengl does not support GL_SUBTRACT\n");
+          }
+          break;
+
+        case D3DTOP_BLENDDIFFUSEALPHA:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_PRIMARY_COLOR));
+                checkGLcall("GL_TEXTURE_ENV, src2_target, GL_PRIMARY_COLOR");
+                glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA);
+                checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_BLENDTEXTUREALPHA:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_TEXTURE);
+                checkGLcall("GL_TEXTURE_ENV, src2_target, GL_TEXTURE");
+                glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA);
+                checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_BLENDFACTORALPHA:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_CONSTANT));
+                checkGLcall("GL_TEXTURE_ENV, src2_target, GL_CONSTANT");
+                glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA);
+                checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_BLENDCURRENTALPHA:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_PREVIOUS));
+                checkGLcall("GL_TEXTURE_ENV, src2_target, GL_PREVIOUS");
+                glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA);
+                checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_DOTPRODUCT3: 
+                if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_ARB);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_ARB");
+                } else if (GL_SUPPORT(EXT_TEXTURE_ENV_DOT3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_EXT);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_EXT");
+                } else {
+                  FIXME("This version of opengl does not support GL_DOT3\n");
+                }
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_LERP:
+                glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE));
+                checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)");
+                glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                glTexEnvi(GL_TEXTURE_ENV, src1_target, src2);
+                checkGLcall("GL_TEXTURE_ENV, src1_target, src2");
+                glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2);
+                checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2");
+                glTexEnvi(GL_TEXTURE_ENV, src2_target, src3);
+                checkGLcall("GL_TEXTURE_ENV, src2_target, src3");
+                glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr3);
+                checkGLcall("GL_TEXTURE_ENV, opr2_target, opr3");
+                glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                break;
+        case D3DTOP_ADDSMOOTH:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break;
+                  case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_BLENDTEXTUREALPHAPM:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_TEXTURE);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, GL_TEXTURE");
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_ONE_MINUS_SRC_ALPHA);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, GL_ONE_MINUS_SRC_APHA");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_MODULATEALPHA_ADDCOLOR:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_MODULATECOLOR_ADDALPHA:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+                  case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break;
+                  case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  switch (opr1) {
+                  case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break;
+                  case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break;
+                  }
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        case D3DTOP_MULTIPLYADD:
+                if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) {
+                  glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI);
+                  checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI");
+                  glTexEnvi(GL_TEXTURE_ENV, src0_target, src3);
+                  checkGLcall("GL_TEXTURE_ENV, src0_target, src3");
+                  glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr3);
+                  checkGLcall("GL_TEXTURE_ENV, opr0_target, opr3");
+                  glTexEnvi(GL_TEXTURE_ENV, src1_target, src1);
+                  checkGLcall("GL_TEXTURE_ENV, src1_target, src1");
+                  glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1);
+                  checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1");
+                  glTexEnvi(GL_TEXTURE_ENV, src2_target, src2);
+                  checkGLcall("GL_TEXTURE_ENV, src2_target, src2");
+                  glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2);
+                  checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2");
+                  glTexEnvi(GL_TEXTURE_ENV, scal_target, 1);
+                  checkGLcall("GL_TEXTURE_ENV, scal_target, 1");
+                } else
+                  Handled = FALSE;
+                break;
+        default:
+                Handled = FALSE;
+        }
+
+        if (Handled) {
+          BOOL  combineOK = TRUE;
+          if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) {
+            DWORD op2;
+            
+            if (isAlpha) {
+              op2 = This->stateBlock->textureState[Stage][D3DTSS_COLOROP];
+            } else {
+              op2 = This->stateBlock->textureState[Stage][D3DTSS_ALPHAOP];
+            }
+            
+            /* Note: If COMBINE4 in effect can't go back to combine! */
+            switch (op2) {
+            case D3DTOP_ADDSMOOTH:
+            case D3DTOP_BLENDTEXTUREALPHAPM:
+            case D3DTOP_MODULATEALPHA_ADDCOLOR:
+            case D3DTOP_MODULATECOLOR_ADDALPHA:
+            case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+            case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+            case D3DTOP_MULTIPLYADD:
+              /* Ignore those implemented in both cases */
+              switch (op) {
+              case D3DTOP_SELECTARG1:
+              case D3DTOP_SELECTARG2:
+                combineOK = FALSE;
+                Handled   = FALSE;
+                break;
+              default:
+                FIXME("Can't use COMBINE4 and COMBINE together, thisop=%d, otherop=%ld, isAlpha(%d)\n", op, op2, isAlpha);
+                LEAVE_GL();
+                return;
+              }
+            }
+          }
+          
+          if (combineOK) {
+            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE));
+            checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE)");
+            
+            LEAVE_GL();
+            return;
+          }
+        }
+
+        LEAVE_GL();
+        
+        /* After all the extensions, if still unhandled, report fixme */
+        FIXME("Unhandled texture operation %d\n", op);
+        #undef GLINFO_LOCATION 
+}
+#endif
+
+/* Setup this textures matrix according to the texture flags*/
+void set_texture_matrix(const float *smat, DWORD flags)
+{
+    float mat[16];
+
+    glMatrixMode(GL_TEXTURE);
+
+    if (flags == D3DTTFF_DISABLE) {
+        glLoadIdentity();
+        checkGLcall("glLoadIdentity()");
+        return;
+    }
+
+    if (flags == (D3DTTFF_COUNT1|D3DTTFF_PROJECTED)) {
+        ERR("Invalid texture transform flags: D3DTTFF_COUNT1|D3DTTFF_PROJECTED\n");
+        checkGLcall("glLoadIdentity()");
+        return;
+    }
+
+    memcpy(mat, smat, 16*sizeof(float));
+
+    switch (flags & ~D3DTTFF_PROJECTED) {
+    case D3DTTFF_COUNT1: mat[1] = mat[5] = mat[9] = mat[13] = 0;
+    case D3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0;
+    default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1;
+    }
+    
+    if (flags & D3DTTFF_PROJECTED) switch (flags & ~D3DTTFF_PROJECTED) {
+    case D3DTTFF_COUNT2:
+        mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13];
+        mat[1] = mat[5] = mat[9] = mat[13] = 0;
+        break;
+    case D3DTTFF_COUNT3:
+        mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14];
+        mat[2] = mat[6] = mat[10] = mat[14] = 0;
+        break;
+    }
+    glLoadMatrixf(mat);
+    checkGLcall("glLoadMatrixf(mat)");
+}
+
+void GetSrcAndOpFromValue(DWORD iValue, BOOL isAlphaArg, GLenum* source, GLenum* operand) 
+{
+  BOOL isAlphaReplicate = FALSE;
+  BOOL isComplement     = FALSE;
+  
+  *operand = GL_SRC_COLOR;
+  *source = GL_TEXTURE;
+  
+  /* Catch alpha replicate */
+  if (iValue & D3DTA_ALPHAREPLICATE) {
+    iValue = iValue & ~D3DTA_ALPHAREPLICATE;
+    isAlphaReplicate = TRUE;
+  }
+  
+  /* Catch Complement */
+  if (iValue & D3DTA_COMPLEMENT) {
+    iValue = iValue & ~D3DTA_COMPLEMENT;
+    isComplement = TRUE;
+  }
+  
+  /* Calculate the operand */
+  if (isAlphaReplicate && !isComplement) {
+    *operand = GL_SRC_ALPHA;
+  } else if (isAlphaReplicate && isComplement) {
+    *operand = GL_ONE_MINUS_SRC_ALPHA;
+  } else if (isComplement) {
+    if (isAlphaArg) {
+      *operand = GL_ONE_MINUS_SRC_ALPHA;
+    } else {
+      *operand = GL_ONE_MINUS_SRC_COLOR;
+    }
+  } else {
+    if (isAlphaArg) {
+      *operand = GL_SRC_ALPHA;
+    } else {
+      *operand = GL_SRC_COLOR;
+    }
+  }
+  
+  /* Calculate the source */
+  switch (iValue & D3DTA_SELECTMASK) {
+  case D3DTA_CURRENT:   *source  = GL_PREVIOUS_EXT;
+    break;
+  case D3DTA_DIFFUSE:   *source  = GL_PRIMARY_COLOR_EXT;
+    break;
+  case D3DTA_TEXTURE:   *source  = GL_TEXTURE;
+    break;
+  case D3DTA_TFACTOR:   *source  = GL_CONSTANT_EXT;
+    break;
+  case D3DTA_SPECULAR:
+    /*
+     * According to the GL_ARB_texture_env_combine specs, SPECULAR is
+     * 'Secondary color' and isn't supported until base GL supports it
+     * There is no concept of temp registers as far as I can tell
+     */
+    FIXME("Unhandled texture arg D3DTA_SPECULAR\n");
+    *source = GL_TEXTURE;
+    break;
+
+  default:
+    FIXME("Unrecognized texture arg %ld\n", iValue);
+    *source = GL_TEXTURE;
+  }
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 75a470c..f6f4fcb 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -69,18 +69,51 @@
 /*****************************************************************************
  * Defines
  */
+
+/* GL related defines */
+/* ------------------ */
 #define GL_SUPPORT(ExtName)           (GLINFO_LOCATION.supported[ExtName] != 0)
 #define GL_LIMITS(ExtName)            (GLINFO_LOCATION.max_##ExtName)
 #define GL_EXTCALL(FuncName)          (GLINFO_LOCATION.FuncName)
 
+#define D3DCOLOR_R(dw) (((float) (((dw) >> 16) & 0xFF)) / 255.0f)
+#define D3DCOLOR_G(dw) (((float) (((dw) >>  8) & 0xFF)) / 255.0f)
+#define D3DCOLOR_B(dw) (((float) (((dw) >>  0) & 0xFF)) / 255.0f)
+#define D3DCOLOR_A(dw) (((float) (((dw) >> 24) & 0xFF)) / 255.0f)
+
+#define D3DCOLORTOGLFLOAT4(dw, vec) \
+  (vec)[0] = D3DCOLOR_R(dw); \
+  (vec)[1] = D3DCOLOR_G(dw); \
+  (vec)[2] = D3DCOLOR_B(dw); \
+  (vec)[3] = D3DCOLOR_A(dw);
+  
+/* Note: The following is purely to keep the source code as clear from #ifdefs as possible */
+#if defined(GL_VERSION_1_3)
+#define GL_ACTIVETEXTURE(textureNo)                          \
+            glActiveTexture(GL_TEXTURE0 + textureNo);        \
+            checkGLcall("glActiveTexture");      
+#else 
+#define GL_ACTIVETEXTURE(textureNo)                          \
+            glActiveTextureARB(GL_TEXTURE0_ARB + textureNo); \
+            checkGLcall("glActiveTextureARB");
+#endif
+
+/* DirectX Device Limits */
+/* --------------------- */
 #define MAX_STREAMS  16  /* Maximum possible streams - used for fixed size arrays
                             See MaxStreams in MSDN under GetDeviceCaps */
 #define HIGHEST_TRANSFORMSTATE 512 
                          /* Highest value in D3DTRANSFORMSTATETYPE */
+#define HIGHEST_RENDER_STATE   209
+                         /* Highest D3DRS_ value                   */
+#define HIGHEST_TEXTURE_STATE   32
+                         /* Highest D3DTSS_ value                  */
 #define WINED3D_VSHADER_MAX_CONSTANTS  96   
                          /* Maximum number of constants provided to the shaders */
 #define MAX_CLIPPLANES  D3DMAXUSERCLIPPLANES
 
+/* Checking of API calls */
+/* --------------------- */
 #define checkGLcall(A) \
 { \
     GLint err = glGetError();   \
@@ -91,6 +124,10 @@
     } \
 }
 
+/* Trace routines / diagnostics */
+/* ---------------------------- */
+
+/* Dump out a matrix and copy it */
 #define conv_mat(mat,gl_mat)                                                                \
 do {                                                                                        \
     TRACE("%f %f %f %f\n", (mat)->u.s._11, (mat)->u.s._12, (mat)->u.s._13, (mat)->u.s._14); \
@@ -100,17 +137,6 @@
     memcpy(gl_mat, (mat), 16 * sizeof(float));                                              \
 } while (0)
 
-/* The following is purely to keep the source code as clear from #ifdefs as possible */
-#if defined(GL_VERSION_1_3)
-#define GL_ACTIVETEXTURE(textureNo)                          \
-            glActiveTexture(GL_TEXTURE0 + textureNo);        \
-            checkGLcall("glActiveTexture");      
-#else 
-#define GL_ACTIVETEXTURE(textureNo)                          \
-            glActiveTextureARB(GL_TEXTURE0_ARB + textureNo); \
-            checkGLcall("glActiveTextureARB");
-#endif
-
 /* Macro to dump out the current state of the light chain */
 #define DUMP_LIGHT_CHAIN()                    \
 {                                             \
@@ -121,11 +147,20 @@
   }                                           \
 }
 
+/* Trace vector and strided data information */
 #define TRACE_VECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w);
 #define TRACE_STRIDED(sd,name) TRACE( #name "=(data:%p, stride:%ld, type:%ld)\n", sd->u.s.name.lpData, sd->u.s.name.dwStride, sd->u.s.name.dwType);
 
+/* Defines used for optimizations */
+
+/*    Only reapply what is necessary */
+#define REAPPLY_ALPHAOP  0x0001
+#define REAPPLY_ALL      0xFFFF
+
+/* Advance declaration of structures to satisfy compiler */
 typedef struct IWineD3DStateBlockImpl IWineD3DStateBlockImpl;
 
+/* Global variables */
 extern const float identity[16];
 
 /*****************************************************************************
@@ -268,6 +303,11 @@
       #define                         IS_TRACKING        1  /* tracking_parm is tracking diffuse color  */
       #define                         NEEDS_TRACKING     2  /* Tracking needs to be enabled when needed */
       #define                         NEEDS_DISABLE      3  /* Tracking needs to be disabled when needed*/
+    UINT                    srcBlend;
+    UINT                    dstBlend;
+    UINT                    alphafunc;
+    UINT                    stencilfunc;
+    BOOL                    texture_shader_active;  /* TODO: Confirm use is correct */
 
     /* State block related */
     BOOL                    isRecordingState;
@@ -283,6 +323,9 @@
     /* For rendering to a texture using glCopyTexImage */
     BOOL                          renderUpsideDown;
 
+    /* Textures for when no other textures are mapped */
+    UINT                          dummyTextureName[8];
+
 } IWineD3DDeviceImpl;
 
 extern IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
@@ -380,6 +423,8 @@
         BOOL                      textures[8];
         BOOL                      transform[HIGHEST_TRANSFORMSTATE];
         BOOL                      viewport;
+        BOOL                      renderState[HIGHEST_RENDER_STATE];
+        BOOL                      textureState[8][HIGHEST_TEXTURE_STATE];
         BOOL                      clipplane[MAX_CLIPPLANES];
 } SAVEDSTATES;
 
@@ -428,9 +473,20 @@
     /* Material */
     WINED3DMATERIAL           material;
 
+    /* Indexed Vertex Blending */
+    D3DVERTEXBLENDFLAGS       vertex_blend;
+    FLOAT                     tween_factor;
+
+    /* RenderState */
+    DWORD                     renderState[HIGHEST_RENDER_STATE];
+
     /* Texture */
     IWineD3DBaseTexture      *textures[8];
     int                       textureDimensions[8];
+
+    /* Texture State Stage */
+    DWORD                     textureState[8][HIGHEST_TEXTURE_STATE];
+
 };
 
 extern IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl;
@@ -438,11 +494,21 @@
 /*****************************************************************************
  * Utility function prototypes 
  */
+
+/* Trace routines */
 const char* debug_d3dformat(D3DFORMAT fmt);
 const char* debug_d3ddevicetype(D3DDEVTYPE devtype);
 const char* debug_d3dresourcetype(D3DRESOURCETYPE res);
 const char* debug_d3dusage(DWORD usage);
 const char* debug_d3dprimitivetype(D3DPRIMITIVETYPE PrimitiveType);
+const char* debug_d3drenderstate(DWORD state);
+const char* debug_d3dtexturestate(DWORD state);
+
+/* Routines for GL <-> D3D values */
+GLenum StencilOp(DWORD op);
+void   set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3);
+void   set_texture_matrix(const float *smat, DWORD flags);
+void   GetSrcAndOpFromValue(DWORD iValue, BOOL isAlphaArg, GLenum* source, GLenum* operand);
 
 #if 0 /* Needs fixing during rework */
 /*****************************************************************************
diff --git a/include/wine/wined3d_interface.h b/include/wine/wined3d_interface.h
index c8e11df..073c7b2 100644
--- a/include/wine/wined3d_interface.h
+++ b/include/wine/wined3d_interface.h
@@ -182,11 +182,19 @@
     STDMETHOD(GetIndices)(THIS_ IWineD3DIndexBuffer ** ppIndexData,UINT * pBaseVertexIndex) PURE;
     STDMETHOD(SetViewport)(THIS_ CONST WINED3DVIEWPORT * pViewport) PURE;
     STDMETHOD(GetViewport)(THIS_ WINED3DVIEWPORT * pViewport) PURE;
+    STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE  State,DWORD  Value) PURE;
+    STDMETHOD(GetRenderState)(THIS_ D3DRENDERSTATETYPE  State,DWORD * pValue) PURE;
+    STDMETHOD(SetTextureStageState)(THIS_ DWORD  Stage,D3DTEXTURESTAGESTATETYPE  Type,DWORD  Value) PURE;
+    STDMETHOD(GetTextureStageState)(THIS_ DWORD  Stage,D3DTEXTURESTAGESTATETYPE  Type,DWORD * pValue) PURE;
     STDMETHOD(BeginScene)(THIS) PURE;
     STDMETHOD(DrawPrimitive)(THIS_ D3DPRIMITIVETYPE  PrimitiveType,UINT  StartVertex,UINT  PrimitiveCount) PURE;
     STDMETHOD(DrawIndexedPrimitive)(THIS_ D3DPRIMITIVETYPE  PrimitiveType,INT baseVIdx, UINT  minIndex,UINT  NumVertices,UINT  startIndex,UINT  primCount) PURE;
     STDMETHOD(DrawPrimitiveUP)(THIS_ D3DPRIMITIVETYPE  PrimitiveType,UINT  PrimitiveCount,CONST void * pVertexStreamZeroData,UINT  VertexStreamZeroStride) PURE;
     STDMETHOD(DrawIndexedPrimitiveUP)(THIS_ D3DPRIMITIVETYPE  PrimitiveType,UINT  MinVertexIndex,UINT  NumVertexIndices,UINT  PrimitiveCount,CONST void * pIndexData,D3DFORMAT  IndexDataFormat,CONST void * pVertexStreamZeroData,UINT  VertexStreamZeroStride) PURE;
+    /*** Internal use IWineD3D methods ***/
+    STDMETHOD_(void, SetupTextureStates)(THIS_ DWORD Stage, DWORD Flags);
+
+
 };
 #undef INTERFACE
 
@@ -221,11 +229,16 @@
 #define IWineD3DDevice_GetIndices(p,a,b)                        (p)->lpVtbl->GetIndices(p,a,b)
 #define IWineD3DDevice_SetViewport(p,a)                         (p)->lpVtbl->SetViewport(p,a)
 #define IWineD3DDevice_GetViewport(p,a)                         (p)->lpVtbl->GetViewport(p,a)
+#define IWineD3DDevice_SetRenderState(p,a,b)                    (p)->lpVtbl->SetRenderState(p,a,b)
+#define IWineD3DDevice_GetRenderState(p,a,b)                    (p)->lpVtbl->GetRenderState(p,a,b)
+#define IWineD3DDevice_SetTextureStageState(p,a,b,c)            (p)->lpVtbl->SetTextureStageState(p,a,b,c)
+#define IWineD3DDevice_GetTextureStageState(p,a,b,c)            (p)->lpVtbl->GetTextureStageState(p,a,b,c)
 #define IWineD3DDevice_BeginScene(p)                            (p)->lpVtbl->BeginScene(p)
 #define IWineD3DDevice_DrawPrimitive(p,a,b,c)                   (p)->lpVtbl->DrawPrimitive(p,a,b,c)
 #define IWineD3DDevice_DrawIndexedPrimitive(p,a,b,c,d,e,f)      (p)->lpVtbl->DrawIndexedPrimitive(p,a,b,c,d,e,f)
 #define IWineD3DDevice_DrawPrimitiveUP(p,a,b,c,d)               (p)->lpVtbl->DrawPrimitiveUP(p,a,b,c,d)
 #define IWineD3DDevice_DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h)
+#define IWineD3DDevice_SetupTextureStates(p,a,b)                (p)->lpVtbl->SetupTextureStates(p,a,b)
 #endif
 
 /*****************************************************************************