Integrate hardware vertex shaders into the drawing pipeline.
[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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wined3d_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
27 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
28
29 static const Wined3dTextureStateMap textureObjectSamplerStates[]  = {
30     {WINED3DSAMP_ADDRESSU,      WINED3DSAMP_ADDRESSU},
31     {WINED3DSAMP_ADDRESSV,      WINED3DSAMP_ADDRESSV},
32     {WINED3DSAMP_ADDRESSW,      WINED3DSAMP_ADDRESSW},
33 /* NOTE: Sometimes it's a good idea to disable the setting of border colour, e.g. Axis and Allies */
34     {WINED3DSAMP_BORDERCOLOR,   WINED3DFUNC_NOTSUPPORTED/* WINED3DSAMP_BORDERCOLOR */},
35     {WINED3DSAMP_MAGFILTER,     WINED3DSAMP_MAGFILTER},
36     {WINED3DSAMP_MINFILTER,     WINED3DSAMP_MINFILTER},
37     {WINED3DSAMP_MIPFILTER,     WINED3DSAMP_MIPFILTER},
38 /* applies to the texture unit
39     WINED3DSAMP_MIPMAPLODBIAS, WINED3DSAMP_MIPMAPLODBIAS,
40 */
41     {WINED3DSAMP_MAXMIPLEVEL,   WINED3DSAMP_MAXMIPLEVEL},
42 #if 0
43     {WINED3DSAMP_MAXANISOTROPY, GL_SUPPORTED(EXT_TEXTURE_FILTER_ANISOTROPIC) ? WINED3DSAMP_MAXANISOTROPY : WINED3DFUNC_NOTSUPPORTED},
44 #else
45     {WINED3DSAMP_MAXANISOTROPY, WINED3DSAMP_MAXANISOTROPY},
46 #endif
47     {WINED3DSAMP_SRGBTEXTURE,   WINED3DFUNC_UNIMPLEMENTED},
48     {WINED3DSAMP_ELEMENTINDEX,  WINED3DFUNC_UNIMPLEMENTED},
49     {WINED3DSAMP_DMAPOFFSET,    WINED3DFUNC_UNIMPLEMENTED},
50     {-1, 0}
51 };
52
53 static const Wined3dTextureStateMap textureObjectTextureStates[] = {
54     {WINED3DTSS_ADDRESSW , WINED3DTSS_ADDRESSW},
55     {-1, 0}
56 };
57
58 /* *******************************************
59    IWineD3DBaseTexture IUnknown parts follow
60    ******************************************* */
61 HRESULT WINAPI IWineD3DBaseTextureImpl_QueryInterface(IWineD3DBaseTexture *iface, REFIID riid, LPVOID *ppobj)
62 {
63     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
64     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
65     /* FIXME: This needs to extend an IWineD3DBaseObject */
66     if (IsEqualGUID(riid, &IID_IUnknown)
67         || IsEqualGUID(riid, &IID_IWineD3DResource)
68         || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)) {
69         IUnknown_AddRef(iface);
70         *ppobj = This;
71         return D3D_OK;
72     }
73     return E_NOINTERFACE;
74 }
75
76 ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface) {
77     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
78     ULONG ref = InterlockedIncrement(&This->resource.ref);
79
80     TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
81     return ref;
82 }
83
84 ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) {
85     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
86     ULONG ref = InterlockedDecrement(&This->resource.ref);
87     TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
88     if (ref == 0) {
89         IWineD3DBaseTextureImpl_CleanUp(iface);
90         HeapFree(GetProcessHeap(), 0, This);
91     }
92     return ref;
93 }
94
95 /* class static */
96 void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface) {
97     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
98     TRACE("(%p) : textureName(%d)\n", This, This->baseTexture.textureName);
99     if (This->baseTexture.textureName != 0) {
100         ENTER_GL();
101         TRACE("(%p) : Deleting texture %d\n", This, This->baseTexture.textureName);
102         glDeleteTextures(1, &This->baseTexture.textureName);
103         LEAVE_GL();
104     }
105     IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
106 }
107
108 /* ****************************************************
109    IWineD3DBaseTexture IWineD3DResource parts follow
110    **************************************************** */
111 HRESULT WINAPI IWineD3DBaseTextureImpl_GetDevice(IWineD3DBaseTexture *iface, IWineD3DDevice** ppDevice) {
112     return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
113 }
114
115 HRESULT WINAPI IWineD3DBaseTextureImpl_SetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
116     return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
117 }
118
119 HRESULT WINAPI IWineD3DBaseTextureImpl_GetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
120     return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
121 }
122
123 HRESULT WINAPI IWineD3DBaseTextureImpl_FreePrivateData(IWineD3DBaseTexture *iface, REFGUID refguid) {
124     return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
125 }
126
127 DWORD    WINAPI        IWineD3DBaseTextureImpl_SetPriority(IWineD3DBaseTexture *iface, DWORD PriorityNew) {
128     return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
129 }
130
131 DWORD    WINAPI        IWineD3DBaseTextureImpl_GetPriority(IWineD3DBaseTexture *iface) {
132     return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
133 }
134
135 void     WINAPI        IWineD3DBaseTextureImpl_PreLoad(IWineD3DBaseTexture *iface) {
136     return IWineD3DResourceImpl_PreLoad((IWineD3DResource *)iface);
137 }
138
139 D3DRESOURCETYPE WINAPI IWineD3DBaseTextureImpl_GetType(IWineD3DBaseTexture *iface) {
140     return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
141 }
142
143 HRESULT WINAPI IWineD3DBaseTextureImpl_GetParent(IWineD3DBaseTexture *iface, IUnknown **pParent) {
144     return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
145 }
146
147 /* ******************************************************
148    IWineD3DBaseTexture IWineD3DBaseTexture parts follow
149    ****************************************************** */
150
151 /* There is no OpenGL equivilent of setLOD, getLOD, all they do it priortise testure loading
152  * so just pretend that they work unless something really needs a failure. */
153 DWORD WINAPI IWineD3DBaseTextureImpl_SetLOD(IWineD3DBaseTexture *iface, DWORD LODNew) {
154     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
155
156     if (This->resource.pool != D3DPOOL_MANAGED) {
157         return  D3DERR_INVALIDCALL;
158     }
159
160     if(LODNew >= This->baseTexture.levels)
161         LODNew = This->baseTexture.levels - 1;
162      This->baseTexture.LOD = LODNew;
163
164     TRACE("(%p) : set bogus LOD to %d \n", This, This->baseTexture.LOD);
165
166     return This->baseTexture.LOD;
167 }
168
169 DWORD WINAPI IWineD3DBaseTextureImpl_GetLOD(IWineD3DBaseTexture *iface) {
170     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
171
172     if (This->resource.pool != D3DPOOL_MANAGED) {
173         return  D3DERR_INVALIDCALL;
174     }
175
176     TRACE("(%p) : returning %d \n", This, This->baseTexture.LOD);
177
178     return This->baseTexture.LOD;
179 }
180
181 DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface) {
182     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
183     TRACE("(%p) : returning %d\n", This, This->baseTexture.levels);
184     return This->baseTexture.levels;
185 }
186
187 HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, D3DTEXTUREFILTERTYPE FilterType) {
188   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
189
190   if (!(This->baseTexture.usage & D3DUSAGE_AUTOGENMIPMAP)) {
191       TRACE("(%p) : returning invalid call\n", This);
192       return D3DERR_INVALIDCALL;
193   }
194   This->baseTexture.filterType = FilterType;
195   TRACE("(%p) : \n", This);
196   return D3D_OK;
197 }
198
199 D3DTEXTUREFILTERTYPE WINAPI IWineD3DBaseTextureImpl_GetAutoGenFilterType(IWineD3DBaseTexture *iface) {
200   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
201   FIXME("(%p) : stub\n", This);
202   if (!(This->baseTexture.usage & D3DUSAGE_AUTOGENMIPMAP)) {
203      return D3DTEXF_NONE;
204   }
205   return This->baseTexture.filterType;
206   return D3DTEXF_LINEAR; /* default */
207 }
208
209 void WINAPI IWineD3DBaseTextureImpl_GenerateMipSubLevels(IWineD3DBaseTexture *iface) {
210   IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
211   /* TODO: implement filters using GL_SGI_generate_mipmaps http://oss.sgi.com/projects/ogl-sample/registry/SGIS/generate_mipmap.txt */
212   FIXME("(%p) : stub\n", This);
213   return ;
214 }
215
216 /* Internal function, No d3d mapping */
217 BOOL WINAPI IWineD3DBaseTextureImpl_SetDirty(IWineD3DBaseTexture *iface, BOOL dirty) {
218     BOOL old;
219     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
220     old = This->baseTexture.dirty;
221     This->baseTexture.dirty = dirty;
222     return old;
223 }
224
225 BOOL WINAPI IWineD3DBaseTextureImpl_GetDirty(IWineD3DBaseTexture *iface) {
226     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
227     return This->baseTexture.dirty;
228 }
229
230 HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) {
231     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
232     HRESULT hr = D3D_OK;
233     UINT textureDimensions;
234     BOOL isNewTexture = FALSE;
235     TRACE("(%p) : About to bind texture\n", This);
236
237     textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
238     ENTER_GL();
239 #if 0 /* TODO: context manager support */
240      IWineD3DContextManager_PushState(This->contextManager, textureDimensions, ENABLED, NOW /* make sure the state is applied now */);
241 #else
242     glEnable(textureDimensions);
243 #endif
244
245     /* Generate a texture name if we don't already have one */
246     if (This->baseTexture.textureName == 0) {
247         glGenTextures(1, &This->baseTexture.textureName);
248         checkGLcall("glGenTextures");
249         TRACE("Generated texture %d\n", This->baseTexture.textureName);
250         if (This->resource.pool == D3DPOOL_DEFAULT) {
251             /* Tell opengl to try and keep this texture in video ram (well mostly) */
252             GLclampf tmp;
253             tmp = 0.9f;
254             glPrioritizeTextures(1, &This->baseTexture.textureName, &tmp);
255
256         }
257         /* Initilise the state of the texture object
258         to the openGL defaults, not the directx defaults */
259         This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]      = D3DTADDRESS_WRAP;
260         This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]      = D3DTADDRESS_WRAP;
261         This->baseTexture.states[WINED3DTEXSTA_ADDRESSW]      = D3DTADDRESS_WRAP;
262         This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR]   = 0;
263         This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]     = D3DTEXF_LINEAR;
264         This->baseTexture.states[WINED3DTEXSTA_MINFILTER]     = D3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */
265         This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]     = D3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */
266         This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL]   = 0;
267         This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = 0;
268         This->baseTexture.states[WINED3DTEXSTA_SRGBTEXTURE]   = 0;
269         This->baseTexture.states[WINED3DTEXSTA_ELEMENTINDEX]  = 0;
270         This->baseTexture.states[WINED3DTEXSTA_DMAPOFFSET]    = 0;
271         This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW]   = D3DTADDRESS_WRAP;
272         IWineD3DBaseTexture_SetDirty(iface, TRUE);
273         isNewTexture = TRUE;
274     }
275
276     /* Bind the texture */
277     if (This->baseTexture.textureName != 0) {
278         /* Always need to reset the number of mipmap levels when rebinding as it is
279         a property of the active texture unit, and another texture may have set it
280         to a different value                                                       */
281         if (This->baseTexture.levels > 1) {
282             TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1);
283             glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1);
284             checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)");
285         } else {
286            glTexParameteri(textureDimensions, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
287         }
288         glBindTexture(textureDimensions, This->baseTexture.textureName);
289         checkGLcall("glBindTexture");
290         if (isNewTexture) {
291             /* For a new texture we have to set the textures levels after binding the texture,
292             * in theory this is all we should ever have to dom, but because ATI's drivers are broken we
293             * also need to set the texture dimensins before the texture is is set */
294             TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1);
295             glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1);
296             checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)");
297         } else {
298             TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1);
299             glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1);
300             checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)");
301         }
302                 
303     } else { /* this only happened if we've run out of openGL textures */
304         WARN("This texture doesn't have an openGL texture assigned to it\n");
305         hr =  D3DERR_INVALIDCALL;
306     }
307
308     LEAVE_GL();
309     return hr;
310 }
311
312 HRESULT WINAPI IWineD3DBaseTextureImpl_UnBindTexture(IWineD3DBaseTexture *iface) {
313     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
314     UINT textureDimensions;
315
316     TRACE("(%p) : About to bind texture\n", This);
317     textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
318
319     ENTER_GL();
320
321     glBindTexture(textureDimensions, 0);
322 #if 0 /* TODO: context manager support */
323      IWineD3DContextManager_PopState(This->contextManager, textureDimensions, ENABLED, NOW /* make sure the state is applied now */);
324 #else
325     glDisable(textureDimensions);
326 #endif
327
328     LEAVE_GL();
329     return D3D_OK;
330 }
331
332 UINT WINAPI IWineD3DBaseTextureImpl_GetTextureDimensions(IWineD3DBaseTexture *iface){
333     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
334     FIXME("(%p) : This shouldn't be called\n", This);
335     return D3D_OK;
336 }
337
338 static inline GLenum warpLookupType(WINED3DSAMPLERSTATETYPE Type) {
339     switch(Type) {
340     case WINED3DSAMP_ADDRESSU:
341         return GL_TEXTURE_WRAP_S;
342     case WINED3DSAMP_ADDRESSV:
343         return GL_TEXTURE_WRAP_T;
344     case WINED3DSAMP_ADDRESSW:
345         return GL_TEXTURE_WRAP_R;
346     default:
347         FIXME("Unexpected warp type %d\n", Type);
348         return 0;
349     }
350 }
351
352 void WINAPI IWineD3DBaseTextureImpl_ApplyStateChanges(IWineD3DBaseTexture *iface,
353                                     const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1],
354                                     const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) {
355     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
356     int i;
357     DWORD *state = This->baseTexture.states;
358     GLint textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
359     IWineD3DBaseTexture_PreLoad(iface);
360     /* run through a couple of loops and apply and states that are different */
361     /* this will reduce the number of texture state changes to an absolute minimum
362     for multi-parameter states we  pickup the first one that changes, work out the correct values for the other states
363     and set all the states that we've just applied to their new values */
364
365     for (i = 0 ;textureObjectSamplerStates[i].state != -1; i++) {
366         if (*state != samplerStates[textureObjectSamplerStates[i].state]) {
367             /* apply the state */
368             TRACE("(%p) : Changing state %u from %ld to %ld \n",This, i, *state , samplerStates[textureObjectSamplerStates[i].state]);
369             switch (textureObjectSamplerStates[i].function) {
370             case WINED3DSAMP_ADDRESSU:
371             case WINED3DSAMP_ADDRESSV: /* fall through */
372             case WINED3DSAMP_ADDRESSW: /* fall through */
373                 *state = samplerStates[textureObjectSamplerStates[i].state];
374                 if (*state < minLookup[WINELOOKUP_WARPPARAM] || *state > maxLookup[WINELOOKUP_WARPPARAM]) {
375                     FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", *state, textureObjectSamplerStates[i].function);
376                 } else {
377                     GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][*state - minLookup[WINELOOKUP_WARPPARAM]];
378                     TRACE("Setting WRAP_R to %d for %x\n", wrapParm, textureDimensions);
379                     glTexParameteri(textureDimensions, warpLookupType(textureObjectSamplerStates[i].function), wrapParm);
380                     checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
381                 }
382             break;
383             case WINED3DSAMP_BORDERCOLOR:
384             {
385                 float col[4];
386                 *state = samplerStates[textureObjectSamplerStates[i].state];
387                 D3DCOLORTOGLFLOAT4(*state, col);
388                 TRACE("Setting border color for %u to %lx\n", textureDimensions, *state);
389                 glTexParameterfv(textureDimensions, GL_TEXTURE_BORDER_COLOR, &col[0]);
390                 checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)");
391             }
392             break;
393             case WINED3DSAMP_MAGFILTER:
394                 {
395                     GLint glValue;
396                     *state = samplerStates[textureObjectSamplerStates[i].state];
397                     if (*state < minLookup[WINELOOKUP_MAGFILTER] || *state > maxLookup[WINELOOKUP_MAGFILTER]) {
398                         FIXME("Unrecognized or unsupported MAGFILTER* value %ld, state %d\n", *state, textureObjectSamplerStates[i].function);
399                     }
400                     glValue = stateLookup[WINELOOKUP_MAGFILTER][*state - minLookup[WINELOOKUP_MAGFILTER]];
401                     TRACE("ValueMAG=%ld setting MAGFILTER to %x\n", *state, glValue);
402                     glTexParameteri(textureDimensions, GL_TEXTURE_MAG_FILTER, glValue);
403                 /* We need to reset the Aniotropic filtering state when we change the mag filter to D3DTEXF_ANISOTROPIC (this seems a bit weird, check the documentataion to see how it should be switched off. */
404                     if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && D3DTEXF_ANISOTROPIC == *state) {
405                         glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]);
406                     }
407                 }
408             break;
409
410             case WINED3DSAMP_MINFILTER:
411                 This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = samplerStates[WINED3DSAMP_MIPFILTER];
412             case WINED3DSAMP_MIPFILTER: /* fall through */
413                 {
414                     GLint glValue;
415                     *state = samplerStates[textureObjectSamplerStates[i].state];
416                     if (This->baseTexture.states[WINED3DTEXSTA_MINFILTER] < D3DTEXF_NONE ||
417                         This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] < D3DTEXF_NONE ||
418                         This->baseTexture.states[WINED3DTEXSTA_MINFILTER] > D3DTEXF_ANISOTROPIC ||
419                         This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] > D3DTEXF_LINEAR)
420                     {
421
422                         FIXME("Unrecognized or unsupported D3DSAMP_MINFILTER value %ld, state %d D3DSAMP_MIPFILTER value %ld, state %d\n",
423                                 This->baseTexture.states[WINED3DTEXSTA_MINFILTER],
424                                 textureObjectSamplerStates[WINED3DTEXSTA_MINFILTER].function,
425                                 This->baseTexture.states[WINED3DTEXSTA_MIPFILTER],
426                                 textureObjectSamplerStates[WINED3DTEXSTA_MIPFILTER].function);
427                     }
428                     glValue = minMipLookup[min(max(This->baseTexture.states[WINED3DTEXSTA_MINFILTER],D3DTEXF_NONE), D3DTEXF_ANISOTROPIC)]
429                                                 [min(max(This->baseTexture.states[WINED3DTEXSTA_MIPFILTER],D3DTEXF_NONE), D3DTEXF_LINEAR)];
430
431                     TRACE("ValueMIN=%ld, ValueMIP=%ld, setting MINFILTER to %x\n", 
432                             This->baseTexture.states[WINED3DTEXSTA_MINFILTER], 
433                             This->baseTexture.states[WINED3DTEXSTA_MIPFILTER], glValue);
434                     glTexParameteri(textureDimensions, GL_TEXTURE_MIN_FILTER, glValue);
435                     checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");
436                 }
437             break;
438             case WINED3DSAMP_MAXMIPLEVEL:
439                 *state = samplerStates[textureObjectSamplerStates[i].state];
440                 /**
441                 * Not really the same, but the more apprioprate than nothing
442                 */
443                 glTexParameteri(textureDimensions, GL_TEXTURE_BASE_LEVEL, *state);
444             break;
445             case WINED3DSAMP_MAXANISOTROPY:
446                 *state = samplerStates[textureObjectSamplerStates[i].state];
447                 glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT,  *state);
448                 checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ...");
449             break;
450             case WINED3DFUNC_UNIMPLEMENTED: /* unimplemented */
451                 TRACE("(%p) : stub\n", This);
452                 *state = samplerStates[textureObjectSamplerStates[i].state];
453             break;
454             case WINED3DFUNC_NOTSUPPORTED: /* nop */
455                 TRACE("(%p) : %s function is not supported by this opengl implementation\n", This, "unknown" /* TODO: replace with debug_blah... */);
456                 *state = samplerStates[textureObjectSamplerStates[i].state];
457             break;
458             }
459         }
460         state++;
461     }
462
463     for(i = 0 ;textureObjectTextureStates[i].state != - 1; i++) {
464         if(*state != textureStates[textureObjectTextureStates[i].state] ) {
465             /* apply the state */
466             *state = textureStates[textureObjectTextureStates[i].state];
467             switch (textureObjectTextureStates[i].function) {
468             case WINED3DTSS_ADDRESSW:
469             /* I'm not sure what to do if this is set as well as ADDRESSW on the sampler, how do they interact together? */
470             break;
471             case WINED3DFUNC_UNIMPLEMENTED: /* unimplemented */
472             TRACE("(%p) : stub\n", This);
473             break;
474             case WINED3DFUNC_NOTSUPPORTED: /* nop */
475             TRACE("(%p) : function no supported by this opengl implementation\n", This);
476             break;
477             }
478         }
479         state++;
480     }
481 }
482
483
484 static const IWineD3DBaseTextureVtbl IWineD3DBaseTexture_Vtbl =
485 {
486     /* IUnknown */
487     IWineD3DBaseTextureImpl_QueryInterface,
488     IWineD3DBaseTextureImpl_AddRef,
489     IWineD3DBaseTextureImpl_Release,
490     /* IWineD3DResource */
491     IWineD3DBaseTextureImpl_GetParent,
492     IWineD3DBaseTextureImpl_GetDevice,
493     IWineD3DBaseTextureImpl_SetPrivateData,
494     IWineD3DBaseTextureImpl_GetPrivateData,
495     IWineD3DBaseTextureImpl_FreePrivateData,
496     IWineD3DBaseTextureImpl_SetPriority,
497     IWineD3DBaseTextureImpl_GetPriority,
498     IWineD3DBaseTextureImpl_PreLoad,
499     IWineD3DBaseTextureImpl_GetType,
500     /*IWineD3DBaseTexture*/
501     IWineD3DBaseTextureImpl_SetLOD,
502     IWineD3DBaseTextureImpl_GetLOD,
503     IWineD3DBaseTextureImpl_GetLevelCount,
504     IWineD3DBaseTextureImpl_SetAutoGenFilterType,
505     IWineD3DBaseTextureImpl_GetAutoGenFilterType,
506     IWineD3DBaseTextureImpl_GenerateMipSubLevels,
507     IWineD3DBaseTextureImpl_SetDirty,
508     IWineD3DBaseTextureImpl_GetDirty,
509     /* internal */
510     IWineD3DBaseTextureImpl_BindTexture,
511     IWineD3DBaseTextureImpl_UnBindTexture,
512     IWineD3DBaseTextureImpl_GetTextureDimensions,
513     IWineD3DBaseTextureImpl_ApplyStateChanges
514
515 };