2 * IWineD3DDevice implementation
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2003-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
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.
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.
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
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
28 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
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 */
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) {
42 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
43 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
45 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
46 glMatrixMode(GL_MODELVIEW);
48 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
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");
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");
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");
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");
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");
85 switch (lightInfo->OriginalParms.Type) {
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");
97 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
98 checkGLcall("glLightfv");
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");
109 case D3DLIGHT_DIRECTIONAL:
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");
120 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
123 /* Restore the modelview matrix */
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);
137 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
138 DWORD FVF, D3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
141 IWineD3DVertexBufferImpl *object;
142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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;
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;
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;
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;
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;
191 HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, D3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 IWineD3DStateBlockImpl *object;
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;
203 object->blockType = Type;
204 *ppStateBlock = (IWineD3DStateBlock *)object;
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 */
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");
224 HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
227 /* Update the current statte block */
228 This->updateStateBlock->fvf = fvf;
229 This->updateStateBlock->changed.fvf = TRUE;
230 This->updateStateBlock->set.fvf = TRUE;
232 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
234 /* No difference if recording or not */
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;
245 * Get / Set Stream Source
247 HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
249 IWineD3DVertexBuffer *oldSrc;
251 oldSrc = This->stateBlock->stream_source[StreamNumber];
252 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
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;
260 /* Handle recording of state blocks */
261 if (This->isRecordingState) {
262 TRACE("Recording... not performing anything\n");
266 /* Not recording... */
267 if (oldSrc != NULL) IWineD3DVertexBuffer_Release(oldSrc);
268 if (pStreamData != NULL) IWineD3DVertexBuffer_AddRef(pStreamData);
273 HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
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 */
285 * Get / Set & Multipy Transform
287 HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
290 /* Most of this routine, comments included copied from ddraw tree initially: */
291 TRACE("(%p) : Transform State=%d\n", This, d3dts);
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));
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.
308 * From here on we assume that the new matrix is different, wherever it matters.
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");
314 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
318 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
319 where ViewMat = Camera space, WorldMat = world space.
321 In OpenGL, camera and world space is combined into GL_MODELVIEW
322 matrix. The Projection matrix stay projection matrix.
325 /* Capture the times we can just ignore the change for now */
326 if (d3dts == D3DTS_WORLDMATRIX(0)) {
327 This->modelview_valid = FALSE;
330 } else if (d3dts == D3DTS_PROJECTION) {
331 This->proj_valid = FALSE;
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");
341 /* Now we really are going to have to change a matrix */
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);
349 set_texture_matrix((float *)lpmatrix,
350 This->updateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]);
354 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
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
363 PLIGHTINFOEL *lightChain = NULL;
364 This->modelview_valid = FALSE;
365 This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float));
367 glMatrixMode(GL_MODELVIEW);
368 checkGLcall("glMatrixMode(GL_MODELVIEW)");
370 glLoadMatrixf((float *)lpmatrix);
371 checkGLcall("glLoadMatrixf(...)");
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;
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");
390 } else { /* What was requested!?? */
391 WARN("invalid matrix specified: %i\n", d3dts);
394 /* Release lock, all done */
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));
406 HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
407 D3DMATRIX *mat = NULL;
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);
416 if (State < HIGHEST_TRANSFORMSTATE)
418 mat = &This->updateStateBlock->transforms[State];
420 FIXME("Unhandled transform state!!\n");
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);
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);
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);
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);
444 /* Apply change via set transform - will reapply to eg. lights this way */
445 IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
451 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
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. */
459 HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
461 PLIGHTINFOEL *object, *temp;
463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
464 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
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;
472 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
473 object->OriginalIndex = Index;
474 object->glIndex = -1;
475 object->changed = TRUE;
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;
481 temp = This->updateStateBlock->lights;
482 while (temp->next != NULL) temp=temp->next;
485 TRACE("Recording... not performing anything more\n");
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;
493 /* If we didn't find it in the list of lights, time to add it */
494 if (object == NULL) {
495 PLIGHTINFOEL *insertAt,*prevPos;
497 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
498 if (NULL == object) {
499 return D3DERR_OUTOFVIDEOMEMORY;
501 object->OriginalIndex = Index;
502 object->glIndex = -1;
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;
508 while (insertAt != NULL && insertAt->glIndex != -1) {
510 insertAt = insertAt->next;
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;
522 prevPos->next = object;
524 object->prev = prevPos;
525 object->next = insertAt;
526 insertAt->prev = object;
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);
539 /* Save away the information */
540 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
542 switch (pLight->Type) {
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;
553 case D3DLIGHT_DIRECTIONAL:
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;
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;
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;
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.
583 if (pLight->Falloff == 0) {
586 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
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;
596 FIXME("Unrecognized light type %d\n", pLight->Type);
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);
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);
611 /* Locate the light in the live lights */
612 lightInfo = This->stateBlock->lights;
613 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
615 if (lightInfo == NULL) {
616 TRACE("Light information requested but light not defined\n");
617 return D3DERR_INVALIDCALL;
620 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
625 * Get / Set Light Enable
626 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
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);
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;
639 lightInfo->OriginalIndex = Index;
640 lightInfo->glIndex = -1;
641 lightInfo->enabledChanged = TRUE;
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;
647 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
648 while (temp->next != NULL) temp=temp->next;
649 temp->next = lightInfo;
651 TRACE("Recording... not performing anything more\n");
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;
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);
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;
702 /* OK, we now have a light... */
703 if (Enable == FALSE) {
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);
710 glDisable(GL_LIGHT0 + lightInfo->glIndex);
711 checkGLcall("glDisable GL_LIGHT0+Index");
714 TRACE("Nothing to do as light was not enabled\n");
716 lightInfo->lightEnabled = FALSE;
719 /* We are enabling it. If it is enabled, its really simple */
720 if (lightInfo->lightEnabled == TRUE) {
722 TRACE("Nothing to do as light was enabled\n");
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;
729 glEnable(GL_LIGHT0 + lightInfo->glIndex);
730 checkGLcall("glEnable GL_LIGHT0+Index already setup");
733 /* Otherwise got to find space - lights are ordered gl indexes first */
735 PLIGHTINFOEL *bsf = NULL;
736 PLIGHTINFOEL *pos = This->stateBlock->lights;
737 PLIGHTINFOEL *prev = NULL;
741 /* Try to minimize changes as much as possible */
742 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
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 */
750 /* Step to next space */
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;
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;
769 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
770 if (bsf->prev != NULL) {
771 bsf->prev->next = lightInfo;
773 This->stateBlock->lights = lightInfo;
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;
787 bsf->prev = lightInfo;
788 bsf->next = lightInfo->next;
789 lightInfo->next = bsf;
790 lightInfo->prev = bsfPrev;
795 glIndex = bsf->glIndex;
797 lightInfo->glIndex = glIndex;
798 lightInfo->lightEnabled = TRUE;
800 /* Finally set up the light in gl itself */
801 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
803 setup_light(iface, glIndex, lightInfo);
804 glEnable(GL_LIGHT0 + glIndex);
805 checkGLcall("glEnable GL_LIGHT0 new setup");
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) {
812 /* We reached the end of the allocated gl lights, so already
813 know the index of the next one! */
815 lightInfo->glIndex = glIndex;
816 lightInfo->lightEnabled = TRUE;
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 */
822 /* Remove this light from the list */
823 lightInfo->prev->next = lightInfo->next;
824 if (lightInfo->next != NULL) {
825 lightInfo->next->prev = lightInfo->prev;
828 /* Add in at appropriate place (inbetween prev and pos) */
829 lightInfo->prev = prev;
830 lightInfo->next = pos;
832 This->stateBlock->lights = lightInfo;
834 prev->next = lightInfo;
837 pos->prev = lightInfo;
841 /* Finally set up the light in gl itself */
842 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
844 setup_light(iface, glIndex, lightInfo);
845 glEnable(GL_LIGHT0 + glIndex);
846 checkGLcall("glEnable GL_LIGHT0 new setup");
855 HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
857 PLIGHTINFOEL *lightInfo = NULL;
858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
859 TRACE("(%p) : for idx(%ld)\n", This, Index);
861 /* Locate the light in the live lights */
862 lightInfo = This->stateBlock->lights;
863 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
865 if (lightInfo == NULL) {
866 TRACE("Light enabled state requested but light not defined\n");
867 return D3DERR_INVALIDCALL;
869 *pEnable = lightInfo->lightEnabled;
874 * Get / Set Clip Planes
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);
881 if (Index >= GL_LIMITS(clipplanes)) {
882 TRACE("Application has requested clipplane this device doesn't support\n");
883 return D3DERR_INVALIDCALL;
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];
893 /* Handle recording of state blocks */
894 if (This->isRecordingState) {
895 TRACE("Recording... not performing anything\n");
903 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
904 glMatrixMode(GL_MODELVIEW);
906 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
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");
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);
927 if (Index >= GL_LIMITS(clipplanes)) {
928 TRACE("Application has requested clipplane this device doesn't support\n");
929 return D3DERR_INVALIDCALL;
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];
940 * Get / Set Clip Plane Status
941 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
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;
949 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
950 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
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;
960 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
961 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
967 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
969 HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
972 This->updateStateBlock->changed.material = TRUE;
973 This->updateStateBlock->set.material = TRUE;
974 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
976 /* Handle recording of state blocks */
977 if (This->isRecordingState) {
978 TRACE("Recording... not performing anything\n");
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);
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");
994 /* Only change material color if specular is enabled, otherwise it is set to black */
996 if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
997 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular);
998 checkGLcall("glMaterialfv");
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");
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");
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);
1027 * Scene related functions
1029 HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
1030 /* At the moment we have no need for any functionality at the beginning
1032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1033 TRACE("(%p) : stub\n", This);
1037 /**********************************************************
1038 * IUnknown parts follows
1039 **********************************************************/
1041 HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
1043 return E_NOINTERFACE;
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);
1052 ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
1053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 TRACE("(%p) : Releasing from %ld\n", This, This->ref);
1056 ref = InterlockedDecrement(&This->ref);
1058 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
1059 IWineD3D_Release(This->wineD3D);
1060 HeapFree(GetProcessHeap(), 0, This);
1065 /**********************************************************
1066 * IWineD3DDevice VTbl follows
1067 **********************************************************/
1069 IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
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