wined3d: Remove some assumptions that PreLoad() will always bind the texture.
[wine] / dlls / wined3d / basetexture.c
1 /*
2  * IWineD3DBaseTexture Implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2004 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
28 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
29
30 /* *******************************************
31    IWineD3DBaseTexture IUnknown parts follow
32    ******************************************* */
33 HRESULT WINAPI IWineD3DBaseTextureImpl_QueryInterface(IWineD3DBaseTexture *iface, REFIID riid, LPVOID *ppobj)
34 {
35     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
36     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
37     if (IsEqualGUID(riid, &IID_IUnknown)
38         || IsEqualGUID(riid, &IID_IWineD3DBase)
39         || IsEqualGUID(riid, &IID_IWineD3DResource)
40         || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)) {
41         IUnknown_AddRef(iface);
42         *ppobj = This;
43         return S_OK;
44     }
45     *ppobj = NULL;
46     return E_NOINTERFACE;
47 }
48
49 ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface) {
50     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
51     ULONG ref = InterlockedIncrement(&This->resource.ref);
52
53     TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
54     return ref;
55 }
56
57 ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) {
58     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
59     ULONG ref = InterlockedDecrement(&This->resource.ref);
60     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
61     if (ref == 0) {
62         IWineD3DBaseTextureImpl_CleanUp(iface);
63         HeapFree(GetProcessHeap(), 0, This);
64     }
65     return ref;
66 }
67
68 /* class static */
69 void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface) {
70     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
71     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
72
73     TRACE("(%p) : textureName(%d)\n", This, This->baseTexture.textureName);
74     if (This->baseTexture.textureName != 0) {
75         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
76         ENTER_GL();
77         TRACE("(%p) : Deleting texture %d\n", This, This->baseTexture.textureName);
78         glDeleteTextures(1, &This->baseTexture.textureName);
79         LEAVE_GL();
80     }
81     IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
82 }
83
84 /* ****************************************************
85    IWineD3DBaseTexture IWineD3DResource parts follow
86    **************************************************** */
87 HRESULT WINAPI IWineD3DBaseTextureImpl_GetDevice(IWineD3DBaseTexture *iface, IWineD3DDevice** ppDevice) {
88     return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
89 }
90
91 HRESULT WINAPI IWineD3DBaseTextureImpl_SetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
92     return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
93 }
94
95 HRESULT WINAPI IWineD3DBaseTextureImpl_GetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
96     return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
97 }
98
99 HRESULT WINAPI IWineD3DBaseTextureImpl_FreePrivateData(IWineD3DBaseTexture *iface, REFGUID refguid) {
100     return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
101 }
102
103 DWORD    WINAPI        IWineD3DBaseTextureImpl_SetPriority(IWineD3DBaseTexture *iface, DWORD PriorityNew) {
104     return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
105 }
106
107 DWORD    WINAPI        IWineD3DBaseTextureImpl_GetPriority(IWineD3DBaseTexture *iface) {
108     return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
109 }
110
111 void     WINAPI        IWineD3DBaseTextureImpl_PreLoad(IWineD3DBaseTexture *iface) {
112     IWineD3DResourceImpl_PreLoad((IWineD3DResource *)iface);
113 }
114
115 void     WINAPI        IWineD3DBaseTextureImpl_UnLoad(IWineD3DBaseTexture *iface) {
116     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
117     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
118
119     if(This->baseTexture.textureName) {
120         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
121         ENTER_GL();
122         glDeleteTextures(1, &This->baseTexture.textureName);
123         This->baseTexture.textureName = 0;
124         LEAVE_GL();
125     }
126     This->baseTexture.dirty = TRUE;
127 }
128
129 WINED3DRESOURCETYPE WINAPI IWineD3DBaseTextureImpl_GetType(IWineD3DBaseTexture *iface) {
130     return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
131 }
132
133 HRESULT WINAPI IWineD3DBaseTextureImpl_GetParent(IWineD3DBaseTexture *iface, IUnknown **pParent) {
134     return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
135 }
136
137 /* ******************************************************
138    IWineD3DBaseTexture IWineD3DBaseTexture parts follow
139    ****************************************************** */
140
141 /* There is no OpenGL equivalent of setLOD, getLOD. All they do anyway is prioritize texture loading
142  * so just pretend that they work unless something really needs a failure. */
143 DWORD WINAPI IWineD3DBaseTextureImpl_SetLOD(IWineD3DBaseTexture *iface, DWORD LODNew) {
144     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
145
146     if (This->resource.pool != WINED3DPOOL_MANAGED) {
147         return  WINED3DERR_INVALIDCALL;
148     }
149
150     if(LODNew >= This->baseTexture.levels)
151         LODNew = This->baseTexture.levels - 1;
152      This->baseTexture.LOD = LODNew;
153
154     TRACE("(%p) : set bogus LOD to %d\n", This, This->baseTexture.LOD);
155
156     return This->baseTexture.LOD;
157 }
158
159 DWORD WINAPI IWineD3DBaseTextureImpl_GetLOD(IWineD3DBaseTexture *iface) {
160     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
161
162     if (This->resource.pool != WINED3DPOOL_MANAGED) {
163         return  WINED3DERR_INVALIDCALL;
164     }
165
166     TRACE("(%p) : returning %d\n", This, This->baseTexture.LOD);
167
168     return This->baseTexture.LOD;
169 }
170
171 DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface) {
172     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
173     TRACE("(%p) : returning %d\n", This, This->baseTexture.levels);
174     return This->baseTexture.levels;
175 }
176
177 HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) {
178   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
179   IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
180   UINT textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
181
182   if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) {
183       TRACE("(%p) : returning invalid call\n", This);
184       return WINED3DERR_INVALIDCALL;
185   }
186   if(This->baseTexture.filterType != FilterType) {
187       /* What about multithreading? Do we want all the context overhead just to set this value?
188        * Or should we delay the applying until the texture is used for drawing? For now, apply
189        * immediately.
190        */
191       ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
192       ENTER_GL();
193       glBindTexture(textureDimensions, This->baseTexture.textureName);
194       checkGLcall("glBindTexture");
195       switch(FilterType) {
196           case WINED3DTEXF_NONE:
197           case WINED3DTEXF_POINT:
198               glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
199               checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST)");
200
201               break;
202           case WINED3DTEXF_LINEAR:
203               glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
204               checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)");
205
206               break;
207           default:
208               WARN("Unexpected filter type %d, setting to GL_NICEST\n", FilterType);
209               glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
210               checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)");
211       }
212       LEAVE_GL();
213   }
214   This->baseTexture.filterType = FilterType;
215   TRACE("(%p) :\n", This);
216   return WINED3D_OK;
217 }
218
219 WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DBaseTextureImpl_GetAutoGenFilterType(IWineD3DBaseTexture *iface) {
220   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
221   FIXME("(%p) : stub\n", This);
222   if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) {
223      return WINED3DTEXF_NONE;
224   }
225   return This->baseTexture.filterType;
226 }
227
228 void WINAPI IWineD3DBaseTextureImpl_GenerateMipSubLevels(IWineD3DBaseTexture *iface) {
229   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
230   /* TODO: implement filters using GL_SGI_generate_mipmaps http://oss.sgi.com/projects/ogl-sample/registry/SGIS/generate_mipmap.txt */
231   FIXME("(%p) : stub\n", This);
232   return ;
233 }
234
235 /* Internal function, No d3d mapping */
236 BOOL WINAPI IWineD3DBaseTextureImpl_SetDirty(IWineD3DBaseTexture *iface, BOOL dirty) {
237     BOOL old;
238     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
239     old = This->baseTexture.dirty;
240     This->baseTexture.dirty = dirty;
241     return old;
242 }
243
244 BOOL WINAPI IWineD3DBaseTextureImpl_GetDirty(IWineD3DBaseTexture *iface) {
245     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
246     return This->baseTexture.dirty;
247 }
248
249 HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) {
250     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
251     HRESULT hr = WINED3D_OK;
252     UINT textureDimensions;
253     BOOL isNewTexture = FALSE;
254     TRACE("(%p) : About to bind texture\n", This);
255
256     textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
257     ENTER_GL();
258     /* Generate a texture name if we don't already have one */
259     if (This->baseTexture.textureName == 0) {
260         glGenTextures(1, &This->baseTexture.textureName);
261         checkGLcall("glGenTextures");
262         TRACE("Generated texture %d\n", This->baseTexture.textureName);
263         if (This->resource.pool == WINED3DPOOL_DEFAULT) {
264             /* Tell opengl to try and keep this texture in video ram (well mostly) */
265             GLclampf tmp;
266             tmp = 0.9f;
267             glPrioritizeTextures(1, &This->baseTexture.textureName, &tmp);
268
269         }
270         /* Initialise the state of the texture object
271         to the openGL defaults, not the directx defaults */
272         This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]      = WINED3DTADDRESS_WRAP;
273         This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]      = WINED3DTADDRESS_WRAP;
274         This->baseTexture.states[WINED3DTEXSTA_ADDRESSW]      = WINED3DTADDRESS_WRAP;
275         This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR]   = 0;
276         This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]     = WINED3DTEXF_LINEAR;
277         This->baseTexture.states[WINED3DTEXSTA_MINFILTER]     = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
278         This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]     = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
279         This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL]   = 0;
280         This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = 0;
281         This->baseTexture.states[WINED3DTEXSTA_SRGBTEXTURE]   = 0;
282         This->baseTexture.states[WINED3DTEXSTA_ELEMENTINDEX]  = 0;
283         This->baseTexture.states[WINED3DTEXSTA_DMAPOFFSET]    = 0;
284         This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW]   = WINED3DTADDRESS_WRAP;
285         IWineD3DBaseTexture_SetDirty(iface, TRUE);
286         isNewTexture = TRUE;
287
288         if(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) {
289             /* This means double binding the texture at creation, but keeps the code simpler all
290              * in all, and the run-time path free from additional checks
291              */
292             glBindTexture(textureDimensions, This->baseTexture.textureName);
293             checkGLcall("glBindTexture");
294             glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
295             checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
296         }
297     }
298
299     /* Bind the texture */
300     if (This->baseTexture.textureName != 0) {
301         glBindTexture(textureDimensions, This->baseTexture.textureName);
302         checkGLcall("glBindTexture");
303         if (isNewTexture) {
304             /* For a new texture we have to set the textures levels after binding the texture.
305              * In theory this is all we should ever have to do, but because ATI's drivers are broken, we
306              * also need to set the texture dimensions before the texture is set
307              * Beware that texture rectangles do not support mipmapping, but set the maxmiplevel if we're
308              * relying on the partial GL_ARB_texture_non_power_of_two emulation with texture rectangles
309              * (ie, do not care for cond_np2 here, just look for GL_TEXTURE_RECTANGLE_ARB)
310              */
311             if(textureDimensions != GL_TEXTURE_RECTANGLE_ARB) {
312                 TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1);
313                 glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1);
314                 checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)");
315             }
316             if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) {
317                 /* Cubemaps are always set to clamp, regardless of the sampler state. */
318                 glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
319                 glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
320                 glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
321             }
322         }
323                 
324     } else { /* this only happened if we've run out of openGL textures */
325         WARN("This texture doesn't have an openGL texture assigned to it\n");
326         hr =  WINED3DERR_INVALIDCALL;
327     }
328
329     LEAVE_GL();
330     return hr;
331 }
332
333 UINT WINAPI IWineD3DBaseTextureImpl_GetTextureDimensions(IWineD3DBaseTexture *iface){
334     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
335     FIXME("(%p) : This shouldn't be called\n", This);
336     return WINED3D_OK;
337 }
338
339 BOOL WINAPI IWineD3DBaseTextureImpl_IsCondNP2(IWineD3DBaseTexture *iface){
340     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
341     FIXME("(%p) : This shouldn't be called\n", This);
342     return FALSE;
343 }
344
345 static inline GLenum warpLookupType(WINED3DSAMPLERSTATETYPE Type) {
346     switch(Type) {
347     case WINED3DSAMP_ADDRESSU:
348         return GL_TEXTURE_WRAP_S;
349     case WINED3DSAMP_ADDRESSV:
350         return GL_TEXTURE_WRAP_T;
351     case WINED3DSAMP_ADDRESSW:
352         return GL_TEXTURE_WRAP_R;
353     default:
354         FIXME("Unexpected warp type %d\n", Type);
355         return 0;
356     }
357 }
358
359 static inline void apply_wrap(const GLint textureDimensions, const DWORD state, const GLint type,
360                               BOOL cond_np2) {
361     GLint wrapParm;
362
363     if (state < minLookup[WINELOOKUP_WARPPARAM] || state > maxLookup[WINELOOKUP_WARPPARAM]) {
364         FIXME("Unrecognized or unsupported WINED3DTADDRESS_U value %d\n", state);
365     } else {
366         if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) {
367             /* Cubemaps are always set to clamp, regardless of the sampler state. */
368             wrapParm = GL_CLAMP_TO_EDGE;
369         } else if(cond_np2) {
370             if(state == WINED3DTADDRESS_WRAP) {
371                 wrapParm = GL_CLAMP_TO_EDGE;
372             } else {
373                 wrapParm = stateLookup[WINELOOKUP_WARPPARAM][state - minLookup[WINELOOKUP_WARPPARAM]];
374             }
375         } else {
376             wrapParm = stateLookup[WINELOOKUP_WARPPARAM][state - minLookup[WINELOOKUP_WARPPARAM]];
377         }
378         TRACE("Setting WRAP_S to %d for %x\n", wrapParm, textureDimensions);
379         glTexParameteri(textureDimensions, type, wrapParm);
380         checkGLcall("glTexParameteri(..., type, wrapParm)");
381     }
382 }
383
384 void WINAPI IWineD3DBaseTextureImpl_ApplyStateChanges(IWineD3DBaseTexture *iface,
385                                     const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1],
386                                     const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) {
387     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
388     DWORD state;
389     GLint textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
390     BOOL cond_np2 = IWineD3DBaseTexture_IsCondNP2(iface);
391
392     /* ApplyStateChanges relies on the correct texture being bound and loaded. */
393
394     if(samplerStates[WINED3DSAMP_ADDRESSU]      != This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]) {
395         state = samplerStates[WINED3DSAMP_ADDRESSU];
396         apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_S, cond_np2);
397         This->baseTexture.states[WINED3DTEXSTA_ADDRESSU] = state;
398     }
399
400     if(samplerStates[WINED3DSAMP_ADDRESSV]      != This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]) {
401         state = samplerStates[WINED3DSAMP_ADDRESSV];
402         apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_T, cond_np2);
403         This->baseTexture.states[WINED3DTEXSTA_ADDRESSV] = state;
404     }
405
406     if(samplerStates[WINED3DSAMP_ADDRESSW]      != This->baseTexture.states[WINED3DTEXSTA_ADDRESSW]) {
407         state = samplerStates[WINED3DSAMP_ADDRESSW];
408         apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_R, cond_np2);
409         This->baseTexture.states[WINED3DTEXSTA_ADDRESSW] = state;
410     }
411
412     if(samplerStates[WINED3DSAMP_BORDERCOLOR]   != This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR]) {
413         float col[4];
414
415         state = samplerStates[WINED3DSAMP_BORDERCOLOR];
416         D3DCOLORTOGLFLOAT4(state, col);
417         TRACE("Setting border color for %u to %x\n", textureDimensions, state);
418         glTexParameterfv(textureDimensions, GL_TEXTURE_BORDER_COLOR, &col[0]);
419         checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)");
420         This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR] = state;
421     }
422
423     if(samplerStates[WINED3DSAMP_MAGFILTER]     != This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]) {
424         GLint glValue;
425         state = samplerStates[WINED3DSAMP_MAGFILTER];
426         if (state > WINED3DTEXF_ANISOTROPIC) {
427             FIXME("Unrecognized or unsupported MAGFILTER* value %d\n", state);
428         } else {
429             glValue = (*This->baseTexture.magLookup)[state - WINED3DTEXF_NONE];
430             TRACE("ValueMAG=%d setting MAGFILTER to %x\n", state, glValue);
431             glTexParameteri(textureDimensions, GL_TEXTURE_MAG_FILTER, glValue);
432             /* We need to reset the Anisotropic filtering state when we change the mag filter to WINED3DTEXF_ANISOTROPIC (this seems a bit weird, check the documentation to see how it should be switched off. */
433             if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && WINED3DTEXF_ANISOTROPIC == state &&
434                 !cond_np2) {
435                 glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]);
436             }
437             This->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = state;
438         }
439     }
440
441     if((samplerStates[WINED3DSAMP_MINFILTER]     != This->baseTexture.states[WINED3DTEXSTA_MINFILTER] ||
442         samplerStates[WINED3DSAMP_MIPFILTER]     != This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] ||
443         samplerStates[WINED3DSAMP_MAXMIPLEVEL]   != This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL])) {
444         GLint glValue;
445
446         This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = samplerStates[WINED3DSAMP_MIPFILTER];
447         This->baseTexture.states[WINED3DTEXSTA_MINFILTER] = samplerStates[WINED3DSAMP_MINFILTER];
448         This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] = samplerStates[WINED3DSAMP_MAXMIPLEVEL];
449
450         if (This->baseTexture.states[WINED3DTEXSTA_MINFILTER] > WINED3DTEXF_ANISOTROPIC ||
451             This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] > WINED3DTEXF_LINEAR)
452         {
453
454             FIXME("Unrecognized or unsupported D3DSAMP_MINFILTER value %d D3DSAMP_MIPFILTER value %d\n",
455                   This->baseTexture.states[WINED3DTEXSTA_MINFILTER],
456                   This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]);
457         }
458         glValue = (*This->baseTexture.minMipLookup)
459                 [min(max(samplerStates[WINED3DSAMP_MINFILTER],WINED3DTEXF_NONE), WINED3DTEXF_ANISOTROPIC)]
460                 [min(max(samplerStates[WINED3DSAMP_MIPFILTER],WINED3DTEXF_NONE), WINED3DTEXF_LINEAR)];
461
462         TRACE("ValueMIN=%d, ValueMIP=%d, setting MINFILTER to %x\n",
463               samplerStates[WINED3DSAMP_MINFILTER],
464               samplerStates[WINED3DSAMP_MIPFILTER], glValue);
465         glTexParameteri(textureDimensions, GL_TEXTURE_MIN_FILTER, glValue);
466         checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");
467
468         if(!cond_np2) {
469             if(This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] == WINED3DTEXF_NONE) {
470                 glValue = 0;
471             } else if(This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] >= This->baseTexture.levels) {
472                 glValue = This->baseTexture.levels - 1;
473             } else {
474                 glValue = This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL];
475             }
476             glTexParameteri(textureDimensions, GL_TEXTURE_BASE_LEVEL, glValue);
477         }
478     }
479
480     if(samplerStates[WINED3DSAMP_MAXANISOTROPY] != This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY]) {
481         if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && !cond_np2) {
482             glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]);
483             checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ...");
484         } else {
485             WARN("Unsupported in local OpenGL implementation: glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT\n");
486         }
487         This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = samplerStates[WINED3DSAMP_MAXANISOTROPY];
488     }
489 }
490
491
492 static const IWineD3DBaseTextureVtbl IWineD3DBaseTexture_Vtbl =
493 {
494     /* IUnknown */
495     IWineD3DBaseTextureImpl_QueryInterface,
496     IWineD3DBaseTextureImpl_AddRef,
497     IWineD3DBaseTextureImpl_Release,
498     /* IWineD3DResource */
499     IWineD3DBaseTextureImpl_GetParent,
500     IWineD3DBaseTextureImpl_GetDevice,
501     IWineD3DBaseTextureImpl_SetPrivateData,
502     IWineD3DBaseTextureImpl_GetPrivateData,
503     IWineD3DBaseTextureImpl_FreePrivateData,
504     IWineD3DBaseTextureImpl_SetPriority,
505     IWineD3DBaseTextureImpl_GetPriority,
506     IWineD3DBaseTextureImpl_PreLoad,
507     IWineD3DBaseTextureImpl_UnLoad,
508     IWineD3DBaseTextureImpl_GetType,
509     /*IWineD3DBaseTexture*/
510     IWineD3DBaseTextureImpl_SetLOD,
511     IWineD3DBaseTextureImpl_GetLOD,
512     IWineD3DBaseTextureImpl_GetLevelCount,
513     IWineD3DBaseTextureImpl_SetAutoGenFilterType,
514     IWineD3DBaseTextureImpl_GetAutoGenFilterType,
515     IWineD3DBaseTextureImpl_GenerateMipSubLevels,
516     IWineD3DBaseTextureImpl_SetDirty,
517     IWineD3DBaseTextureImpl_GetDirty,
518     /* internal */
519     IWineD3DBaseTextureImpl_BindTexture,
520     IWineD3DBaseTextureImpl_GetTextureDimensions,
521     IWineD3DBaseTextureImpl_IsCondNP2,
522     IWineD3DBaseTextureImpl_ApplyStateChanges
523
524 };