Fix compilation.
[wine] / dlls / wined3d / device.c
1 /*
2  * IWineD3DDevice implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2003-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
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);
27 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
28 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
29
30 /**********************************************************
31  * Global variable / Constants follow
32  **********************************************************/
33 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};  /* When needed for comparisons */
34
35 /**********************************************************
36  * Utility functions follow
37  **********************************************************/
38 /* Convert the D3DLIGHT properties into equivalent gl lights */
39 void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
40
41     float quad_att;
42     float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
43     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
44
45     /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
46     glMatrixMode(GL_MODELVIEW);
47     glPushMatrix();
48     glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
49
50     /* Diffuse: */
51     colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
52     colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
53     colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
54     colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
55     glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
56     checkGLcall("glLightfv");
57
58     /* Specular */
59     colRGBA[0] = lightInfo->OriginalParms.Specular.r;
60     colRGBA[1] = lightInfo->OriginalParms.Specular.g;
61     colRGBA[2] = lightInfo->OriginalParms.Specular.b;
62     colRGBA[3] = lightInfo->OriginalParms.Specular.a;
63     glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
64     checkGLcall("glLightfv");
65
66     /* Ambient */
67     colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
68     colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
69     colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
70     colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
71     glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
72     checkGLcall("glLightfv");
73
74     /* Attenuation - Are these right? guessing... */
75     glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION,  lightInfo->OriginalParms.Attenuation0);
76     checkGLcall("glLightf");
77     glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION,    lightInfo->OriginalParms.Attenuation1);
78     checkGLcall("glLightf");
79
80     quad_att = 1.4/(lightInfo->OriginalParms.Range*lightInfo->OriginalParms.Range);
81     if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
82     glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
83     checkGLcall("glLightf");
84
85     switch (lightInfo->OriginalParms.Type) {
86     case D3DLIGHT_POINT:
87         /* Position */
88         glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
89         checkGLcall("glLightfv");
90         glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
91         checkGLcall("glLightf");
92         /* FIXME: Range */
93         break;
94
95     case D3DLIGHT_SPOT:
96         /* Position */
97         glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
98         checkGLcall("glLightfv");
99         /* Direction */
100         glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
101         checkGLcall("glLightfv");
102         glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
103         checkGLcall("glLightf");
104         glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
105         checkGLcall("glLightf");
106         /* FIXME: Range */
107         break;
108
109     case D3DLIGHT_DIRECTIONAL:
110         /* Direction */
111         glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
112         checkGLcall("glLightfv");
113         glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
114         checkGLcall("glLightf");
115         glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
116         checkGLcall("glLightf");
117         break;
118
119     default:
120         FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
121     }
122
123     /* Restore the modelview matrix */
124     glPopMatrix();
125 }
126
127 /**********************************************************
128  * IWineD3DDevice implementation follows
129  **********************************************************/
130 HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
131     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
132     *pParent = This->parent;
133     IUnknown_AddRef(This->parent);
134     return D3D_OK;
135 }
136
137 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage, 
138                              DWORD FVF, D3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
139                              IUnknown *parent) {
140
141     IWineD3DVertexBufferImpl *object;
142     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
143
144     /* Allocate the storage for the device */
145     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DVertexBufferImpl));
146     object->lpVtbl                = &IWineD3DVertexBuffer_Vtbl;
147     object->resource.wineD3DDevice= iface;
148     IWineD3DDevice_AddRef(iface);
149     object->resource.parent       = parent;
150     object->resource.resourceType = D3DRTYPE_VERTEXBUFFER;
151     object->resource.ref          = 1;
152     object->allocatedMemory       = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size);
153     object->currentDesc.Usage     = Usage;
154     object->currentDesc.Pool      = Pool;
155     object->currentDesc.FVF       = FVF;
156     object->currentDesc.Size      = Size;
157
158     TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->allocatedMemory, object);
159     *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
160
161     return D3D_OK;
162 }
163
164 HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage, 
165                                                     D3DFORMAT Format, D3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
166                                                     HANDLE *sharedHandle, IUnknown *parent) {
167     IWineD3DIndexBufferImpl *object;
168     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
169
170     /* Allocate the storage for the device */
171     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DIndexBufferImpl));
172     object->lpVtbl = &IWineD3DIndexBuffer_Vtbl;
173     object->resource.wineD3DDevice = iface;
174     object->resource.resourceType  = D3DRTYPE_INDEXBUFFER;
175     object->resource.parent        = parent;
176     IWineD3DDevice_AddRef(iface);
177     object->resource.ref = 1;
178     object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
179     object->currentDesc.Usage = Usage;
180     object->currentDesc.Pool  = Pool;
181     object->currentDesc.Format= Format;
182     object->currentDesc.Size  = Length;
183
184     TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format, 
185                            debug_d3dformat(Format), Pool, object, object->allocatedMemory);
186     *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
187
188     return D3D_OK;
189 }
190
191 HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
192   
193     IWineD3DDeviceImpl     *This = (IWineD3DDeviceImpl *)iface;
194     IWineD3DStateBlockImpl *object;
195   
196     /* Allocate Storage for the state block */
197     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
198     object->lpVtbl        = &IWineD3DStateBlock_Vtbl;
199     object->wineD3DDevice = iface;
200     IWineD3DDevice_AddRef(iface);
201     object->parent        = parent;
202     object->ref           = 1;
203     object->blockType     = Type;
204     *ppStateBlock         = (IWineD3DStateBlock *)object;
205
206     /* Special case - Used during initialization to produce a placeholder stateblock
207           so other functions called can update a state block                         */
208     if (Type == (D3DSTATEBLOCKTYPE) 0) {
209         /* Don't bother increasing the reference count otherwise a device will never
210            be freed due to circular dependencies                                   */
211         return D3D_OK;
212     }
213
214     /* Otherwise, might as well set the whole state block to the appropriate values */
215     IWineD3DDevice_AddRef(iface);
216     memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
217     FIXME("unfinished - needs to set up changed and set attributes\n");
218     return D3D_OK;
219 }
220
221 /*****
222  * Get / Set FVF
223  *****/
224 HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
225     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
226
227     /* Update the current statte block */
228     This->updateStateBlock->fvf              = fvf;
229     This->updateStateBlock->changed.fvf      = TRUE;
230     This->updateStateBlock->set.fvf          = TRUE;
231
232     TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
233     
234     /* No difference if recording or not */
235     return D3D_OK;
236 }
237 HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
238     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
239     TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
240     *pfvf = This->stateBlock->fvf;
241     return D3D_OK;
242 }
243
244 /*****
245  * Get / Set Stream Source
246  *****/
247 HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
248     IWineD3DDeviceImpl       *This = (IWineD3DDeviceImpl *)iface;
249     IWineD3DVertexBuffer     *oldSrc;
250
251     oldSrc = This->stateBlock->stream_source[StreamNumber];
252     TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
253
254     This->updateStateBlock->changed.stream_source[StreamNumber] = TRUE;
255     This->updateStateBlock->set.stream_source[StreamNumber]     = TRUE;
256     This->updateStateBlock->stream_stride[StreamNumber]         = Stride;
257     This->updateStateBlock->stream_source[StreamNumber]         = pStreamData;
258     This->updateStateBlock->stream_offset[StreamNumber]         = OffsetInBytes;
259
260     /* Handle recording of state blocks */
261     if (This->isRecordingState) {
262         TRACE("Recording... not performing anything\n");
263         return D3D_OK;
264     }
265
266     /* Not recording... */
267     if (oldSrc != NULL) IWineD3DVertexBuffer_Release(oldSrc);
268     if (pStreamData != NULL) IWineD3DVertexBuffer_AddRef(pStreamData);
269
270     return D3D_OK;
271 }
272
273 HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
274     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
275
276     TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber, This->stateBlock->stream_source[StreamNumber], This->stateBlock->stream_stride[StreamNumber]);
277     *pStream = This->stateBlock->stream_source[StreamNumber];
278     *pStride = This->stateBlock->stream_stride[StreamNumber];
279     *pOffset = This->stateBlock->stream_offset[StreamNumber];
280     IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
281     return D3D_OK;
282 }
283
284 /*****
285  * Get / Set & Multipy Transform
286  *****/
287 HRESULT  WINAPI  IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
288     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
289
290     /* Most of this routine, comments included copied from ddraw tree initially: */
291     TRACE("(%p) : Transform State=%d\n", This, d3dts);
292
293     /* Handle recording of state blocks */
294     if (This->isRecordingState) {
295         TRACE("Recording... not performing anything\n");
296         This->updateStateBlock->changed.transform[d3dts] = TRUE;
297         This->updateStateBlock->set.transform[d3dts]     = TRUE;
298         memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
299         return D3D_OK;
300     }
301
302     /*
303      * If the new matrix is the same as the current one,
304      * we cut off any further processing. this seems to be a reasonable
305      * optimization because as was noticed, some apps (warcraft3 for example)
306      * tend towards setting the same matrix repeatedly for some reason.
307      *
308      * From here on we assume that the new matrix is different, wherever it matters.
309      */
310     if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
311         TRACE("The app is setting the same matrix over again\n");
312         return D3D_OK;
313     } else {
314         conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
315     }
316
317     /*
318        ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
319        where ViewMat = Camera space, WorldMat = world space.
320
321        In OpenGL, camera and world space is combined into GL_MODELVIEW
322        matrix.  The Projection matrix stay projection matrix. 
323      */
324
325     /* Capture the times we can just ignore the change for now */
326     if (d3dts == D3DTS_WORLDMATRIX(0)) {
327         This->modelview_valid = FALSE;
328         return D3D_OK;
329
330     } else if (d3dts == D3DTS_PROJECTION) {
331         This->proj_valid = FALSE;
332         return D3D_OK;
333
334     } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) { 
335         /* Indexed Vertex Blending Matrices 256 -> 511  */
336         /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
337         FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
338         return D3D_OK;
339     } 
340     
341     /* Now we really are going to have to change a matrix */
342     ENTER_GL();
343
344     if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
345         if (d3dts < GL_LIMITS(textures)) {
346             int tex = d3dts - D3DTS_TEXTURE0;
347             GL_ACTIVETEXTURE(tex);
348 #if 0 /* TODO: */
349             set_texture_matrix((float *)lpmatrix, 
350                                This->updateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]);
351 #endif
352         }
353
354     } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
355         unsigned int k;
356
357         /* If we are changing the View matrix, reset the light and clipping planes to the new view   
358          * NOTE: We have to reset the positions even if the light/plane is not currently
359          *       enabled, since the call to enable it will not reset the position.                 
360          * NOTE2: Apparently texture transforms do NOT need reapplying
361          */
362         
363         PLIGHTINFOEL *lightChain = NULL;
364         This->modelview_valid = FALSE;
365         This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float));
366
367         glMatrixMode(GL_MODELVIEW);
368         checkGLcall("glMatrixMode(GL_MODELVIEW)");
369         glPushMatrix();
370         glLoadMatrixf((float *)lpmatrix);
371         checkGLcall("glLoadMatrixf(...)");
372
373         /* Reset lights */
374         lightChain = This->stateBlock->lights;
375         while (lightChain && lightChain->glIndex != -1) {
376             glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
377             checkGLcall("glLightfv posn");
378             glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
379             checkGLcall("glLightfv dirn");
380             lightChain = lightChain->next;
381         }
382
383         /* Reset Clipping Planes if clipping is enabled */
384         for (k = 0; k < GL_LIMITS(clipplanes); k++) {
385             glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
386             checkGLcall("glClipPlane");
387         }
388         glPopMatrix();
389
390     } else { /* What was requested!?? */
391         WARN("invalid matrix specified: %i\n", d3dts);
392     }
393
394     /* Release lock, all done */
395     LEAVE_GL();
396     return D3D_OK;
397
398 }
399 HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
400     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
401     TRACE("(%p) : for Transform State %d\n", This, State);
402     memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
403     return D3D_OK;
404 }
405
406 HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
407     D3DMATRIX *mat = NULL;
408     D3DMATRIX temp;
409
410     /* Note: Using 'updateStateBlock' rather then 'stateblock' in the code below
411         means it will be recorded in a state block change, but iworks regardless of recording being on. 
412         If this is found to be wrong, change to StateBlock.                             */
413     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
414     TRACE("(%p) : For state %u\n", This, State);
415
416     if (State < HIGHEST_TRANSFORMSTATE)
417     {
418         mat = &This->updateStateBlock->transforms[State];
419     } else {
420         FIXME("Unhandled transform state!!\n");
421     }
422
423     /* Copied from ddraw code:  */
424     temp.u.s._11 = (mat->u.s._11 * pMatrix->u.s._11) + (mat->u.s._21 * pMatrix->u.s._12) + (mat->u.s._31 * pMatrix->u.s._13) + (mat->u.s._41 * pMatrix->u.s._14);
425     temp.u.s._21 = (mat->u.s._11 * pMatrix->u.s._21) + (mat->u.s._21 * pMatrix->u.s._22) + (mat->u.s._31 * pMatrix->u.s._23) + (mat->u.s._41 * pMatrix->u.s._24);
426     temp.u.s._31 = (mat->u.s._11 * pMatrix->u.s._31) + (mat->u.s._21 * pMatrix->u.s._32) + (mat->u.s._31 * pMatrix->u.s._33) + (mat->u.s._41 * pMatrix->u.s._34);
427     temp.u.s._41 = (mat->u.s._11 * pMatrix->u.s._41) + (mat->u.s._21 * pMatrix->u.s._42) + (mat->u.s._31 * pMatrix->u.s._43) + (mat->u.s._41 * pMatrix->u.s._44);
428
429     temp.u.s._12 = (mat->u.s._12 * pMatrix->u.s._11) + (mat->u.s._22 * pMatrix->u.s._12) + (mat->u.s._32 * pMatrix->u.s._13) + (mat->u.s._42 * pMatrix->u.s._14);
430     temp.u.s._22 = (mat->u.s._12 * pMatrix->u.s._21) + (mat->u.s._22 * pMatrix->u.s._22) + (mat->u.s._32 * pMatrix->u.s._23) + (mat->u.s._42 * pMatrix->u.s._24);
431     temp.u.s._32 = (mat->u.s._12 * pMatrix->u.s._31) + (mat->u.s._22 * pMatrix->u.s._32) + (mat->u.s._32 * pMatrix->u.s._33) + (mat->u.s._42 * pMatrix->u.s._34);
432     temp.u.s._42 = (mat->u.s._12 * pMatrix->u.s._41) + (mat->u.s._22 * pMatrix->u.s._42) + (mat->u.s._32 * pMatrix->u.s._43) + (mat->u.s._42 * pMatrix->u.s._44);
433
434     temp.u.s._13 = (mat->u.s._13 * pMatrix->u.s._11) + (mat->u.s._23 * pMatrix->u.s._12) + (mat->u.s._33 * pMatrix->u.s._13) + (mat->u.s._43 * pMatrix->u.s._14);
435     temp.u.s._23 = (mat->u.s._13 * pMatrix->u.s._21) + (mat->u.s._23 * pMatrix->u.s._22) + (mat->u.s._33 * pMatrix->u.s._23) + (mat->u.s._43 * pMatrix->u.s._24);
436     temp.u.s._33 = (mat->u.s._13 * pMatrix->u.s._31) + (mat->u.s._23 * pMatrix->u.s._32) + (mat->u.s._33 * pMatrix->u.s._33) + (mat->u.s._43 * pMatrix->u.s._34);
437     temp.u.s._43 = (mat->u.s._13 * pMatrix->u.s._41) + (mat->u.s._23 * pMatrix->u.s._42) + (mat->u.s._33 * pMatrix->u.s._43) + (mat->u.s._43 * pMatrix->u.s._44);
438
439     temp.u.s._14 = (mat->u.s._14 * pMatrix->u.s._11) + (mat->u.s._24 * pMatrix->u.s._12) + (mat->u.s._34 * pMatrix->u.s._13) + (mat->u.s._44 * pMatrix->u.s._14);
440     temp.u.s._24 = (mat->u.s._14 * pMatrix->u.s._21) + (mat->u.s._24 * pMatrix->u.s._22) + (mat->u.s._34 * pMatrix->u.s._23) + (mat->u.s._44 * pMatrix->u.s._24);
441     temp.u.s._34 = (mat->u.s._14 * pMatrix->u.s._31) + (mat->u.s._24 * pMatrix->u.s._32) + (mat->u.s._34 * pMatrix->u.s._33) + (mat->u.s._44 * pMatrix->u.s._34);
442     temp.u.s._44 = (mat->u.s._14 * pMatrix->u.s._41) + (mat->u.s._24 * pMatrix->u.s._42) + (mat->u.s._34 * pMatrix->u.s._43) + (mat->u.s._44 * pMatrix->u.s._44);
443
444     /* Apply change via set transform - will reapply to eg. lights this way */
445     IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
446     return D3D_OK;
447 }
448
449 /*****
450  * Get / Set Light
451  *   WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
452  *****/
453 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
454    you can reference any indexes you want as long as that number max are enabled are any
455    one point in time! Therefore since the indexes can be anything, we need a linked list of them.
456    However, this causes stateblock problems. When capturing the state block, I duplicate the list,
457    but when recording, just build a chain pretty much of commands to be replayed.                  */
458    
459 HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
460     float rho;
461     PLIGHTINFOEL *object, *temp;
462
463     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
464     TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
465
466     /* If recording state block, just add to end of lights chain */
467     if (This->isRecordingState) {
468         object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
469         if (NULL == object) {
470             return D3DERR_OUTOFVIDEOMEMORY;
471         }
472         memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
473         object->OriginalIndex = Index;
474         object->glIndex = -1;
475         object->changed = TRUE;
476
477         /* Add to the END of the chain of lights changes to be replayed */
478         if (This->updateStateBlock->lights == NULL) {
479             This->updateStateBlock->lights = object;
480         } else {
481             temp = This->updateStateBlock->lights;
482             while (temp->next != NULL) temp=temp->next;
483             temp->next = object;
484         }
485         TRACE("Recording... not performing anything more\n");
486         return D3D_OK;
487     }
488
489     /* Ok, not recording any longer so do real work */
490     object = This->stateBlock->lights;
491     while (object != NULL && object->OriginalIndex != Index) object = object->next;
492
493     /* If we didn't find it in the list of lights, time to add it */
494     if (object == NULL) {
495         PLIGHTINFOEL *insertAt,*prevPos;
496
497         object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
498         if (NULL == object) {
499             return D3DERR_OUTOFVIDEOMEMORY;
500         }
501         object->OriginalIndex = Index;
502         object->glIndex = -1;
503
504         /* Add it to the front of list with the idea that lights will be changed as needed 
505            BUT after any lights currently assigned GL indexes                             */
506         insertAt = This->stateBlock->lights;
507         prevPos  = NULL;
508         while (insertAt != NULL && insertAt->glIndex != -1) {
509             prevPos  = insertAt;
510             insertAt = insertAt->next;
511         }
512
513         if (insertAt == NULL && prevPos == NULL) { /* Start of list */
514             This->stateBlock->lights = object;
515         } else if (insertAt == NULL) { /* End of list */
516             prevPos->next = object;
517             object->prev = prevPos;
518         } else { /* Middle of chain */
519             if (prevPos == NULL) {
520                 This->stateBlock->lights = object;
521             } else {
522                 prevPos->next = object;
523             }
524             object->prev = prevPos;
525             object->next = insertAt;
526             insertAt->prev = object;
527         }
528     }
529
530     /* Initialze the object */
531     TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
532           pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
533           pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
534           pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
535     TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
536           pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
537     TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
538
539     /* Save away the information */
540     memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
541
542     switch (pLight->Type) {
543     case D3DLIGHT_POINT:
544         /* Position */
545         object->lightPosn[0] = pLight->Position.x;
546         object->lightPosn[1] = pLight->Position.y;
547         object->lightPosn[2] = pLight->Position.z;
548         object->lightPosn[3] = 1.0f;
549         object->cutoff = 180.0f;
550         /* FIXME: Range */
551         break;
552
553     case D3DLIGHT_DIRECTIONAL:
554         /* Direction */
555         object->lightPosn[0] = -pLight->Direction.x;
556         object->lightPosn[1] = -pLight->Direction.y;
557         object->lightPosn[2] = -pLight->Direction.z;
558         object->lightPosn[3] = 0.0;
559         object->exponent     = 0.0f;
560         object->cutoff       = 180.0f;
561         break;
562
563     case D3DLIGHT_SPOT:
564         /* Position */
565         object->lightPosn[0] = pLight->Position.x;
566         object->lightPosn[1] = pLight->Position.y;
567         object->lightPosn[2] = pLight->Position.z;
568         object->lightPosn[3] = 1.0;
569
570         /* Direction */
571         object->lightDirn[0] = pLight->Direction.x;
572         object->lightDirn[1] = pLight->Direction.y;
573         object->lightDirn[2] = pLight->Direction.z;
574         object->lightDirn[3] = 1.0;
575
576         /*
577          * opengl-ish and d3d-ish spot lights use too different models for the
578          * light "intensity" as a function of the angle towards the main light direction,
579          * so we only can approximate very roughly.
580          * however spot lights are rather rarely used in games (if ever used at all).
581          * furthermore if still used, probably nobody pays attention to such details.
582          */
583         if (pLight->Falloff == 0) {
584             rho = 6.28f;
585         } else {
586             rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
587         }
588         if (rho < 0.0001) rho = 0.0001f;
589         object->exponent = -0.3/log(cos(rho/2));
590         object->cutoff = pLight->Phi*90/M_PI;
591
592         /* FIXME: Range */
593         break;
594
595     default:
596         FIXME("Unrecognized light type %d\n", pLight->Type);
597     }
598
599     /* Update the live definitions if the light is currently assigned a glIndex */
600     if (object->glIndex != -1) {
601         setup_light(iface, object->glIndex, object);
602     }
603     return D3D_OK;
604 }
605
606 HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
607     PLIGHTINFOEL *lightInfo = NULL;
608     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; 
609     TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
610     
611     /* Locate the light in the live lights */
612     lightInfo = This->stateBlock->lights;
613     while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
614
615     if (lightInfo == NULL) {
616         TRACE("Light information requested but light not defined\n");
617         return D3DERR_INVALIDCALL;
618     }
619
620     memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
621     return D3D_OK;
622 }
623
624 /*****
625  * Get / Set Light Enable 
626  *   (Note for consistency, renamed d3dx function by adding the 'set' prefix)
627  *****/
628 HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
629     PLIGHTINFOEL *lightInfo = NULL;
630     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
631     TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
632
633     /* If recording state block, just add to end of lights chain with changedEnable set to true */
634     if (This->isRecordingState) {
635         lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
636         if (NULL == lightInfo) {
637             return D3DERR_OUTOFVIDEOMEMORY;
638         }
639         lightInfo->OriginalIndex = Index;
640         lightInfo->glIndex = -1;
641         lightInfo->enabledChanged = TRUE;
642
643         /* Add to the END of the chain of lights changes to be replayed */
644         if (This->updateStateBlock->lights == NULL) {
645             This->updateStateBlock->lights = lightInfo;
646         } else {
647             PLIGHTINFOEL *temp = This->updateStateBlock->lights;
648             while (temp->next != NULL) temp=temp->next;
649             temp->next = lightInfo;
650         }
651         TRACE("Recording... not performing anything more\n");
652         return D3D_OK;
653     }
654
655     /* Not recording... So, locate the light in the live lights */
656     lightInfo = This->stateBlock->lights;
657     while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
658
659     /* Special case - enabling an undefined light creates one with a strict set of parms! */
660     if (lightInfo == NULL) {
661         D3DLIGHT9 lightParms;
662         /* Warning - untested code :-) Prob safe to change fixme to a trace but
663              wait until someone confirms it seems to work!                     */
664         TRACE("Light enabled requested but light not defined, so defining one!\n"); 
665         lightParms.Type = D3DLIGHT_DIRECTIONAL;
666         lightParms.Diffuse.r = 1.0;
667         lightParms.Diffuse.g = 1.0;
668         lightParms.Diffuse.b = 1.0;
669         lightParms.Diffuse.a = 0.0;
670         lightParms.Specular.r = 0.0;
671         lightParms.Specular.g = 0.0;
672         lightParms.Specular.b = 0.0;
673         lightParms.Specular.a = 0.0;
674         lightParms.Ambient.r = 0.0;
675         lightParms.Ambient.g = 0.0;
676         lightParms.Ambient.b = 0.0;
677         lightParms.Ambient.a = 0.0;
678         lightParms.Position.x = 0.0;
679         lightParms.Position.y = 0.0;
680         lightParms.Position.z = 0.0;
681         lightParms.Direction.x = 0.0;
682         lightParms.Direction.y = 0.0;
683         lightParms.Direction.z = 1.0;
684         lightParms.Range = 0.0;
685         lightParms.Falloff = 0.0;
686         lightParms.Attenuation0 = 0.0;
687         lightParms.Attenuation1 = 0.0;
688         lightParms.Attenuation2 = 0.0;
689         lightParms.Theta = 0.0;
690         lightParms.Phi = 0.0;
691         IWineD3DDeviceImpl_SetLight(iface, Index, &lightParms);
692
693         /* Search for it again! Should be fairly quick as near head of list */
694         lightInfo = This->stateBlock->lights;
695         while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
696         if (lightInfo == NULL) {
697             FIXME("Adding default lights has failed dismally\n");
698             return D3DERR_INVALIDCALL;
699         }
700     }
701
702     /* OK, we now have a light... */
703     if (Enable == FALSE) {
704
705         /* If we are disabling it, check it was enabled, and
706            still only do something if it has assigned a glIndex (which it should have!)   */
707         if ((lightInfo->lightEnabled == TRUE) && (lightInfo->glIndex != -1)) {
708             TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
709             ENTER_GL();
710             glDisable(GL_LIGHT0 + lightInfo->glIndex);
711             checkGLcall("glDisable GL_LIGHT0+Index");
712             LEAVE_GL();
713         } else {
714             TRACE("Nothing to do as light was not enabled\n");
715         }
716         lightInfo->lightEnabled = FALSE;
717     } else {
718
719         /* We are enabling it. If it is enabled, its really simple */
720         if (lightInfo->lightEnabled == TRUE) {
721             /* nop */
722             TRACE("Nothing to do as light was enabled\n");
723
724         /* If it already has a glIndex, its still simple */
725         } else if (lightInfo->glIndex != -1) {
726             TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
727             lightInfo->lightEnabled = TRUE;
728             ENTER_GL();
729             glEnable(GL_LIGHT0 + lightInfo->glIndex);
730             checkGLcall("glEnable GL_LIGHT0+Index already setup");
731             LEAVE_GL();
732
733         /* Otherwise got to find space - lights are ordered gl indexes first */
734         } else {
735             PLIGHTINFOEL *bsf  = NULL;
736             PLIGHTINFOEL *pos  = This->stateBlock->lights;
737             PLIGHTINFOEL *prev = NULL;
738             int           Index= 0;
739             int           glIndex = -1;
740
741             /* Try to minimize changes as much as possible */
742             while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
743
744                 /* Try to remember which index can be replaced if necessary */
745                 if (bsf==NULL && pos->lightEnabled == FALSE) {
746                     /* Found a light we can replace, save as best replacement */
747                     bsf = pos;
748                 }
749
750                 /* Step to next space */
751                 prev = pos;
752                 pos = pos->next;
753                 Index ++;
754             }
755
756             /* If we have too many active lights, fail the call */
757             if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
758                 FIXME("Program requests too many concurrent lights\n");
759                 return D3DERR_INVALIDCALL;
760
761             /* If we have allocated all lights, but not all are enabled,
762                reuse one which is not enabled                           */
763             } else if (Index == This->maxConcurrentLights) {
764                 /* use bsf - Simply swap the new light and the BSF one */
765                 PLIGHTINFOEL *bsfNext = bsf->next;
766                 PLIGHTINFOEL *bsfPrev = bsf->prev;
767
768                 /* Sort out ends */
769                 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
770                 if (bsf->prev != NULL) {
771                     bsf->prev->next = lightInfo;
772                 } else {
773                     This->stateBlock->lights = lightInfo;
774                 }
775
776                 /* If not side by side, lots of chains to update */
777                 if (bsf->next != lightInfo) {
778                     lightInfo->prev->next = bsf;
779                     bsf->next->prev = lightInfo;
780                     bsf->next       = lightInfo->next;
781                     bsf->prev       = lightInfo->prev;
782                     lightInfo->next = bsfNext;
783                     lightInfo->prev = bsfPrev;
784
785                 } else {
786                     /* Simple swaps */
787                     bsf->prev = lightInfo;
788                     bsf->next = lightInfo->next;
789                     lightInfo->next = bsf;
790                     lightInfo->prev = bsfPrev;
791                 }
792
793
794                 /* Update states */
795                 glIndex = bsf->glIndex;
796                 bsf->glIndex = -1;
797                 lightInfo->glIndex = glIndex;
798                 lightInfo->lightEnabled = TRUE;
799
800                 /* Finally set up the light in gl itself */
801                 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
802                 ENTER_GL();
803                 setup_light(iface, glIndex, lightInfo);
804                 glEnable(GL_LIGHT0 + glIndex);
805                 checkGLcall("glEnable GL_LIGHT0 new setup");
806                 LEAVE_GL();
807
808             /* If we reached the end of the allocated lights, with space in the
809                gl lights, setup a new light                                     */
810             } else if (pos->glIndex == -1) {
811
812                 /* We reached the end of the allocated gl lights, so already 
813                     know the index of the next one!                          */
814                 glIndex = Index;
815                 lightInfo->glIndex = glIndex;
816                 lightInfo->lightEnabled = TRUE;
817
818                 /* In an ideal world, its already in the right place */
819                 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
820                    /* No need to move it */
821                 } else {
822                     /* Remove this light from the list */
823                     lightInfo->prev->next = lightInfo->next;
824                     if (lightInfo->next != NULL) {
825                         lightInfo->next->prev = lightInfo->prev;
826                     }
827
828                     /* Add in at appropriate place (inbetween prev and pos) */
829                     lightInfo->prev = prev;
830                     lightInfo->next = pos;
831                     if (prev == NULL) {
832                         This->stateBlock->lights = lightInfo;
833                     } else {
834                         prev->next = lightInfo;
835                     }
836                     if (pos != NULL) {
837                         pos->prev = lightInfo;
838                     }
839                 }
840
841                 /* Finally set up the light in gl itself */
842                 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
843                 ENTER_GL();
844                 setup_light(iface, glIndex, lightInfo);
845                 glEnable(GL_LIGHT0 + glIndex);
846                 checkGLcall("glEnable GL_LIGHT0 new setup");
847                 LEAVE_GL();
848                 
849             }
850         }
851     }
852     return D3D_OK;
853 }
854
855 HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
856
857     PLIGHTINFOEL *lightInfo = NULL;
858     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; 
859     TRACE("(%p) : for idx(%ld)\n", This, Index);
860     
861     /* Locate the light in the live lights */
862     lightInfo = This->stateBlock->lights;
863     while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
864
865     if (lightInfo == NULL) {
866         TRACE("Light enabled state requested but light not defined\n");
867         return D3DERR_INVALIDCALL;
868     }
869     *pEnable = lightInfo->lightEnabled;
870     return D3D_OK;
871 }
872
873 /*****
874  * Get / Set Clip Planes
875  *****/
876 HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
877     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
878     TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
879
880     /* Validate Index */
881     if (Index >= GL_LIMITS(clipplanes)) {
882         TRACE("Application has requested clipplane this device doesn't support\n");
883         return D3DERR_INVALIDCALL;
884     }
885
886     This->updateStateBlock->changed.clipplane[Index] = TRUE;
887     This->updateStateBlock->set.clipplane[Index] = TRUE;
888     This->updateStateBlock->clipplane[Index][0] = pPlane[0];
889     This->updateStateBlock->clipplane[Index][1] = pPlane[1];
890     This->updateStateBlock->clipplane[Index][2] = pPlane[2];
891     This->updateStateBlock->clipplane[Index][3] = pPlane[3];
892
893     /* Handle recording of state blocks */
894     if (This->isRecordingState) {
895         TRACE("Recording... not performing anything\n");
896         return D3D_OK;
897     }
898
899     /* Apply it */
900
901     ENTER_GL();
902
903     /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
904     glMatrixMode(GL_MODELVIEW);
905     glPushMatrix();
906     glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
907
908     TRACE("Clipplane [%f,%f,%f,%f]\n", 
909           This->updateStateBlock->clipplane[Index][0], 
910           This->updateStateBlock->clipplane[Index][1],
911       This->updateStateBlock->clipplane[Index][2], 
912           This->updateStateBlock->clipplane[Index][3]);
913     glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
914     checkGLcall("glClipPlane");
915
916     glPopMatrix();
917     LEAVE_GL();
918
919     return D3D_OK;
920 }
921
922 HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
923     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
924     TRACE("(%p) : for idx %ld\n", This, Index);
925
926     /* Validate Index */
927     if (Index >= GL_LIMITS(clipplanes)) {
928         TRACE("Application has requested clipplane this device doesn't support\n");
929         return D3DERR_INVALIDCALL;
930     }
931
932     pPlane[0] = This->stateBlock->clipplane[Index][0];
933     pPlane[1] = This->stateBlock->clipplane[Index][1];
934     pPlane[2] = This->stateBlock->clipplane[Index][2];
935     pPlane[3] = This->stateBlock->clipplane[Index][3];
936     return D3D_OK;
937 }
938
939 /*****
940  * Get / Set Clip Plane Status
941  *   WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
942  *****/
943 HRESULT  WINAPI  IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
944     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
945     FIXME("(%p) : stub\n", This);
946     if (NULL == pClipStatus) {
947       return D3DERR_INVALIDCALL;
948     }
949     This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
950     This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
951     return D3D_OK;
952 }
953
954 HRESULT  WINAPI  IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
955     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
956     FIXME("(%p) : stub\n", This);    
957     if (NULL == pClipStatus) {
958       return D3DERR_INVALIDCALL;
959     }
960     pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
961     pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
962     return D3D_OK;
963 }
964
965 /*****
966  * Get / Set Material
967  *   WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
968  *****/
969 HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
970     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
971
972     This->updateStateBlock->changed.material = TRUE;
973     This->updateStateBlock->set.material = TRUE;
974     memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
975
976     /* Handle recording of state blocks */
977     if (This->isRecordingState) {
978         TRACE("Recording... not performing anything\n");
979         return D3D_OK;
980     }
981
982     ENTER_GL();
983     TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
984     TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
985     TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
986     TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
987     TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
988
989     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
990     checkGLcall("glMaterialfv");
991     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
992     checkGLcall("glMaterialfv");
993
994     /* Only change material color if specular is enabled, otherwise it is set to black */
995 #if 0 /* TODO */
996     if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
997        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular);
998        checkGLcall("glMaterialfv");
999     } else {
1000 #endif
1001     {
1002        float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1003        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
1004        checkGLcall("glMaterialfv");
1005     }
1006     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
1007     checkGLcall("glMaterialfv");
1008     glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
1009     checkGLcall("glMaterialf");
1010
1011     LEAVE_GL();
1012     return D3D_OK;
1013 }
1014
1015 HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
1016     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1017     memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
1018     TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, pMaterial->Diffuse.b, pMaterial->Diffuse.a);
1019     TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, pMaterial->Ambient.b, pMaterial->Ambient.a);
1020     TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, pMaterial->Specular.b, pMaterial->Specular.a);
1021     TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, pMaterial->Emissive.b, pMaterial->Emissive.a);
1022     TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
1023     return D3D_OK;
1024 }
1025
1026 /*****
1027  * Scene related functions
1028  *****/
1029 HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
1030     /* At the moment we have no need for any functionality at the beginning
1031        of a scene                                                          */
1032     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1033     TRACE("(%p) : stub\n", This);
1034     return D3D_OK;
1035 }
1036
1037 /**********************************************************
1038  * IUnknown parts follows
1039  **********************************************************/
1040
1041 HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
1042 {
1043     return E_NOINTERFACE;
1044 }
1045
1046 ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
1047     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048     TRACE("(%p) : AddRef increasing from %ld\n", This, This->ref);
1049     return InterlockedIncrement(&This->ref);
1050 }
1051
1052 ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
1053     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1054     ULONG ref;
1055     TRACE("(%p) : Releasing from %ld\n", This, This->ref);
1056     ref = InterlockedDecrement(&This->ref);
1057     if (ref == 0) {
1058         IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
1059         IWineD3D_Release(This->wineD3D);
1060         HeapFree(GetProcessHeap(), 0, This);
1061     }
1062     return ref;
1063 }
1064
1065 /**********************************************************
1066  * IWineD3DDevice VTbl follows
1067  **********************************************************/
1068
1069 IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
1070 {
1071     IWineD3DDeviceImpl_QueryInterface,
1072     IWineD3DDeviceImpl_AddRef,
1073     IWineD3DDeviceImpl_Release,
1074     IWineD3DDeviceImpl_GetParent,
1075     IWineD3DDeviceImpl_CreateVertexBuffer,
1076     IWineD3DDeviceImpl_CreateIndexBuffer,
1077     IWineD3DDeviceImpl_CreateStateBlock,
1078     IWineD3DDeviceImpl_SetFVF,
1079     IWineD3DDeviceImpl_GetFVF,
1080     IWineD3DDeviceImpl_SetStreamSource,
1081     IWineD3DDeviceImpl_GetStreamSource,
1082     IWineD3DDeviceImpl_SetTransform,
1083     IWineD3DDeviceImpl_GetTransform,
1084     IWineD3DDeviceImpl_MultiplyTransform,
1085     IWineD3DDeviceImpl_SetLight,
1086     IWineD3DDeviceImpl_GetLight,
1087     IWineD3DDeviceImpl_SetLightEnable,
1088     IWineD3DDeviceImpl_GetLightEnable,
1089     IWineD3DDeviceImpl_SetClipPlane,
1090     IWineD3DDeviceImpl_GetClipPlane,
1091     IWineD3DDeviceImpl_SetClipStatus,
1092     IWineD3DDeviceImpl_GetClipStatus,
1093     IWineD3DDeviceImpl_SetMaterial,
1094     IWineD3DDeviceImpl_GetMaterial,
1095     IWineD3DDeviceImpl_BeginScene
1096 };