mscms: One more LastError code fixed.
[wine.git] / dlls / wined3d / device.c
blob04a2fe839c659e74bbedcd7727eee26580e843d9
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002-2005 Jason Edmeades
5 * Copyright 2003-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
25 #ifdef HAVE_FLOAT_H
26 # include <float.h>
27 #endif
28 #include "wined3d_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
31 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
33 /* x11drv GDI escapes */
34 #define X11DRV_ESCAPE 6789
35 enum x11drv_escape_codes
37 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
38 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
39 X11DRV_GET_FONT, /* get current X font for a DC */
42 /* retrieve the X display to use on a given DC */
43 inline static Display *get_display( HDC hdc )
45 Display *display;
46 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
48 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
49 sizeof(display), (LPSTR)&display )) display = NULL;
50 return display;
53 /* Memory tracking and object counting */
54 static unsigned int emulated_textureram = 64*1024*1024;
56 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
57 /* enable pbuffer support for offscreen textures */
58 BOOL pbuffer_support = FALSE;
59 /* allocate one pbuffer per surface */
60 BOOL pbuffer_per_surface = FALSE;
62 /* static function declarations */
63 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
65 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
67 /* helper macros */
68 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return D3DERR_OUTOFVIDEOMEMORY;}
70 #define D3DCREATEOBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->wineD3DDevice = This; \
75 object->parent = parent; \
76 object->ref = 1; \
77 *pp##type = (IWineD3D##type *) object; \
80 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->resource.wineD3DDevice = This; \
85 object->resource.parent = parent; \
86 object->resource.resourceType = d3dtype; \
87 object->resource.ref = 1; \
88 object->resource.pool = Pool; \
89 object->resource.format = Format; \
90 object->resource.usage = Usage; \
91 object->resource.size = _size; \
92 /* Check that we have enough video ram left */ \
93 if (Pool == D3DPOOL_DEFAULT) { \
94 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
95 WARN("Out of 'bogus' video memory\n"); \
96 HeapFree(GetProcessHeap(), 0, object); \
97 *pp##type = NULL; \
98 return D3DERR_OUTOFVIDEOMEMORY; \
99 } \
100 globalChangeGlRam(_size); \
102 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == D3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
103 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != D3DPOOL_DEFAULT) { \
104 FIXME("Out of memory!\n"); \
105 HeapFree(GetProcessHeap(), 0, object); \
106 *pp##type = NULL; \
107 return D3DERR_OUTOFVIDEOMEMORY; \
109 *pp##type = (IWineD3D##type *) object; \
110 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
111 TRACE("(%p) : Created resource %p\n", This, object); \
114 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
115 _basetexture.levels = Levels; \
116 _basetexture.filterType = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? D3DTEXF_LINEAR : D3DTEXF_NONE; \
117 _basetexture.LOD = 0; \
118 _basetexture.dirty = TRUE; \
121 /**********************************************************
122 * Global variable / Constants follow
123 **********************************************************/
124 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
126 /**********************************************************
127 * Utility functions follow
128 **********************************************************/
129 /* Convert the D3DLIGHT properties into equivalent gl lights */
130 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
132 float quad_att;
133 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
136 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
137 glMatrixMode(GL_MODELVIEW);
138 glPushMatrix();
139 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
141 /* Diffuse: */
142 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
143 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
144 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
145 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
146 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
147 checkGLcall("glLightfv");
149 /* Specular */
150 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
151 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
152 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
153 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
154 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
155 checkGLcall("glLightfv");
157 /* Ambient */
158 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
159 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
160 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
161 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
162 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
163 checkGLcall("glLightfv");
165 /* Attenuation - Are these right? guessing... */
166 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
167 checkGLcall("glLightf");
168 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
169 checkGLcall("glLightf");
171 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
172 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
173 } else {
174 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
177 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
178 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
179 checkGLcall("glLightf");
181 switch (lightInfo->OriginalParms.Type) {
182 case D3DLIGHT_POINT:
183 /* Position */
184 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
185 checkGLcall("glLightfv");
186 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
187 checkGLcall("glLightf");
188 /* FIXME: Range */
189 break;
191 case D3DLIGHT_SPOT:
192 /* Position */
193 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
194 checkGLcall("glLightfv");
195 /* Direction */
196 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
197 checkGLcall("glLightfv");
198 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
199 checkGLcall("glLightf");
200 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
201 checkGLcall("glLightf");
202 /* FIXME: Range */
203 break;
205 case D3DLIGHT_DIRECTIONAL:
206 /* Direction */
207 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
208 checkGLcall("glLightfv");
209 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
210 checkGLcall("glLightf");
211 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
212 checkGLcall("glLightf");
213 break;
215 default:
216 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
219 /* Restore the modelview matrix */
220 glPopMatrix();
223 /* Apply the current values to the specified texture stage */
224 void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD Flags) {
225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
226 float col[4];
228 union {
229 float f;
230 DWORD d;
231 } tmpvalue;
233 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
234 clamping, MIPLOD, etc. This will work for up to 16 samplers.
237 if (Sampler >= GL_LIMITS(samplers)) {
238 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(samplers));
239 return;
241 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
242 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
243 ENTER_GL();
244 GLACTIVETEXTURE(Sampler);
245 LEAVE_GL();
246 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
247 } else if (Sampler > 0) {
248 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
249 return;
252 /* TODO: change this to a lookup table
253 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
254 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
255 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
256 especially when there are a number of groups of states. */
258 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
260 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
261 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
262 /* these are the only two supported states that need to be applied */
263 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
264 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
265 #if 0 /* not supported at the moment */
266 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
267 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
268 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
269 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
270 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
271 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
272 APPLY_STATE(WINED3DTSS_RESULTARG);
273 APPLY_STATE(WINED3DTSS_CONSTANT);
274 #endif
275 /* a quick sanity check in case someone forgot to update this function */
276 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
277 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
279 #undef APPLY_STATE
281 /* apply any sampler states that always need applying */
282 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
283 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
284 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
285 GL_TEXTURE_LOD_BIAS_EXT,
286 tmpvalue.f);
287 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
290 /* Note the D3DRS value applies to all textures, but GL has one
291 * per texture, so apply it now ready to be used!
293 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
294 /* Set the default alpha blend color */
295 glBlendColor(col[0], col[1], col[2], col[3]);
296 checkGLcall("glBlendColor");
298 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
299 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
300 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
302 /* TODO: NV_POINT_SPRITE */
303 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
304 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
305 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
306 glDisable(GL_POINT_SMOOTH);
308 /* Centre the texture on the vertex */
309 VTRACE("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n");
310 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
312 VTRACE("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n");
313 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
314 checkGLcall("glTexEnvf(...)");
315 VTRACE("glEnable( GL_POINT_SPRITE_ARB )\n");
316 glEnable( GL_POINT_SPRITE_ARB );
317 checkGLcall("glEnable(...)");
318 } else {
319 VTRACE("glDisable( GL_POINT_SPRITE_ARB )\n");
320 glDisable( GL_POINT_SPRITE_ARB );
321 checkGLcall("glEnable(...)");
325 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
328 /**********************************************************
329 * IUnknown parts follows
330 **********************************************************/
332 HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
336 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
337 if (IsEqualGUID(riid, &IID_IUnknown)
338 || IsEqualGUID(riid, &IID_IWineD3DBase)
339 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
340 IUnknown_AddRef(iface);
341 *ppobj = This;
342 return D3D_OK;
345 return E_NOINTERFACE;
348 ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
350 ULONG refCount = InterlockedIncrement(&This->ref);
352 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
353 return refCount;
356 ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
358 ULONG refCount = InterlockedDecrement(&This->ref);
360 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
362 if (!refCount) {
363 /* TODO: Clean up all the surfaces and textures! */
364 /* FIXME: Create targets and state blocks in d3d8 */
365 if (((IWineD3DImpl *)This->wineD3D)->dxVersion > 8) { /*We don't create a state block in d3d8 yet*/
366 /* NOTE: You must release the parent if the object was created via a callback
367 ** ***************************/
368 /* TODO: this is exactly the same as required by _Reset.., so at some point we need to move the code so that is can be called by reset add release... */
369 /* Release all of the swapchains, except the implicit swapchain */
370 IUnknown* stencilBufferParent;
371 IUnknown* swapChainParent;
373 /* NOTE: Don't release swapchain 0 here, it's 'special' */
374 SwapChainList *nextSwapchain = This->swapchains;
375 if (nextSwapchain != NULL) {
376 nextSwapchain = nextSwapchain->next;
377 } else {
378 WARN("Expected to find the implicit swapchain\n");
381 /* release all the other swapchains */
382 while (nextSwapchain != NULL) {
383 SwapChainList *prevSwapchain = nextSwapchain;
384 nextSwapchain = nextSwapchain->next;
385 IWineD3DSwapChain_Release(prevSwapchain->swapchain);
386 /* NOTE: no need to free the list element, it will be done by the release callback
387 HeapFree(GetProcessHeap(), 0, prevSwapchain); */
389 /* Release the buffers (with sanity checks)*/
390 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
391 if(This->depthStencilBuffer != This->stencilBufferTarget)
392 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
394 This->stencilBufferTarget = NULL;
396 if(IWineD3DSurface_Release(This->renderTarget) >0){
397 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
399 This->renderTarget = NULL;
401 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
402 IUnknown_Release(stencilBufferParent); /* once for the get parent */
403 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
404 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
406 This->depthStencilBuffer = NULL;
408 /* Release the update stateblock */
409 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
410 if(This->updateStateBlock != This->stateBlock)
411 FIXME("(%p) Something's still holding the Update stateblock\n",This);
413 This->updateStateBlock = NULL;
414 { /* because were not doing proper internal refcounts releasing the primary state block
415 causes recursion with the extra checks in ResourceReleased, to avoid this we have
416 to set this->stateBlock = NULL; first */
417 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
418 This->stateBlock = NULL;
420 /* Release the stateblock */
421 if(IWineD3DStateBlock_Release(stateBlock) > 0){
422 FIXME("(%p) Something's still holding the Update stateblock\n",This);
426 if (This->swapchains != NULL) {
427 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
428 IWineD3DSwapChain_GetParent(This->swapchains->swapchain, &swapChainParent);
429 IUnknown_Release(swapChainParent); /* once for the get parent */
430 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
431 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
435 if (This->resources != NULL ) {
436 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
438 #if 0 /* TODO: Dump a list of all the resources still bound */
439 dumpResources(This->resources);
440 #endif
441 /* TODO: set the resources to a lost state */
445 IWineD3D_Release(This->wineD3D);
446 This->wineD3D = NULL;
447 HeapFree(GetProcessHeap(), 0, This);
448 TRACE("Freed device %p\n", This);
449 This = NULL;
451 return refCount;
454 /**********************************************************
455 * IWineD3DDevice implementation follows
456 **********************************************************/
457 HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
459 *pParent = This->parent;
460 IUnknown_AddRef(This->parent);
461 return D3D_OK;
464 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
465 DWORD FVF, D3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
466 IUnknown *parent) {
467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
468 IWineD3DVertexBufferImpl *object;
469 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
470 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, D3DRTYPE_VERTEXBUFFER, Size)
472 /*TODO: use VBO's */
473 if (Pool == D3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
474 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
476 object->fvf = FVF;
478 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
479 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
481 return D3D_OK;
484 HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
485 WINED3DFORMAT Format, D3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
486 HANDLE *sharedHandle, IUnknown *parent) {
487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
488 IWineD3DIndexBufferImpl *object;
489 TRACE("(%p) Creating index buffer\n", This);
491 /* Allocate the storage for the device */
492 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,D3DRTYPE_INDEXBUFFER, Length)
494 /*TODO: use VBO's */
495 if (Pool == D3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
496 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
499 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
500 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
501 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
503 return D3D_OK;
506 HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 IWineD3DStateBlockImpl *object;
510 int i, j;
512 D3DCREATEOBJECTINSTANCE(object, StateBlock)
513 object->blockType = Type;
515 /* Special case - Used during initialization to produce a placeholder stateblock
516 so other functions called can update a state block */
517 if (Type == WINED3DSBT_INIT) {
518 /* Don't bother increasing the reference count otherwise a device will never
519 be freed due to circular dependencies */
520 return D3D_OK;
523 /* Otherwise, might as well set the whole state block to the appropriate values */
524 if ( This->stateBlock != NULL) {
525 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
526 } else {
527 memset(object->streamFreq, 1, sizeof(object->streamFreq));
530 /* Reset the ref and type after kludging it */
531 object->wineD3DDevice = This;
532 object->ref = 1;
533 object->blockType = Type;
535 TRACE("Updating changed flags appropriate for type %d\n", Type);
537 if (Type == WINED3DSBT_ALL) {
539 TRACE("ALL => Pretend everything has changed\n");
540 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
541 } else if (Type == WINED3DSBT_PIXELSTATE) {
543 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
544 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
546 object->changed.pixelShader = TRUE;
548 /* Pixel Shader Constants */
549 for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
550 object->changed.pixelShaderConstants[i] = TRUE;
552 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
553 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
555 for (j = 0; j < GL_LIMITS(textures); j++) {
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
557 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
560 for (j = 0 ; j < 16; j++) {
561 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
563 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
567 } else if (Type == WINED3DSBT_VERTEXSTATE) {
569 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
570 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
572 object->changed.vertexShader = TRUE;
574 /* Vertex Shader Constants */
575 for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
576 object->changed.vertexShaderConstants[i] = TRUE;
578 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
579 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
581 for (j = 0; j < GL_LIMITS(textures); j++) {
582 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
583 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
586 for (j = 0 ; j < 16; j++){
587 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
588 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
592 /* Duplicate light chain */
594 PLIGHTINFOEL *src = NULL;
595 PLIGHTINFOEL *dst = NULL;
596 PLIGHTINFOEL *newEl = NULL;
597 src = This->stateBlock->lights;
598 object->lights = NULL;
601 while (src) {
602 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
603 if (newEl == NULL) return D3DERR_OUTOFVIDEOMEMORY;
604 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
605 newEl->prev = dst;
606 newEl->changed = TRUE;
607 newEl->enabledChanged = TRUE;
608 if (dst == NULL) {
609 object->lights = newEl;
610 } else {
611 dst->next = newEl;
613 dst = newEl;
614 src = src->next;
619 } else {
620 FIXME("Unrecognized state block type %d\n", Type);
623 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
624 return D3D_OK;
628 /* ************************************
629 MSDN:
630 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
632 Discard
633 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
635 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
637 ******************************** */
639 HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,D3DRESOURCETYPE Type, DWORD Usage, D3DPOOL Pool, D3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, IUnknown *parent) {
640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
641 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
642 unsigned int pow2Width, pow2Height;
643 unsigned int Size = 1;
644 TRACE("(%p) Create surface\n",This);
646 /** FIXME: Check ranges on the inputs are valid
647 * MSDN
648 * MultisampleQuality
649 * [in] Quality level. The valid range is between zero and one less than the level
650 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
651 * Passing a larger value returns the error D3DERR_INVALIDCALL. The MultisampleQuality
652 * values of paired render targets, depth stencil surfaces, and the MultiSample type
653 * must all match.
654 *******************************/
658 * TODO: Discard MSDN
659 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
661 * If this flag is set, the contents of the depth stencil buffer will be
662 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
663 * with a different depth surface.
665 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
666 ***************************/
668 if(MultisampleQuality < 0) {
669 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
670 return D3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
673 if(MultisampleQuality > 0) {
674 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
675 MultisampleQuality=0;
678 /** FIXME: Check that the format is supported
679 * by the device.
680 *******************************/
682 /* Non-power2 support */
684 /* Find the nearest pow2 match */
685 pow2Width = pow2Height = 1;
686 while (pow2Width < Width) pow2Width <<= 1;
687 while (pow2Height < Height) pow2Height <<= 1;
689 if (pow2Width > Width || pow2Height > Height) {
690 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
691 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
692 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
693 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
694 This, Width, Height);
695 return D3DERR_NOTAVAILABLE;
699 /** Check against the maximum texture sizes supported by the video card **/
700 if (pow2Width > GL_LIMITS(texture_size) || pow2Height > GL_LIMITS(texture_size)) {
701 /* one of three options
702 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
703 2: Set the texture to the maxium size (bad idea)
704 3: WARN and return D3DERR_NOTAVAILABLE;
706 WARN("(%p) Application requested a surface w %d, h %d, but the graphics card only supports %d\n", This, Width, Height, GL_LIMITS(texture_size));
707 return D3DERR_NOTAVAILABLE;
712 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
713 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
714 * space!
715 *********************************/
716 if (WINED3DFMT_UNKNOWN == Format) {
717 Size = 0;
718 } else if (Format == WINED3DFMT_DXT1) {
719 /* DXT1 is half byte per pixel */
720 Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4)) >> 1;
722 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
723 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
724 Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4));
725 } else {
726 Size = (pow2Width * D3DFmtGetBpp(This, Format)) * pow2Height;
729 /** Create and initialise the surface resource **/
730 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,D3DRTYPE_SURFACE, Size)
731 /* "Standalone" surface */
732 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
734 object->currentDesc.Width = Width;
735 object->currentDesc.Height = Height;
736 object->currentDesc.MultiSampleType = MultiSample;
737 object->currentDesc.MultiSampleQuality = MultisampleQuality;
739 /* Setup some glformat defaults */
740 if (WINED3DFMT_UNKNOWN != Format) {
741 object->glDescription.glFormat = D3DFmt2GLFmt(This, object->resource.format);
742 object->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This, object->resource.format);
743 object->glDescription.glType = D3DFmt2GLType(This, object->resource.format);
744 } else {
745 object->glDescription.glFormat = 0;
746 object->glDescription.glFormatInternal = 0;
747 object->glDescription.glType = 0;
750 object->glDescription.textureName = 0;
751 object->glDescription.level = Level;
752 object->glDescription.target = GL_TEXTURE_2D;
754 /* Internal data */
755 object->pow2Width = pow2Width;
756 object->pow2Height = pow2Height;
757 object->nonpow2 = (pow2Width != Width || pow2Height != Height) ? TRUE : FALSE;
758 object->discard = Discard;
759 object->activeLock = FALSE;
761 if (WINED3DFMT_UNKNOWN != Format) {
762 object->bytesPerPixel = D3DFmtGetBpp(This, Format);
763 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
764 } else {
765 object->bytesPerPixel = 0;
766 object->pow2Size = 0;
769 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
771 TRACE("Pool %d %d %d %d",Pool, D3DPOOL_DEFAULT, D3DPOOL_MANAGED, D3DPOOL_SYSTEMMEM);
773 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
774 * this function is too deap to need to care about things like this.
775 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
776 * ****************************************/
777 switch(Pool) {
778 case D3DPOOL_SCRATCH:
779 if(Lockable == FALSE)
780 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
781 which are mutually exclusive, setting lockable to true\n");
782 Lockable = TRUE;
783 break;
784 case D3DPOOL_SYSTEMMEM:
785 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
786 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
787 case D3DPOOL_MANAGED:
788 if(Usage == D3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
789 Usage of DYNAMIC which are mutually exclusive, not doing \
790 anything just telling you.\n");
791 break;
792 case D3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
793 if(!(Usage & D3DUSAGE_DYNAMIC) && !(Usage & D3DUSAGE_RENDERTARGET)
794 && !(Usage && D3DUSAGE_DEPTHSTENCIL ) && Lockable == TRUE)
795 FIXME("Creating a surface with a POOL of DEFAULT with Locable true, that doesn't specify DYNAMIC usage.\n");
796 break;
797 default:
798 FIXME("(%p) Unknown pool %d\n", This, Pool);
799 break;
802 if (Usage & D3DUSAGE_RENDERTARGET && Pool != D3DPOOL_DEFAULT) {
803 FIXME("Trying to create a render target that isn't in the default pool\n");
807 object->locked = FALSE;
808 object->lockable = (WINED3DFMT_D16_LOCKABLE == Format) ? TRUE : Lockable;
810 /* mark the texture as dirty so that it get's loaded first time around*/
811 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
812 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
813 This, Width, Height, Format, debug_d3dformat(Format),
814 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
815 return D3D_OK;
819 HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
820 DWORD Usage, WINED3DFORMAT Format, D3DPOOL Pool,
821 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
822 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
825 IWineD3DTextureImpl *object;
826 unsigned int i;
827 UINT tmpW;
828 UINT tmpH;
829 HRESULT hr;
830 unsigned int pow2Width = Width;
831 unsigned int pow2Height = Height;
834 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
836 /* TODO: It should only be possible to create textures for formats
837 that are reported as supported */
838 if (WINED3DFMT_UNKNOWN >= Format) {
839 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
840 return D3DERR_INVALIDCALL;
843 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, D3DRTYPE_TEXTURE, 0);
844 D3DINITIALIZEBASETEXTURE(object->baseTexture);
845 object->width = Width;
846 object->height = Height;
848 /** Non-power2 support **/
849 /* Find the nearest pow2 match */
850 pow2Width = pow2Height = 1;
851 while (pow2Width < Width) pow2Width <<= 1;
852 while (pow2Height < Height) pow2Height <<= 1;
854 /** FIXME: add support for real non-power-two if it's provided by the video card **/
855 /* Precalculated scaling for 'faked' non power of two texture coords */
856 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
857 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
858 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
860 /* Calculate levels for mip mapping */
861 if (Levels == 0) {
862 TRACE("calculating levels %d\n", object->baseTexture.levels);
863 object->baseTexture.levels++;
864 tmpW = Width;
865 tmpH = Height;
866 while (tmpW > 1 && tmpH > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 object->baseTexture.levels++;
871 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
874 /* Generate all the surfaces */
875 tmpW = Width;
876 tmpH = Height;
877 for (i = 0; i < object->baseTexture.levels; i++)
879 /* use the callback to create the texture surface */
880 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
881 if (hr!= D3D_OK) {
882 int j;
883 FIXME("Failed to create surface %p\n", object);
884 /* clean up */
885 for (j = 0 ; j < i ; j++) {
886 IWineD3DSurface_Release(object->surfaces[j]);
888 /* heap free object */
889 HeapFree(GetProcessHeap(), 0, object);
891 *ppTexture = NULL;
892 return hr;
895 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
896 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
897 /* calculate the next mipmap level */
898 tmpW = max(1, tmpW >> 1);
899 tmpH = max(1, tmpH >> 1);
902 TRACE("(%p) : Created texture %p\n", This, object);
903 return D3D_OK;
906 HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
907 UINT Width, UINT Height, UINT Depth,
908 UINT Levels, DWORD Usage,
909 WINED3DFORMAT Format, D3DPOOL Pool,
910 IWineD3DVolumeTexture **ppVolumeTexture,
911 HANDLE *pSharedHandle, IUnknown *parent,
912 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
915 IWineD3DVolumeTextureImpl *object;
916 unsigned int i;
917 UINT tmpW;
918 UINT tmpH;
919 UINT tmpD;
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN >= Format) {
924 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
925 return D3DERR_INVALIDCALL;
928 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, D3DRTYPE_VOLUMETEXTURE, 0);
929 D3DINITIALIZEBASETEXTURE(object->baseTexture);
931 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
932 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
934 object->width = Width;
935 object->height = Height;
936 object->depth = Depth;
938 /* Calculate levels for mip mapping */
939 if (Levels == 0) {
940 object->baseTexture.levels++;
941 tmpW = Width;
942 tmpH = Height;
943 tmpD = Depth;
944 while (tmpW > 1 && tmpH > 1 && tmpD > 1) {
945 tmpW = max(1, tmpW >> 1);
946 tmpH = max(1, tmpH >> 1);
947 tmpD = max(1, tmpD >> 1);
948 object->baseTexture.levels++;
950 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
953 /* Generate all the surfaces */
954 tmpW = Width;
955 tmpH = Height;
956 tmpD = Depth;
958 for (i = 0; i < object->baseTexture.levels; i++)
960 /* Create the volume */
961 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
962 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
964 /* Set it's container to this object */
965 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
967 /* calcualte the next mipmap level */
968 tmpW = max(1, tmpW >> 1);
969 tmpH = max(1, tmpH >> 1);
970 tmpD = max(1, tmpD >> 1);
973 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
974 TRACE("(%p) : Created volume texture %p\n", This, object);
975 return D3D_OK;
978 HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
979 UINT Width, UINT Height, UINT Depth,
980 DWORD Usage,
981 WINED3DFORMAT Format, D3DPOOL Pool,
982 IWineD3DVolume** ppVolume,
983 HANDLE* pSharedHandle, IUnknown *parent) {
985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
986 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
988 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, D3DRTYPE_VOLUME, ((Width * D3DFmtGetBpp(This, Format)) * Height * Depth))
990 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
991 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
993 object->currentDesc.Width = Width;
994 object->currentDesc.Height = Height;
995 object->currentDesc.Depth = Depth;
996 object->bytesPerPixel = D3DFmtGetBpp(This, Format);
998 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
999 object->lockable = TRUE;
1000 object->locked = FALSE;
1001 memset(&object->lockedBox, 0, sizeof(D3DBOX));
1002 object->dirty = TRUE;
1004 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1007 HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1008 UINT Levels, DWORD Usage,
1009 WINED3DFORMAT Format, D3DPOOL Pool,
1010 IWineD3DCubeTexture **ppCubeTexture,
1011 HANDLE *pSharedHandle, IUnknown *parent,
1012 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1015 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1016 unsigned int i, j;
1017 UINT tmpW;
1018 HRESULT hr;
1019 unsigned int pow2EdgeLength = EdgeLength;
1021 /* TODO: It should only be possible to create textures for formats
1022 that are reported as supported */
1023 if (WINED3DFMT_UNKNOWN >= Format) {
1024 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1025 return D3DERR_INVALIDCALL;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, D3DRTYPE_CUBETEXTURE, 0);
1029 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1031 TRACE("(%p) Create Cube Texture\n", This);
1033 /** Non-power2 support **/
1035 /* Find the nearest pow2 match */
1036 pow2EdgeLength = 1;
1037 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1039 object->edgeLength = EdgeLength;
1040 /* TODO: support for native non-power 2 */
1041 /* Precalculated scaling for 'faked' non power of two texture coords */
1042 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1044 /* Calculate levels for mip mapping */
1045 if (Levels == 0) {
1046 object->baseTexture.levels++;
1047 tmpW = EdgeLength;
1048 while (tmpW > 1) {
1049 tmpW = max(1, tmpW >> 1);
1050 object->baseTexture.levels++;
1052 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1055 /* Generate all the surfaces */
1056 tmpW = EdgeLength;
1057 for (i = 0; i < object->baseTexture.levels; i++) {
1059 /* Create the 6 faces */
1060 for (j = 0; j < 6; j++) {
1062 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1063 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1065 if(hr!= D3D_OK) {
1066 /* clean up */
1067 int k;
1068 int l;
1069 for (l = 0; l < j; l++) {
1070 IWineD3DSurface_Release(object->surfaces[j][i]);
1072 for (k = 0; k < i; k++) {
1073 for (l = 0; l < 6; l++) {
1074 IWineD3DSurface_Release(object->surfaces[l][j]);
1078 FIXME("(%p) Failed to create surface\n",object);
1079 HeapFree(GetProcessHeap(),0,object);
1080 *ppCubeTexture = NULL;
1081 return hr;
1083 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1084 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1086 tmpW = max(1, tmpW >> 1);
1089 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1090 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1091 return D3D_OK;
1094 HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1096 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1098 if (NULL == ppQuery) {
1099 /* Just a check to see if we support this type of query */
1100 HRESULT hr = D3DERR_NOTAVAILABLE;
1101 switch(Type) {
1102 case WINED3DQUERYTYPE_OCCLUSION:
1103 TRACE("(%p) occlusion query\n", This);
1104 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1105 hr = D3D_OK;
1106 else
1107 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1108 break;
1109 case WINED3DQUERYTYPE_VCACHE:
1110 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1111 case WINED3DQUERYTYPE_VERTEXSTATS:
1112 case WINED3DQUERYTYPE_EVENT:
1113 case WINED3DQUERYTYPE_TIMESTAMP:
1114 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1115 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1116 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1117 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1118 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1119 case WINED3DQUERYTYPE_PIXELTIMINGS:
1120 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1121 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1122 default:
1123 FIXME("(%p) Unhandled query type %d\n", This, Type);
1125 return hr;
1128 D3DCREATEOBJECTINSTANCE(object, Query)
1129 object->type = Type;
1130 /* allocated the 'extended' data based on the type of query requested */
1131 switch(Type){
1132 case D3DQUERYTYPE_OCCLUSION:
1133 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1134 TRACE("(%p) Allocating data for an occlusion query\n", This);
1135 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1136 break;
1138 case D3DQUERYTYPE_VCACHE:
1139 case D3DQUERYTYPE_RESOURCEMANAGER:
1140 case D3DQUERYTYPE_VERTEXSTATS:
1141 case D3DQUERYTYPE_EVENT:
1142 case D3DQUERYTYPE_TIMESTAMP:
1143 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1144 case D3DQUERYTYPE_TIMESTAMPFREQ:
1145 case D3DQUERYTYPE_PIPELINETIMINGS:
1146 case D3DQUERYTYPE_INTERFACETIMINGS:
1147 case D3DQUERYTYPE_VERTEXTIMINGS:
1148 case D3DQUERYTYPE_PIXELTIMINGS:
1149 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1150 case D3DQUERYTYPE_CACHEUTILIZATION:
1151 default:
1152 object->extendedData = 0;
1153 FIXME("(%p) Unhandled query type %d\n",This , Type);
1155 TRACE("(%p) : Created Query %p\n", This, object);
1156 return D3D_OK;
1159 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1160 HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1161 IUnknown* parent,
1162 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1163 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1166 HDC hDc;
1167 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1168 int num;
1169 XVisualInfo template;
1170 GLXContext oldContext;
1171 Drawable oldDrawable;
1172 HRESULT hr = D3D_OK;
1174 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1176 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1177 * does a device hold a reference to a swap chain giving them a lifetime of the device
1178 * or does the swap chain notify the device of its destruction.
1179 *******************************/
1181 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1183 /* Initialize other useful values */
1184 object->presentParms.BackBufferCount = 1; /* TODO:? support for gl_aux buffers */
1186 /*********************
1187 * Lookup the window Handle and the relating X window handle
1188 ********************/
1190 /* Setup hwnd we are using, plus which display this equates to */
1191 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1192 if (!object->win_handle) {
1193 object->win_handle = This->createParms.hFocusWindow;
1196 object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window" );
1197 hDc = GetDC(object->win_handle);
1198 object->display = get_display(hDc);
1199 ReleaseDC(object->win_handle, hDc);
1200 TRACE("Using a display of %p %p\n", object->display, hDc);
1202 if (NULL == object->display || NULL == hDc) {
1203 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1204 return D3DERR_NOTAVAILABLE;
1207 if (object->win == 0) {
1208 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1209 return D3DERR_NOTAVAILABLE;
1212 * Create an opengl context for the display visual
1213 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1214 * use different properties after that point in time. FIXME: How to handle when requested format
1215 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1216 * it chooses is identical to the one already being used!
1217 **********************************/
1219 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1220 ENTER_GL();
1222 /* Create a new context for this swapchain */
1223 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1224 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1225 (or the best possible if none is requested) */
1226 TRACE("Found x visual ID : %ld\n", template.visualid);
1228 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1229 if (NULL == object->visInfo) {
1230 ERR("cannot really get XVisual\n");
1231 LEAVE_GL();
1232 return D3DERR_NOTAVAILABLE;
1233 } else {
1234 int n, value;
1235 /* Write out some debug info about the visual/s */
1236 TRACE("Using x visual ID : %ld\n", template.visualid);
1237 TRACE(" visual info: %p\n", object->visInfo);
1238 TRACE(" num items : %d\n", num);
1239 for (n = 0;n < num; n++) {
1240 TRACE("=====item=====: %d\n", n + 1);
1241 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1242 TRACE(" screen : %d\n", object->visInfo[n].screen);
1243 TRACE(" depth : %u\n", object->visInfo[n].depth);
1244 TRACE(" class : %d\n", object->visInfo[n].class);
1245 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1246 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1247 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1248 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1249 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1250 /* log some extra glx info */
1251 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1252 TRACE(" gl_aux_buffers : %d\n", value);
1253 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1254 TRACE(" gl_buffer_size : %d\n", value);
1255 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1256 TRACE(" gl_red_size : %d\n", value);
1257 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1258 TRACE(" gl_green_size : %d\n", value);
1259 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1260 TRACE(" gl_blue_size : %d\n", value);
1261 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1262 TRACE(" gl_alpha_size : %d\n", value);
1263 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1264 TRACE(" gl_depth_size : %d\n", value);
1265 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1266 TRACE(" gl_stencil_size : %d\n", value);
1268 /* Now choose a simila visual ID*/
1270 #ifdef USE_CONTEXT_MANAGER
1272 /** TODO: use a context mamager **/
1273 #endif
1276 IWineD3DSwapChain *implSwapChain;
1277 if (D3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1278 /* The first time around we create the context that is shared with all other swapchains and render targets */
1279 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1280 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1281 } else {
1283 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1284 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1285 /* and create a new context with the implicit swapchains context as the shared context */
1286 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1287 IWineD3DSwapChain_Release(implSwapChain);
1291 /* Cleanup */
1292 XFree(object->visInfo);
1293 object->visInfo = NULL;
1295 if (NULL == object->glCtx) {
1296 ERR("cannot create glxContext\n");
1297 LEAVE_GL();
1298 return D3DERR_NOTAVAILABLE;
1301 LEAVE_GL();
1302 if (object->glCtx == NULL) {
1303 ERR("Error in context creation !\n");
1304 return D3DERR_INVALIDCALL;
1305 } else {
1306 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1307 object->win_handle, object->glCtx, object->win, object->visInfo);
1310 /*********************
1311 * Windowed / Fullscreen
1312 *******************/
1315 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1316 * so we should really check to see if there is a fullscreen swapchain already
1317 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1318 **************************************/
1320 if (!*(pPresentationParameters->Windowed)) {
1322 DEVMODEW devmode;
1323 HDC hdc;
1324 int bpp = 0;
1326 /* Get info on the current display setup */
1327 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1328 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1329 DeleteDC(hdc);
1331 /* Change the display settings */
1332 memset(&devmode, 0, sizeof(DEVMODEW));
1333 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1334 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1335 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1336 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1337 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1338 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1340 /* Make popup window */
1341 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1342 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1343 *(pPresentationParameters->BackBufferWidth),
1344 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1350 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1351 * then the corresponding dimension of the client area of the hDeviceWindow
1352 * (or the focus window, if hDeviceWindow is NULL) is taken.
1353 **********************/
1355 if (*(pPresentationParameters->Windowed) &&
1356 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1357 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1359 RECT Rect;
1360 GetClientRect(object->win_handle, &Rect);
1362 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1363 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1364 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1366 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1367 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1368 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1372 /*********************
1373 * finish off parameter initialization
1374 *******************/
1376 /* Put the correct figures in the presentation parameters */
1377 TRACE("Coppying accross presentaion paraneters\n");
1378 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1379 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1380 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1381 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1382 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1383 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1384 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1385 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1386 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1387 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1388 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1389 object->presentParms.Flags = *(pPresentationParameters->Flags);
1390 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1391 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1394 /*********************
1395 * Create the back, front and stencil buffers
1396 *******************/
1397 TRACE("calling rendertarget CB\n");
1398 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1399 object->presentParms.BackBufferWidth,
1400 object->presentParms.BackBufferHeight,
1401 object->presentParms.BackBufferFormat,
1402 object->presentParms.MultiSampleType,
1403 object->presentParms.MultiSampleQuality,
1404 TRUE /* Lockable */,
1405 &object->frontBuffer,
1406 NULL /* pShared (always null)*/);
1407 if (object->frontBuffer != NULL)
1408 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1409 TRACE("calling rendertarget CB\n");
1410 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1411 object->presentParms.BackBufferWidth,
1412 object->presentParms.BackBufferHeight,
1413 object->presentParms.BackBufferFormat,
1414 object->presentParms.MultiSampleType,
1415 object->presentParms.MultiSampleQuality,
1416 TRUE /* Lockable */,
1417 &object->backBuffer,
1418 NULL /* pShared (always null)*/);
1419 if (object->backBuffer != NULL)
1420 IWineD3DSurface_SetContainer(object->backBuffer, (IWineD3DBase *)object);
1422 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1423 if (pPresentationParameters->EnableAutoDepthStencil) {
1424 TRACE("Creating depth stencil buffer\n");
1425 if (This->depthStencilBuffer == NULL ) {
1426 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1427 object->presentParms.BackBufferWidth,
1428 object->presentParms.BackBufferHeight,
1429 object->presentParms.AutoDepthStencilFormat,
1430 object->presentParms.MultiSampleType,
1431 object->presentParms.MultiSampleQuality,
1432 FALSE /* FIXME: Discard */,
1433 &This->depthStencilBuffer,
1434 NULL /* pShared (always null)*/ );
1435 if (This->depthStencilBuffer != NULL)
1436 IWineD3DSurface_SetContainer(This->depthStencilBuffer, (IWineD3DBase *)iface);
1439 /** TODO: A check on width, height and multisample types
1440 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1441 ****************************/
1442 object->wantsDepthStencilBuffer = TRUE;
1443 } else {
1444 object->wantsDepthStencilBuffer = FALSE;
1447 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer, object->wantsDepthStencilBuffer);
1450 /*********************
1451 * init the default renderTarget management
1452 *******************/
1453 object->drawable = object->win;
1454 object->render_ctx = object->glCtx;
1456 if (hr == D3D_OK) {
1457 /*********************
1458 * Setup some defaults and clear down the buffers
1459 *******************/
1460 ENTER_GL();
1461 /** save current context and drawable **/
1462 oldContext = glXGetCurrentContext();
1463 oldDrawable = glXGetCurrentDrawable();
1465 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1466 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1467 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1469 checkGLcall("glXMakeCurrent");
1471 TRACE("Setting up the screen\n");
1472 /* Clear the screen */
1473 glClearColor(1.0, 0.0, 0.0, 0.0);
1474 checkGLcall("glClearColor");
1475 glClearIndex(0);
1476 glClearDepth(1);
1477 glClearStencil(0xffff);
1479 checkGLcall("glClear");
1481 glColor3f(1.0, 1.0, 1.0);
1482 checkGLcall("glColor3f");
1484 glEnable(GL_LIGHTING);
1485 checkGLcall("glEnable");
1487 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1488 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1490 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1491 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1493 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1494 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1496 /* switch back to the original context (if there was one)*/
1497 if (This->swapchains != NULL) {
1498 /** TODO: restore the context and drawable **/
1499 glXMakeCurrent(object->display, oldDrawable, oldContext);
1502 LEAVE_GL();
1504 { /* Finally add the swapchain to the end of the devices' swapchain list */
1505 SwapChainList **nextSwapchain;
1506 nextSwapchain = &This->swapchains;
1507 while (*nextSwapchain != NULL) {
1508 nextSwapchain = &((*nextSwapchain)->next);
1510 (*nextSwapchain) = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->swapchains));
1511 (*nextSwapchain)->swapchain = (IWineD3DSwapChain *)object;
1513 TRACE("Set swapchain to %p\n", object);
1514 } else { /* something went wrong so clean up */
1515 IUnknown* bufferParent;
1516 if (object->frontBuffer) {
1518 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1519 IUnknown_Release(bufferParent); /* once for the get parent */
1520 if (IUnknown_Release(bufferParent) > 0) {
1521 FIXME("(%p) Something's still holding the front buffer\n",This);
1524 if (object->backBuffer) {
1525 IWineD3DSurface_GetParent(object->backBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the back buffer\n",This);
1531 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1532 /* Clean up the context */
1533 /* check that we are the current context first (we shouldn't be though!) */
1534 if (object->glCtx != 0) {
1535 if(glXGetCurrentContext() == object->glCtx) {
1536 glXMakeCurrent(object->display, None, NULL);
1538 glXDestroyContext(object->display, object->glCtx);
1540 HeapFree(GetProcessHeap(), 0, object);
1544 return hr;
1547 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1548 UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1550 unsigned int numberOfSwapChains = 0;
1551 SwapChainList *swapchain;
1553 swapchain = This->swapchains;
1554 /* itterate through the list to get a count */
1555 while (swapchain != NULL) {
1556 swapchain = swapchain->next;
1557 numberOfSwapChains++;
1560 TRACE("(%p) returning %d\n", This, numberOfSwapChains);
1561 return numberOfSwapChains;
1564 HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1566 SwapChainList *swapchain;
1567 int i = iSwapChain;
1568 HRESULT hr = D3DERR_INVALIDCALL;
1569 swapchain = This->swapchains;
1570 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1573 TRACE("(%p) Finding swapchain %d\n", This, iSwapChain);
1574 while (i > 0 && swapchain != NULL) {
1575 swapchain = swapchain->next;
1576 --i;
1579 if (i > 0) {
1580 FIXME("(%p) Unable to find swapchain %d\n", This, iSwapChain);
1581 *pSwapChain = NULL;
1582 } else if (swapchain != NULL) {
1583 /** TODO: move off to a linkesList implementation **/
1584 *pSwapChain = swapchain->swapchain;
1585 IWineD3DSwapChain_AddRef(*pSwapChain);
1586 hr = D3D_OK;
1589 TRACE("(%p) returning %p\n", This, *pSwapChain);
1590 return hr;
1593 HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1596 FIXME("(%p) : Stub\n",This);
1597 return D3D_OK;
1601 /*****
1602 * Vertex Declaration
1603 *****/
1604 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1606 IWineD3DVertexDeclarationImpl *object = NULL;
1607 HRESULT hr = D3D_OK;
1608 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1609 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1610 object->allFVF = 0;
1612 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1614 return hr;
1617 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1618 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1620 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1621 HRESULT hr = D3D_OK;
1622 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1624 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1625 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1627 if (D3D_OK != hr) {
1628 FIXME("(%p) : Failed to set the function, returning D3DERR_INVALIDCALL\n", iface);
1629 IWineD3DVertexShader_Release(*ppVertexShader);
1630 return D3DERR_INVALIDCALL;
1633 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1634 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1635 /* Foo */
1636 } else {
1637 /* Bar */
1640 #endif
1643 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1644 if (pDeclaration != NULL) {
1645 IWineD3DVertexDeclaration *vertexDeclaration;
1646 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1647 if (D3D_OK == hr) {
1648 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1649 object->vertexDeclaration = vertexDeclaration;
1650 } else {
1651 FIXME("(%p) : Failed to set the declaration, returning D3DERR_INVALIDCALL\n", iface);
1652 IWineD3DVertexShader_Release(*ppVertexShader);
1653 return D3DERR_INVALIDCALL;
1657 return D3D_OK;
1660 HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1662 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1663 HRESULT hr = D3D_OK;
1665 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1666 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1667 if (D3D_OK == hr) {
1668 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1669 } else {
1670 WARN("(%p) : Failed to create pixel shader\n", This);
1673 return hr;
1676 HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 *ppD3D= This->wineD3D;
1679 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1680 IWineD3D_AddRef(*ppD3D);
1681 return D3D_OK;
1684 UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1685 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
1686 * Into the video ram as possible and seeing how many fit
1687 * you can also get the correct initial value from via X and ATI's driver
1688 *******************/
1689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1690 static BOOL showfixmes = TRUE;
1691 if (showfixmes) {
1692 FIXME("(%p) : stub, emulating %dMib for now, returning %dMib\n", This, (emulated_textureram/(1024*1024)),
1693 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1694 showfixmes = FALSE;
1696 TRACE("(%p) : emulating %dMib for now, returning %dMib\n", This, (emulated_textureram/(1024*1024)),
1697 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1698 /* videomemory is simulated videomemory + AGP memory left */
1699 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1704 /*****
1705 * Get / Set FVF
1706 *****/
1707 HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1709 HRESULT hr = D3D_OK;
1711 /* Update the current state block */
1712 This->updateStateBlock->fvf = fvf;
1713 This->updateStateBlock->changed.fvf = TRUE;
1714 This->updateStateBlock->set.fvf = TRUE;
1716 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
1718 if (0 != fvf) {
1719 /* clear down the vertex declaration
1720 NOTE: Axis and Allies doesn't work properly otherwise
1721 (may be a stateblock problem though!)
1723 hr = IWineD3DDevice_SetVertexDeclaration(iface, NULL);
1726 return hr;
1730 HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1732 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
1733 *pfvf = This->stateBlock->fvf;
1734 return D3D_OK;
1737 /*****
1738 * Get / Set Stream Source
1739 *****/
1740 HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1742 IWineD3DVertexBuffer *oldSrc;
1744 /**TODO: instance and index data, see
1745 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
1747 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
1748 **************/
1750 /* D3d9 only, but shouldn't hurt d3d8 */
1751 UINT streamFlags;
1753 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
1754 if (streamFlags) {
1755 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
1756 FIXME("stream index data not supported\n");
1758 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
1759 FIXME("stream instance data not supported\n");
1763 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
1765 if (StreamNumber >= MAX_STREAMS) {
1766 WARN("Stream out of range %d\n", StreamNumber);
1767 return D3DERR_INVALIDCALL;
1770 oldSrc = This->stateBlock->streamSource[StreamNumber];
1771 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1773 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1774 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1775 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1776 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1777 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1778 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
1780 /* Handle recording of state blocks */
1781 if (This->isRecordingState) {
1782 TRACE("Recording... not performing anything\n");
1783 return D3D_OK;
1786 /* Not recording... */
1787 /* Need to do a getParent and pass the reffs up */
1788 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1789 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1790 so for now, just count internally */
1791 if (pStreamData != NULL) {
1792 IWineD3DVertexBuffer_AddRef(pStreamData);
1794 if (oldSrc != NULL) {
1795 IWineD3DVertexBuffer_Release(oldSrc);
1798 return D3D_OK;
1801 HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1803 UINT streamFlags;
1805 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
1806 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
1809 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
1810 if (streamFlags) {
1811 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
1812 FIXME("stream index data not supported\n");
1814 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
1815 FIXME("stream instance data not supported\n");
1819 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
1821 if (StreamNumber >= MAX_STREAMS) {
1822 WARN("Stream out of range %d\n", StreamNumber);
1823 return D3DERR_INVALIDCALL;
1825 *pStream = This->stateBlock->streamSource[StreamNumber];
1826 *pStride = This->stateBlock->streamStride[StreamNumber];
1827 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1829 if (*pStream == NULL) {
1830 FIXME("Attempting to get an empty stream %d, returning D3DERR_INVALIDCALL\n", StreamNumber);
1831 return D3DERR_INVALIDCALL;
1834 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1835 return D3D_OK;
1838 /*Should be quite easy, just an extension of vertexdata
1839 ref...
1840 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
1842 The divider is a bit odd though
1844 VertexOffset = StartVertex / Divider * StreamStride +
1845 VertexIndex / Divider * StreamStride + StreamOffset
1848 HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1851 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1852 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
1854 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
1855 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
1856 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
1858 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
1859 FIXME("Stream indexing not fully supported\n");
1862 return D3D_OK;
1865 HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
1866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
1869 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
1871 TRACE("(%p) : returning %d\n", This, *Divider);
1873 return D3D_OK;
1876 /*****
1877 * Get / Set & Multiply Transform
1878 *****/
1879 HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
1880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 /* Most of this routine, comments included copied from ddraw tree initially: */
1883 TRACE("(%p) : Transform State=%d\n", This, d3dts);
1885 /* Handle recording of state blocks */
1886 if (This->isRecordingState) {
1887 TRACE("Recording... not performing anything\n");
1888 This->updateStateBlock->changed.transform[d3dts] = TRUE;
1889 This->updateStateBlock->set.transform[d3dts] = TRUE;
1890 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
1891 return D3D_OK;
1895 * If the new matrix is the same as the current one,
1896 * we cut off any further processing. this seems to be a reasonable
1897 * optimization because as was noticed, some apps (warcraft3 for example)
1898 * tend towards setting the same matrix repeatedly for some reason.
1900 * From here on we assume that the new matrix is different, wherever it matters.
1902 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
1903 TRACE("The app is setting the same matrix over again\n");
1904 return D3D_OK;
1905 } else {
1906 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
1910 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
1911 where ViewMat = Camera space, WorldMat = world space.
1913 In OpenGL, camera and world space is combined into GL_MODELVIEW
1914 matrix. The Projection matrix stay projection matrix.
1917 /* Capture the times we can just ignore the change for now */
1918 if (d3dts == D3DTS_WORLDMATRIX(0)) {
1919 This->modelview_valid = FALSE;
1920 return D3D_OK;
1922 } else if (d3dts == D3DTS_PROJECTION) {
1923 This->proj_valid = FALSE;
1924 return D3D_OK;
1926 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
1927 /* Indexed Vertex Blending Matrices 256 -> 511 */
1928 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
1929 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
1930 return D3D_OK;
1933 /* Now we really are going to have to change a matrix */
1934 ENTER_GL();
1936 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
1937 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
1938 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
1939 unsigned int k;
1941 /* If we are changing the View matrix, reset the light and clipping planes to the new view
1942 * NOTE: We have to reset the positions even if the light/plane is not currently
1943 * enabled, since the call to enable it will not reset the position.
1944 * NOTE2: Apparently texture transforms do NOT need reapplying
1947 PLIGHTINFOEL *lightChain = NULL;
1948 This->modelview_valid = FALSE;
1949 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
1951 glMatrixMode(GL_MODELVIEW);
1952 checkGLcall("glMatrixMode(GL_MODELVIEW)");
1953 glPushMatrix();
1954 glLoadMatrixf((float *)lpmatrix);
1955 checkGLcall("glLoadMatrixf(...)");
1957 /* Reset lights */
1958 lightChain = This->stateBlock->lights;
1959 while (lightChain && lightChain->glIndex != -1) {
1960 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
1961 checkGLcall("glLightfv posn");
1962 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
1963 checkGLcall("glLightfv dirn");
1964 lightChain = lightChain->next;
1967 /* Reset Clipping Planes if clipping is enabled */
1968 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
1969 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
1970 checkGLcall("glClipPlane");
1972 glPopMatrix();
1974 } else { /* What was requested!?? */
1975 WARN("invalid matrix specified: %i\n", d3dts);
1978 /* Release lock, all done */
1979 LEAVE_GL();
1980 return D3D_OK;
1983 HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
1984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1985 TRACE("(%p) : for Transform State %d\n", This, State);
1986 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
1987 return D3D_OK;
1990 HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
1991 D3DMATRIX *mat = NULL;
1992 D3DMATRIX temp;
1994 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
1995 * below means it will be recorded in a state block change, but it
1996 * works regardless where it is recorded.
1997 * If this is found to be wrong, change to StateBlock.
1999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2000 TRACE("(%p) : For state %u\n", This, State);
2002 if (State < HIGHEST_TRANSFORMSTATE)
2004 mat = &This->updateStateBlock->transforms[State];
2005 } else {
2006 FIXME("Unhandled transform state!!\n");
2009 /* Copied from ddraw code: */
2010 temp.u.s._11 = (mat->u.s._11 * pMatrix->u.s._11) + (mat->u.s._21 * pMatrix->u.s._12) +
2011 (mat->u.s._31 * pMatrix->u.s._13) + (mat->u.s._41 * pMatrix->u.s._14);
2012 temp.u.s._21 = (mat->u.s._11 * pMatrix->u.s._21) + (mat->u.s._21 * pMatrix->u.s._22) +
2013 (mat->u.s._31 * pMatrix->u.s._23) + (mat->u.s._41 * pMatrix->u.s._24);
2014 temp.u.s._31 = (mat->u.s._11 * pMatrix->u.s._31) + (mat->u.s._21 * pMatrix->u.s._32) +
2015 (mat->u.s._31 * pMatrix->u.s._33) + (mat->u.s._41 * pMatrix->u.s._34);
2016 temp.u.s._41 = (mat->u.s._11 * pMatrix->u.s._41) + (mat->u.s._21 * pMatrix->u.s._42) +
2017 (mat->u.s._31 * pMatrix->u.s._43) + (mat->u.s._41 * pMatrix->u.s._44);
2019 temp.u.s._12 = (mat->u.s._12 * pMatrix->u.s._11) + (mat->u.s._22 * pMatrix->u.s._12) +
2020 (mat->u.s._32 * pMatrix->u.s._13) + (mat->u.s._42 * pMatrix->u.s._14);
2021 temp.u.s._22 = (mat->u.s._12 * pMatrix->u.s._21) + (mat->u.s._22 * pMatrix->u.s._22) +
2022 (mat->u.s._32 * pMatrix->u.s._23) + (mat->u.s._42 * pMatrix->u.s._24);
2023 temp.u.s._32 = (mat->u.s._12 * pMatrix->u.s._31) + (mat->u.s._22 * pMatrix->u.s._32) +
2024 (mat->u.s._32 * pMatrix->u.s._33) + (mat->u.s._42 * pMatrix->u.s._34);
2025 temp.u.s._42 = (mat->u.s._12 * pMatrix->u.s._41) + (mat->u.s._22 * pMatrix->u.s._42) +
2026 (mat->u.s._32 * pMatrix->u.s._43) + (mat->u.s._42 * pMatrix->u.s._44);
2028 temp.u.s._13 = (mat->u.s._13 * pMatrix->u.s._11) + (mat->u.s._23 * pMatrix->u.s._12) +
2029 (mat->u.s._33 * pMatrix->u.s._13) + (mat->u.s._43 * pMatrix->u.s._14);
2030 temp.u.s._23 = (mat->u.s._13 * pMatrix->u.s._21) + (mat->u.s._23 * pMatrix->u.s._22) +
2031 (mat->u.s._33 * pMatrix->u.s._23) + (mat->u.s._43 * pMatrix->u.s._24);
2032 temp.u.s._33 = (mat->u.s._13 * pMatrix->u.s._31) + (mat->u.s._23 * pMatrix->u.s._32) +
2033 (mat->u.s._33 * pMatrix->u.s._33) + (mat->u.s._43 * pMatrix->u.s._34);
2034 temp.u.s._43 = (mat->u.s._13 * pMatrix->u.s._41) + (mat->u.s._23 * pMatrix->u.s._42) +
2035 (mat->u.s._33 * pMatrix->u.s._43) + (mat->u.s._43 * pMatrix->u.s._44);
2037 temp.u.s._14 = (mat->u.s._14 * pMatrix->u.s._11) + (mat->u.s._24 * pMatrix->u.s._12) +
2038 (mat->u.s._34 * pMatrix->u.s._13) + (mat->u.s._44 * pMatrix->u.s._14);
2039 temp.u.s._24 = (mat->u.s._14 * pMatrix->u.s._21) + (mat->u.s._24 * pMatrix->u.s._22) +
2040 (mat->u.s._34 * pMatrix->u.s._23) + (mat->u.s._44 * pMatrix->u.s._24);
2041 temp.u.s._34 = (mat->u.s._14 * pMatrix->u.s._31) + (mat->u.s._24 * pMatrix->u.s._32) +
2042 (mat->u.s._34 * pMatrix->u.s._33) + (mat->u.s._44 * pMatrix->u.s._34);
2043 temp.u.s._44 = (mat->u.s._14 * pMatrix->u.s._41) + (mat->u.s._24 * pMatrix->u.s._42) +
2044 (mat->u.s._34 * pMatrix->u.s._43) + (mat->u.s._44 * pMatrix->u.s._44);
2046 /* Apply change via set transform - will reapply to eg. lights this way */
2047 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2050 /*****
2051 * Get / Set Light
2052 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2053 *****/
2054 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2055 you can reference any indexes you want as long as that number max are enabled at any
2056 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2057 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2058 but when recording, just build a chain pretty much of commands to be replayed. */
2060 HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2061 float rho;
2062 PLIGHTINFOEL *object, *temp;
2064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2065 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2067 /* If recording state block, just add to end of lights chain */
2068 if (This->isRecordingState) {
2069 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2070 if (NULL == object) {
2071 return D3DERR_OUTOFVIDEOMEMORY;
2073 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2074 object->OriginalIndex = Index;
2075 object->glIndex = -1;
2076 object->changed = TRUE;
2078 /* Add to the END of the chain of lights changes to be replayed */
2079 if (This->updateStateBlock->lights == NULL) {
2080 This->updateStateBlock->lights = object;
2081 } else {
2082 temp = This->updateStateBlock->lights;
2083 while (temp->next != NULL) temp=temp->next;
2084 temp->next = object;
2086 TRACE("Recording... not performing anything more\n");
2087 return D3D_OK;
2090 /* Ok, not recording any longer so do real work */
2091 object = This->stateBlock->lights;
2092 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2094 /* If we didn't find it in the list of lights, time to add it */
2095 if (object == NULL) {
2096 PLIGHTINFOEL *insertAt,*prevPos;
2098 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2099 if (NULL == object) {
2100 return D3DERR_OUTOFVIDEOMEMORY;
2102 object->OriginalIndex = Index;
2103 object->glIndex = -1;
2105 /* Add it to the front of list with the idea that lights will be changed as needed
2106 BUT after any lights currently assigned GL indexes */
2107 insertAt = This->stateBlock->lights;
2108 prevPos = NULL;
2109 while (insertAt != NULL && insertAt->glIndex != -1) {
2110 prevPos = insertAt;
2111 insertAt = insertAt->next;
2114 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2115 This->stateBlock->lights = object;
2116 } else if (insertAt == NULL) { /* End of list */
2117 prevPos->next = object;
2118 object->prev = prevPos;
2119 } else { /* Middle of chain */
2120 if (prevPos == NULL) {
2121 This->stateBlock->lights = object;
2122 } else {
2123 prevPos->next = object;
2125 object->prev = prevPos;
2126 object->next = insertAt;
2127 insertAt->prev = object;
2131 /* Initialize the object */
2132 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,
2133 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2134 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2135 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2136 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2137 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2138 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2140 /* Save away the information */
2141 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2143 switch (pLight->Type) {
2144 case D3DLIGHT_POINT:
2145 /* Position */
2146 object->lightPosn[0] = pLight->Position.x;
2147 object->lightPosn[1] = pLight->Position.y;
2148 object->lightPosn[2] = pLight->Position.z;
2149 object->lightPosn[3] = 1.0f;
2150 object->cutoff = 180.0f;
2151 /* FIXME: Range */
2152 break;
2154 case D3DLIGHT_DIRECTIONAL:
2155 /* Direction */
2156 object->lightPosn[0] = -pLight->Direction.x;
2157 object->lightPosn[1] = -pLight->Direction.y;
2158 object->lightPosn[2] = -pLight->Direction.z;
2159 object->lightPosn[3] = 0.0;
2160 object->exponent = 0.0f;
2161 object->cutoff = 180.0f;
2162 break;
2164 case D3DLIGHT_SPOT:
2165 /* Position */
2166 object->lightPosn[0] = pLight->Position.x;
2167 object->lightPosn[1] = pLight->Position.y;
2168 object->lightPosn[2] = pLight->Position.z;
2169 object->lightPosn[3] = 1.0;
2171 /* Direction */
2172 object->lightDirn[0] = pLight->Direction.x;
2173 object->lightDirn[1] = pLight->Direction.y;
2174 object->lightDirn[2] = pLight->Direction.z;
2175 object->lightDirn[3] = 1.0;
2178 * opengl-ish and d3d-ish spot lights use too different models for the
2179 * light "intensity" as a function of the angle towards the main light direction,
2180 * so we only can approximate very roughly.
2181 * however spot lights are rather rarely used in games (if ever used at all).
2182 * furthermore if still used, probably nobody pays attention to such details.
2184 if (pLight->Falloff == 0) {
2185 rho = 6.28f;
2186 } else {
2187 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2189 if (rho < 0.0001) rho = 0.0001f;
2190 object->exponent = -0.3/log(cos(rho/2));
2191 object->cutoff = pLight->Phi*90/M_PI;
2193 /* FIXME: Range */
2194 break;
2196 default:
2197 FIXME("Unrecognized light type %d\n", pLight->Type);
2200 /* Update the live definitions if the light is currently assigned a glIndex */
2201 if (object->glIndex != -1) {
2202 setup_light(iface, object->glIndex, object);
2204 return D3D_OK;
2207 HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2208 PLIGHTINFOEL *lightInfo = NULL;
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2210 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2212 /* Locate the light in the live lights */
2213 lightInfo = This->stateBlock->lights;
2214 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2216 if (lightInfo == NULL) {
2217 TRACE("Light information requested but light not defined\n");
2218 return D3DERR_INVALIDCALL;
2221 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2222 return D3D_OK;
2225 /*****
2226 * Get / Set Light Enable
2227 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2228 *****/
2229 HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2230 PLIGHTINFOEL *lightInfo = NULL;
2231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2232 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2234 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2235 if (This->isRecordingState) {
2236 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2237 if (NULL == lightInfo) {
2238 return D3DERR_OUTOFVIDEOMEMORY;
2240 lightInfo->OriginalIndex = Index;
2241 lightInfo->glIndex = -1;
2242 lightInfo->enabledChanged = TRUE;
2244 /* Add to the END of the chain of lights changes to be replayed */
2245 if (This->updateStateBlock->lights == NULL) {
2246 This->updateStateBlock->lights = lightInfo;
2247 } else {
2248 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2249 while (temp->next != NULL) temp=temp->next;
2250 temp->next = lightInfo;
2252 TRACE("Recording... not performing anything more\n");
2253 return D3D_OK;
2256 /* Not recording... So, locate the light in the live lights */
2257 lightInfo = This->stateBlock->lights;
2258 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2260 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2261 if (lightInfo == NULL) {
2262 D3DLIGHT9 lightParms;
2263 /* Warning - untested code :-) Prob safe to change fixme to a trace but
2264 wait until someone confirms it seems to work! */
2265 TRACE("Light enabled requested but light not defined, so defining one!\n");
2266 lightParms.Type = D3DLIGHT_DIRECTIONAL;
2267 lightParms.Diffuse.r = 1.0;
2268 lightParms.Diffuse.g = 1.0;
2269 lightParms.Diffuse.b = 1.0;
2270 lightParms.Diffuse.a = 0.0;
2271 lightParms.Specular.r = 0.0;
2272 lightParms.Specular.g = 0.0;
2273 lightParms.Specular.b = 0.0;
2274 lightParms.Specular.a = 0.0;
2275 lightParms.Ambient.r = 0.0;
2276 lightParms.Ambient.g = 0.0;
2277 lightParms.Ambient.b = 0.0;
2278 lightParms.Ambient.a = 0.0;
2279 lightParms.Position.x = 0.0;
2280 lightParms.Position.y = 0.0;
2281 lightParms.Position.z = 0.0;
2282 lightParms.Direction.x = 0.0;
2283 lightParms.Direction.y = 0.0;
2284 lightParms.Direction.z = 1.0;
2285 lightParms.Range = 0.0;
2286 lightParms.Falloff = 0.0;
2287 lightParms.Attenuation0 = 0.0;
2288 lightParms.Attenuation1 = 0.0;
2289 lightParms.Attenuation2 = 0.0;
2290 lightParms.Theta = 0.0;
2291 lightParms.Phi = 0.0;
2292 IWineD3DDeviceImpl_SetLight(iface, Index, &lightParms);
2294 /* Search for it again! Should be fairly quick as near head of list */
2295 lightInfo = This->stateBlock->lights;
2296 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2297 if (lightInfo == NULL) {
2298 FIXME("Adding default lights has failed dismally\n");
2299 return D3DERR_INVALIDCALL;
2303 /* OK, we now have a light... */
2304 if (Enable == FALSE) {
2306 /* If we are disabling it, check it was enabled, and
2307 still only do something if it has assigned a glIndex (which it should have!) */
2308 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2309 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2310 ENTER_GL();
2311 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2312 checkGLcall("glDisable GL_LIGHT0+Index");
2313 LEAVE_GL();
2314 } else {
2315 TRACE("Nothing to do as light was not enabled\n");
2317 lightInfo->lightEnabled = FALSE;
2318 } else {
2320 /* We are enabling it. If it is enabled, it's really simple */
2321 if (lightInfo->lightEnabled) {
2322 /* nop */
2323 TRACE("Nothing to do as light was enabled\n");
2325 /* If it already has a glIndex, it's still simple */
2326 } else if (lightInfo->glIndex != -1) {
2327 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2328 lightInfo->lightEnabled = TRUE;
2329 ENTER_GL();
2330 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2331 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2332 LEAVE_GL();
2334 /* Otherwise got to find space - lights are ordered gl indexes first */
2335 } else {
2336 PLIGHTINFOEL *bsf = NULL;
2337 PLIGHTINFOEL *pos = This->stateBlock->lights;
2338 PLIGHTINFOEL *prev = NULL;
2339 int Index= 0;
2340 int glIndex = -1;
2342 /* Try to minimize changes as much as possible */
2343 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2345 /* Try to remember which index can be replaced if necessary */
2346 if (bsf==NULL && pos->lightEnabled == FALSE) {
2347 /* Found a light we can replace, save as best replacement */
2348 bsf = pos;
2351 /* Step to next space */
2352 prev = pos;
2353 pos = pos->next;
2354 Index ++;
2357 /* If we have too many active lights, fail the call */
2358 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2359 FIXME("Program requests too many concurrent lights\n");
2360 return D3DERR_INVALIDCALL;
2362 /* If we have allocated all lights, but not all are enabled,
2363 reuse one which is not enabled */
2364 } else if (Index == This->maxConcurrentLights) {
2365 /* use bsf - Simply swap the new light and the BSF one */
2366 PLIGHTINFOEL *bsfNext = bsf->next;
2367 PLIGHTINFOEL *bsfPrev = bsf->prev;
2369 /* Sort out ends */
2370 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2371 if (bsf->prev != NULL) {
2372 bsf->prev->next = lightInfo;
2373 } else {
2374 This->stateBlock->lights = lightInfo;
2377 /* If not side by side, lots of chains to update */
2378 if (bsf->next != lightInfo) {
2379 lightInfo->prev->next = bsf;
2380 bsf->next->prev = lightInfo;
2381 bsf->next = lightInfo->next;
2382 bsf->prev = lightInfo->prev;
2383 lightInfo->next = bsfNext;
2384 lightInfo->prev = bsfPrev;
2386 } else {
2387 /* Simple swaps */
2388 bsf->prev = lightInfo;
2389 bsf->next = lightInfo->next;
2390 lightInfo->next = bsf;
2391 lightInfo->prev = bsfPrev;
2395 /* Update states */
2396 glIndex = bsf->glIndex;
2397 bsf->glIndex = -1;
2398 lightInfo->glIndex = glIndex;
2399 lightInfo->lightEnabled = TRUE;
2401 /* Finally set up the light in gl itself */
2402 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2403 ENTER_GL();
2404 setup_light(iface, glIndex, lightInfo);
2405 glEnable(GL_LIGHT0 + glIndex);
2406 checkGLcall("glEnable GL_LIGHT0 new setup");
2407 LEAVE_GL();
2409 /* If we reached the end of the allocated lights, with space in the
2410 gl lights, setup a new light */
2411 } else if (pos->glIndex == -1) {
2413 /* We reached the end of the allocated gl lights, so already
2414 know the index of the next one! */
2415 glIndex = Index;
2416 lightInfo->glIndex = glIndex;
2417 lightInfo->lightEnabled = TRUE;
2419 /* In an ideal world, it's already in the right place */
2420 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2421 /* No need to move it */
2422 } else {
2423 /* Remove this light from the list */
2424 lightInfo->prev->next = lightInfo->next;
2425 if (lightInfo->next != NULL) {
2426 lightInfo->next->prev = lightInfo->prev;
2429 /* Add in at appropriate place (inbetween prev and pos) */
2430 lightInfo->prev = prev;
2431 lightInfo->next = pos;
2432 if (prev == NULL) {
2433 This->stateBlock->lights = lightInfo;
2434 } else {
2435 prev->next = lightInfo;
2437 if (pos != NULL) {
2438 pos->prev = lightInfo;
2442 /* Finally set up the light in gl itself */
2443 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2444 ENTER_GL();
2445 setup_light(iface, glIndex, lightInfo);
2446 glEnable(GL_LIGHT0 + glIndex);
2447 checkGLcall("glEnable GL_LIGHT0 new setup");
2448 LEAVE_GL();
2453 return D3D_OK;
2456 HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2458 PLIGHTINFOEL *lightInfo = NULL;
2459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 TRACE("(%p) : for idx(%ld)\n", This, Index);
2462 /* Locate the light in the live lights */
2463 lightInfo = This->stateBlock->lights;
2464 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2466 if (lightInfo == NULL) {
2467 TRACE("Light enabled state requested but light not defined\n");
2468 return D3DERR_INVALIDCALL;
2470 *pEnable = lightInfo->lightEnabled;
2471 return D3D_OK;
2474 /*****
2475 * Get / Set Clip Planes
2476 *****/
2477 HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2481 /* Validate Index */
2482 if (Index >= GL_LIMITS(clipplanes)) {
2483 TRACE("Application has requested clipplane this device doesn't support\n");
2484 return D3DERR_INVALIDCALL;
2487 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2488 This->updateStateBlock->set.clipplane[Index] = TRUE;
2489 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2490 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2491 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2492 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2494 /* Handle recording of state blocks */
2495 if (This->isRecordingState) {
2496 TRACE("Recording... not performing anything\n");
2497 return D3D_OK;
2500 /* Apply it */
2502 ENTER_GL();
2504 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2505 glMatrixMode(GL_MODELVIEW);
2506 glPushMatrix();
2507 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
2509 TRACE("Clipplane [%f,%f,%f,%f]\n",
2510 This->updateStateBlock->clipplane[Index][0],
2511 This->updateStateBlock->clipplane[Index][1],
2512 This->updateStateBlock->clipplane[Index][2],
2513 This->updateStateBlock->clipplane[Index][3]);
2514 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2515 checkGLcall("glClipPlane");
2517 glPopMatrix();
2518 LEAVE_GL();
2520 return D3D_OK;
2523 HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 TRACE("(%p) : for idx %ld\n", This, Index);
2527 /* Validate Index */
2528 if (Index >= GL_LIMITS(clipplanes)) {
2529 TRACE("Application has requested clipplane this device doesn't support\n");
2530 return D3DERR_INVALIDCALL;
2533 pPlane[0] = This->stateBlock->clipplane[Index][0];
2534 pPlane[1] = This->stateBlock->clipplane[Index][1];
2535 pPlane[2] = This->stateBlock->clipplane[Index][2];
2536 pPlane[3] = This->stateBlock->clipplane[Index][3];
2537 return D3D_OK;
2540 /*****
2541 * Get / Set Clip Plane Status
2542 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2543 *****/
2544 HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2546 FIXME("(%p) : stub\n", This);
2547 if (NULL == pClipStatus) {
2548 return D3DERR_INVALIDCALL;
2550 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2551 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2552 return D3D_OK;
2555 HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 FIXME("(%p) : stub\n", This);
2558 if (NULL == pClipStatus) {
2559 return D3DERR_INVALIDCALL;
2561 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2562 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2563 return D3D_OK;
2566 /*****
2567 * Get / Set Material
2568 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
2569 *****/
2570 HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2573 This->updateStateBlock->changed.material = TRUE;
2574 This->updateStateBlock->set.material = TRUE;
2575 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2577 /* Handle recording of state blocks */
2578 if (This->isRecordingState) {
2579 TRACE("Recording... not performing anything\n");
2580 return D3D_OK;
2583 ENTER_GL();
2584 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2585 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2586 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2587 pMaterial->Ambient.b, pMaterial->Ambient.a);
2588 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2589 pMaterial->Specular.b, pMaterial->Specular.a);
2590 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2591 pMaterial->Emissive.b, pMaterial->Emissive.a);
2592 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2594 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2595 checkGLcall("glMaterialfv(GL_AMBIENT)");
2596 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2597 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2599 /* Only change material color if specular is enabled, otherwise it is set to black */
2600 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2601 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2602 checkGLcall("glMaterialfv(GL_SPECULAR");
2603 } else {
2604 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2605 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2606 checkGLcall("glMaterialfv(GL_SPECULAR");
2608 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2609 checkGLcall("glMaterialfv(GL_EMISSION)");
2610 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2611 checkGLcall("glMaterialf(GL_SHININESS");
2613 LEAVE_GL();
2614 return D3D_OK;
2617 HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2619 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2620 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2621 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2622 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2623 pMaterial->Ambient.b, pMaterial->Ambient.a);
2624 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2625 pMaterial->Specular.b, pMaterial->Specular.a);
2626 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2627 pMaterial->Emissive.b, pMaterial->Emissive.a);
2628 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2630 return D3D_OK;
2633 /*****
2634 * Get / Set Indices
2635 *****/
2636 HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2637 UINT BaseVertexIndex) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 IWineD3DIndexBuffer *oldIdxs;
2641 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2642 oldIdxs = This->updateStateBlock->pIndexData;
2644 This->updateStateBlock->changed.indices = TRUE;
2645 This->updateStateBlock->set.indices = TRUE;
2646 This->updateStateBlock->pIndexData = pIndexData;
2647 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2649 /* Handle recording of state blocks */
2650 if (This->isRecordingState) {
2651 TRACE("Recording... not performing anything\n");
2652 return D3D_OK;
2655 if (NULL != pIndexData) {
2656 IWineD3DIndexBuffer_AddRef(pIndexData);
2658 if (NULL != oldIdxs) {
2659 IWineD3DIndexBuffer_Release(oldIdxs);
2661 return D3D_OK;
2664 HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2667 *ppIndexData = This->stateBlock->pIndexData;
2669 /* up ref count on ppindexdata */
2670 if (*ppIndexData) {
2671 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2672 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2673 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2674 }else{
2675 TRACE("(%p) No index data set\n", This);
2677 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2679 return D3D_OK;
2682 /*****
2683 * Get / Set Viewports
2684 *****/
2685 HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 TRACE("(%p)\n", This);
2689 This->updateStateBlock->changed.viewport = TRUE;
2690 This->updateStateBlock->set.viewport = TRUE;
2691 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2693 /* Handle recording of state blocks */
2694 if (This->isRecordingState) {
2695 TRACE("Recording... not performing anything\n");
2696 return D3D_OK;
2698 This->viewport_changed = TRUE;
2700 ENTER_GL();
2702 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
2703 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2705 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
2706 checkGLcall("glDepthRange");
2707 /* Note: GL requires lower left, DirectX supplies upper left */
2708 /* TODO: replace usage of renderTarget with context management */
2709 glViewport(pViewport->X,
2710 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
2711 pViewport->Width, pViewport->Height);
2713 checkGLcall("glViewport");
2715 LEAVE_GL();
2717 return D3D_OK;
2721 HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p)\n", This);
2724 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2725 return D3D_OK;
2728 /*****
2729 * Get / Set Render States
2730 * TODO: Verify against dx9 definitions
2731 *****/
2732 HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 DWORD OldValue = This->stateBlock->renderState[State];
2737 /* Simple way of referring to either a DWORD or a 4 byte float */
2738 union {
2739 DWORD d;
2740 float f;
2741 } tmpvalue;
2743 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
2744 This->updateStateBlock->changed.renderState[State] = TRUE;
2745 This->updateStateBlock->set.renderState[State] = TRUE;
2746 This->updateStateBlock->renderState[State] = Value;
2748 /* Handle recording of state blocks */
2749 if (This->isRecordingState) {
2750 TRACE("Recording... not performing anything\n");
2751 return D3D_OK;
2754 ENTER_GL();
2756 switch (State) {
2757 case WINED3DRS_FILLMODE :
2758 switch ((D3DFILLMODE) Value) {
2759 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
2760 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
2761 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
2762 default:
2763 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
2765 checkGLcall("glPolygonMode (fillmode)");
2766 break;
2768 case WINED3DRS_LIGHTING :
2769 if (Value) {
2770 glEnable(GL_LIGHTING);
2771 checkGLcall("glEnable GL_LIGHTING");
2772 } else {
2773 glDisable(GL_LIGHTING);
2774 checkGLcall("glDisable GL_LIGHTING");
2776 break;
2778 case WINED3DRS_ZENABLE :
2779 switch ((D3DZBUFFERTYPE) Value) {
2780 case D3DZB_FALSE:
2781 glDisable(GL_DEPTH_TEST);
2782 checkGLcall("glDisable GL_DEPTH_TEST");
2783 break;
2784 case D3DZB_TRUE:
2785 glEnable(GL_DEPTH_TEST);
2786 checkGLcall("glEnable GL_DEPTH_TEST");
2787 break;
2788 case D3DZB_USEW:
2789 glEnable(GL_DEPTH_TEST);
2790 checkGLcall("glEnable GL_DEPTH_TEST");
2791 FIXME("W buffer is not well handled\n");
2792 break;
2793 default:
2794 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
2796 break;
2798 case WINED3DRS_CULLMODE :
2800 /* If we are culling "back faces with clockwise vertices" then
2801 set front faces to be counter clockwise and enable culling
2802 of back faces */
2803 switch ((D3DCULL) Value) {
2804 case D3DCULL_NONE:
2805 glDisable(GL_CULL_FACE);
2806 checkGLcall("glDisable GL_CULL_FACE");
2807 break;
2808 case D3DCULL_CW:
2809 glEnable(GL_CULL_FACE);
2810 checkGLcall("glEnable GL_CULL_FACE");
2811 if (This->renderUpsideDown) {
2812 glFrontFace(GL_CW);
2813 checkGLcall("glFrontFace GL_CW");
2814 } else {
2815 glFrontFace(GL_CCW);
2816 checkGLcall("glFrontFace GL_CCW");
2818 glCullFace(GL_BACK);
2819 break;
2820 case D3DCULL_CCW:
2821 glEnable(GL_CULL_FACE);
2822 checkGLcall("glEnable GL_CULL_FACE");
2823 if (This->renderUpsideDown) {
2824 glFrontFace(GL_CCW);
2825 checkGLcall("glFrontFace GL_CCW");
2826 } else {
2827 glFrontFace(GL_CW);
2828 checkGLcall("glFrontFace GL_CW");
2830 glCullFace(GL_BACK);
2831 break;
2832 default:
2833 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
2835 break;
2837 case WINED3DRS_SHADEMODE :
2838 switch ((D3DSHADEMODE) Value) {
2839 case D3DSHADE_FLAT:
2840 glShadeModel(GL_FLAT);
2841 checkGLcall("glShadeModel");
2842 break;
2843 case D3DSHADE_GOURAUD:
2844 glShadeModel(GL_SMOOTH);
2845 checkGLcall("glShadeModel");
2846 break;
2847 case D3DSHADE_PHONG:
2848 FIXME("D3DSHADE_PHONG isn't supported?\n");
2850 LEAVE_GL();
2851 return D3DERR_INVALIDCALL;
2852 default:
2853 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
2855 break;
2857 case WINED3DRS_DITHERENABLE :
2858 if (Value) {
2859 glEnable(GL_DITHER);
2860 checkGLcall("glEnable GL_DITHER");
2861 } else {
2862 glDisable(GL_DITHER);
2863 checkGLcall("glDisable GL_DITHER");
2865 break;
2867 case WINED3DRS_ZWRITEENABLE :
2868 if (Value) {
2869 glDepthMask(1);
2870 checkGLcall("glDepthMask");
2871 } else {
2872 glDepthMask(0);
2873 checkGLcall("glDepthMask");
2875 break;
2877 case WINED3DRS_ZFUNC :
2879 int glParm = GL_LESS;
2881 switch ((D3DCMPFUNC) Value) {
2882 case D3DCMP_NEVER: glParm=GL_NEVER; break;
2883 case D3DCMP_LESS: glParm=GL_LESS; break;
2884 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
2885 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
2886 case D3DCMP_GREATER: glParm=GL_GREATER; break;
2887 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
2888 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
2889 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
2890 default:
2891 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
2893 glDepthFunc(glParm);
2894 checkGLcall("glDepthFunc");
2896 break;
2898 case WINED3DRS_AMBIENT :
2900 float col[4];
2901 D3DCOLORTOGLFLOAT4(Value, col);
2902 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
2903 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
2904 checkGLcall("glLightModel for MODEL_AMBIENT");
2907 break;
2909 case WINED3DRS_ALPHABLENDENABLE :
2910 if (Value) {
2911 glEnable(GL_BLEND);
2912 checkGLcall("glEnable GL_BLEND");
2913 } else {
2914 glDisable(GL_BLEND);
2915 checkGLcall("glDisable GL_BLEND");
2917 break;
2919 case WINED3DRS_SRCBLEND :
2920 case WINED3DRS_DESTBLEND :
2922 int newVal = GL_ZERO;
2923 switch (Value) {
2924 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
2925 case D3DBLEND_ONE : newVal = GL_ONE; break;
2926 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
2927 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
2928 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
2929 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
2930 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
2931 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
2932 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
2933 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
2934 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
2936 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
2937 This->srcBlend = newVal;
2938 This->dstBlend = newVal;
2939 break;
2941 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
2942 This->srcBlend = newVal;
2943 This->dstBlend = newVal;
2944 break;
2945 default:
2946 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
2949 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
2950 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
2951 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
2952 glBlendFunc(This->srcBlend, This->dstBlend);
2954 checkGLcall("glBlendFunc");
2956 break;
2958 case WINED3DRS_ALPHATESTENABLE :
2959 if (Value) {
2960 glEnable(GL_ALPHA_TEST);
2961 checkGLcall("glEnable GL_ALPHA_TEST");
2962 } else {
2963 glDisable(GL_ALPHA_TEST);
2964 checkGLcall("glDisable GL_ALPHA_TEST");
2966 break;
2968 case WINED3DRS_ALPHAFUNC :
2970 int glParm = GL_LESS;
2971 float ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
2973 switch ((D3DCMPFUNC) Value) {
2974 case D3DCMP_NEVER: glParm = GL_NEVER; break;
2975 case D3DCMP_LESS: glParm = GL_LESS; break;
2976 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
2977 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
2978 case D3DCMP_GREATER: glParm = GL_GREATER; break;
2979 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
2980 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
2981 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
2982 default:
2983 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
2985 TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref);
2986 glAlphaFunc(glParm, ref);
2987 This->alphafunc = glParm;
2988 checkGLcall("glAlphaFunc");
2990 break;
2992 case WINED3DRS_ALPHAREF :
2994 int glParm = This->alphafunc;
2995 float ref = 1.0f;
2997 ref = ((float) Value) / 255.0f;
2998 TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref);
2999 glAlphaFunc(glParm, ref);
3000 checkGLcall("glAlphaFunc");
3002 break;
3004 case WINED3DRS_CLIPPLANEENABLE :
3005 case WINED3DRS_CLIPPING :
3007 /* Ensure we only do the changed clip planes */
3008 DWORD enable = 0xFFFFFFFF;
3009 DWORD disable = 0x00000000;
3011 /* If enabling / disabling all */
3012 if (State == WINED3DRS_CLIPPING) {
3013 if (Value) {
3014 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3015 disable = 0x00;
3016 } else {
3017 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3018 enable = 0x00;
3020 } else {
3021 enable = Value & ~OldValue;
3022 disable = ~Value & OldValue;
3025 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3026 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3027 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3028 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3029 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3030 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3032 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3033 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3034 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3035 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3036 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3037 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3039 /** update clipping status */
3040 if (enable) {
3041 This->stateBlock->clip_status.ClipUnion = 0;
3042 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3043 } else {
3044 This->stateBlock->clip_status.ClipUnion = 0;
3045 This->stateBlock->clip_status.ClipIntersection = 0;
3048 break;
3050 case WINED3DRS_BLENDOP :
3052 int glParm = GL_FUNC_ADD;
3054 switch ((D3DBLENDOP) Value) {
3055 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3056 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3057 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3058 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3059 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3060 default:
3061 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3063 TRACE("glBlendEquation(%x)\n", glParm);
3064 glBlendEquation(glParm);
3065 checkGLcall("glBlendEquation");
3067 break;
3069 case WINED3DRS_TEXTUREFACTOR :
3071 unsigned int i;
3073 /* Note the texture color applies to all textures whereas
3074 GL_TEXTURE_ENV_COLOR applies to active only */
3075 float col[4];
3076 D3DCOLORTOGLFLOAT4(Value, col);
3077 /* Set the default alpha blend color */
3078 glBlendColor(col[0], col[1], col[2], col[3]);
3079 checkGLcall("glBlendColor");
3081 /* And now the default texture color as well */
3082 for (i = 0; i < GL_LIMITS(textures); i++) {
3084 /* Note the D3DRS value applies to all textures, but GL has one
3085 per texture, so apply it now ready to be used! */
3086 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3087 GLACTIVETEXTURE(i);
3088 } else if (i>0) {
3089 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3092 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3093 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3096 break;
3098 case WINED3DRS_SPECULARENABLE :
3100 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3101 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3102 specular color. This is wrong:
3103 Separate specular color means the specular colour is maintained separately, whereas
3104 single color means it is merged in. However in both cases they are being used to
3105 some extent.
3106 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3107 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3108 running 1.4 yet!
3110 if (Value) {
3111 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3112 checkGLcall("glMaterialfv");
3113 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3114 glEnable(GL_COLOR_SUM_EXT);
3115 } else {
3116 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3118 checkGLcall("glEnable(GL_COLOR_SUM)");
3119 } else {
3120 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3122 /* for the case of enabled lighting: */
3123 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3124 checkGLcall("glMaterialfv");
3126 /* for the case of disabled lighting: */
3127 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3128 glDisable(GL_COLOR_SUM_EXT);
3129 } else {
3130 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3132 checkGLcall("glDisable(GL_COLOR_SUM)");
3135 break;
3137 case WINED3DRS_STENCILENABLE :
3138 if (Value) {
3139 glEnable(GL_STENCIL_TEST);
3140 checkGLcall("glEnable GL_STENCIL_TEST");
3141 } else {
3142 glDisable(GL_STENCIL_TEST);
3143 checkGLcall("glDisable GL_STENCIL_TEST");
3145 break;
3147 case WINED3DRS_STENCILFUNC :
3149 int glParm = GL_ALWAYS;
3150 int ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3151 GLuint mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3153 switch ((D3DCMPFUNC) Value) {
3154 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3155 case D3DCMP_LESS: glParm=GL_LESS; break;
3156 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3157 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3158 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3159 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3160 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3161 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3162 default:
3163 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3165 TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
3166 This->stencilfunc = glParm;
3167 glStencilFunc(glParm, ref, mask);
3168 checkGLcall("glStencilFunc");
3170 break;
3172 case WINED3DRS_STENCILREF :
3174 int glParm = This->stencilfunc;
3175 int ref = 0;
3176 GLuint mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3178 ref = Value;
3179 TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
3180 glStencilFunc(glParm, ref, mask);
3181 checkGLcall("glStencilFunc");
3183 break;
3185 case WINED3DRS_STENCILMASK :
3187 int glParm = This->stencilfunc;
3188 int ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3189 GLuint mask = Value;
3191 TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask);
3192 glStencilFunc(glParm, ref, mask);
3193 checkGLcall("glStencilFunc");
3195 break;
3197 case WINED3DRS_STENCILFAIL :
3199 GLenum fail ;
3200 GLint zpass ;
3201 GLint zfail ;
3203 fail = StencilOp(Value);
3204 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);
3205 checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);");
3206 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);
3207 checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);");
3209 TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
3210 glStencilOp(fail, zfail, zpass);
3211 checkGLcall("glStencilOp(fail, zfail, zpass);");
3213 break;
3214 case WINED3DRS_STENCILZFAIL :
3216 GLint fail ;
3217 GLint zpass ;
3218 GLenum zfail ;
3220 glGetIntegerv(GL_STENCIL_FAIL, &fail);
3221 checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);");
3222 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);
3223 checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);");
3224 zfail = StencilOp(Value);
3226 TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
3227 glStencilOp(fail, zfail, zpass);
3228 checkGLcall("glStencilOp(fail, zfail, zpass);");
3230 break;
3231 case WINED3DRS_STENCILPASS :
3233 GLint fail ;
3234 GLenum zpass ;
3235 GLint zfail ;
3237 glGetIntegerv(GL_STENCIL_FAIL, &fail);
3238 checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);");
3239 zpass = StencilOp(Value);
3240 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);
3241 checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);");
3243 TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass);
3244 glStencilOp(fail, zfail, zpass);
3245 checkGLcall("glStencilOp(fail, zfail, zpass);");
3247 break;
3249 case WINED3DRS_STENCILWRITEMASK :
3251 glStencilMask(Value);
3252 TRACE("glStencilMask(%lu)\n", Value);
3253 checkGLcall("glStencilMask");
3255 break;
3257 case WINED3DRS_FOGENABLE :
3259 if (Value/* && This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] != D3DFOG_NONE*/) {
3260 glEnable(GL_FOG);
3261 checkGLcall("glEnable GL_FOG");
3262 } else {
3263 glDisable(GL_FOG);
3264 checkGLcall("glDisable GL_FOG");
3267 break;
3269 case WINED3DRS_RANGEFOGENABLE :
3271 if (Value) {
3272 TRACE("Enabled RANGEFOG");
3273 } else {
3274 TRACE("Disabled RANGEFOG");
3277 break;
3279 case WINED3DRS_FOGCOLOR :
3281 float col[4];
3282 D3DCOLORTOGLFLOAT4(Value, col);
3283 /* Set the default alpha blend color */
3284 glFogfv(GL_FOG_COLOR, &col[0]);
3285 checkGLcall("glFog GL_FOG_COLOR");
3287 break;
3289 case WINED3DRS_FOGTABLEMODE :
3291 glHint(GL_FOG_HINT, GL_NICEST);
3292 switch (Value) {
3293 case D3DFOG_NONE: /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break;
3294 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break;
3295 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break;
3296 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break;
3297 default:
3298 FIXME("Unsupported Value(%lu) for WINED3DRS_FOGTABLEMODE!\n", Value);
3300 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3301 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3304 break;
3306 case WINED3DRS_FOGVERTEXMODE :
3308 glHint(GL_FOG_HINT, GL_FASTEST);
3309 switch (Value) {
3310 case D3DFOG_NONE: /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break;
3311 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break;
3312 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break;
3313 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break;
3314 default:
3315 FIXME("Unsupported Value(%lu) for WINED3DRS_FOGTABLEMODE!\n", Value);
3317 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3318 glFogi(GL_FOG_DISTANCE_MODE_NV, This->stateBlock->renderState[WINED3DRS_RANGEFOGENABLE] ? GL_EYE_RADIAL_NV : GL_EYE_PLANE_ABSOLUTE_NV);
3321 break;
3323 case WINED3DRS_FOGSTART :
3325 tmpvalue.d = Value;
3326 glFogfv(GL_FOG_START, &tmpvalue.f);
3327 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
3328 TRACE("Fog Start == %f\n", tmpvalue.f);
3330 break;
3332 case WINED3DRS_FOGEND :
3334 tmpvalue.d = Value;
3335 glFogfv(GL_FOG_END, &tmpvalue.f);
3336 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
3337 TRACE("Fog End == %f\n", tmpvalue.f);
3339 break;
3341 case WINED3DRS_FOGDENSITY :
3343 tmpvalue.d = Value;
3344 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
3345 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
3347 break;
3349 case WINED3DRS_VERTEXBLEND :
3351 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
3352 TRACE("Vertex Blending state to %ld\n", Value);
3354 break;
3356 case WINED3DRS_TWEENFACTOR :
3358 tmpvalue.d = Value;
3359 This->updateStateBlock->tween_factor = tmpvalue.f;
3360 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
3362 break;
3364 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
3366 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
3368 break;
3370 case WINED3DRS_COLORVERTEX :
3371 case WINED3DRS_DIFFUSEMATERIALSOURCE :
3372 case WINED3DRS_SPECULARMATERIALSOURCE :
3373 case WINED3DRS_AMBIENTMATERIALSOURCE :
3374 case WINED3DRS_EMISSIVEMATERIALSOURCE :
3376 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
3378 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
3379 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
3380 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
3381 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
3382 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
3383 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
3385 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
3386 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
3387 Parm = GL_AMBIENT_AND_DIFFUSE;
3388 } else {
3389 Parm = GL_DIFFUSE;
3391 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
3392 Parm = GL_AMBIENT;
3393 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
3394 Parm = GL_EMISSION;
3395 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
3396 Parm = GL_SPECULAR;
3397 } else {
3398 Parm = -1;
3401 if (Parm == -1) {
3402 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
3403 } else {
3404 This->tracking_color = NEEDS_TRACKING;
3405 This->tracking_parm = Parm;
3408 } else {
3409 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
3412 break;
3414 case WINED3DRS_LINEPATTERN :
3416 union {
3417 DWORD d;
3418 D3DLINEPATTERN lp;
3419 } tmppattern;
3420 tmppattern.d = Value;
3422 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
3424 if (tmppattern.lp.wRepeatFactor) {
3425 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
3426 checkGLcall("glLineStipple(repeat, linepattern)");
3427 glEnable(GL_LINE_STIPPLE);
3428 checkGLcall("glEnable(GL_LINE_STIPPLE);");
3429 } else {
3430 glDisable(GL_LINE_STIPPLE);
3431 checkGLcall("glDisable(GL_LINE_STIPPLE);");
3434 break;
3436 case WINED3DRS_ZBIAS : /* D3D8 only */
3438 if (Value) {
3439 tmpvalue.d = Value;
3440 TRACE("ZBias value %f\n", tmpvalue.f);
3441 glPolygonOffset(0, -tmpvalue.f);
3442 checkGLcall("glPolygonOffset(0, -Value)");
3443 glEnable(GL_POLYGON_OFFSET_FILL);
3444 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
3445 glEnable(GL_POLYGON_OFFSET_LINE);
3446 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
3447 glEnable(GL_POLYGON_OFFSET_POINT);
3448 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
3449 } else {
3450 glDisable(GL_POLYGON_OFFSET_FILL);
3451 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
3452 glDisable(GL_POLYGON_OFFSET_LINE);
3453 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
3454 glDisable(GL_POLYGON_OFFSET_POINT);
3455 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
3458 break;
3460 case WINED3DRS_NORMALIZENORMALS :
3461 if (Value) {
3462 glEnable(GL_NORMALIZE);
3463 checkGLcall("glEnable(GL_NORMALIZE);");
3464 } else {
3465 glDisable(GL_NORMALIZE);
3466 checkGLcall("glDisable(GL_NORMALIZE);");
3468 break;
3470 case WINED3DRS_POINTSIZE :
3471 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
3472 tmpvalue.d = Value;
3473 TRACE("Set point size to %f\n", tmpvalue.f);
3474 glPointSize(tmpvalue.f);
3475 checkGLcall("glPointSize(...);");
3476 break;
3478 case WINED3DRS_POINTSIZE_MIN :
3479 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
3480 tmpvalue.d = Value;
3481 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
3482 checkGLcall("glPointParameterfEXT(...);");
3483 } else {
3484 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
3486 break;
3488 case WINED3DRS_POINTSIZE_MAX :
3489 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
3490 tmpvalue.d = Value;
3491 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
3492 checkGLcall("glPointParameterfEXT(...);");
3493 } else {
3494 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
3496 break;
3498 case WINED3DRS_POINTSCALE_A :
3499 case WINED3DRS_POINTSCALE_B :
3500 case WINED3DRS_POINTSCALE_C :
3501 case WINED3DRS_POINTSCALEENABLE :
3504 * POINTSCALEENABLE controls how point size value is treated. If set to
3505 * true, the point size is scaled with repsect to height of viewport.
3506 * When set to false point size is in pixels.
3508 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
3511 /* Default values */
3512 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
3515 * Minium valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
3516 * This means that OpenGL will clamp really small point sizes to 1.0f.
3517 * To correct for this we need to multiply by the scale factor when sizes
3518 * are less than 1.0f. scale_factor = 1.0f / point_size.
3520 GLfloat pointSize = *((float*)&This->stateBlock->renderState[D3DRS_POINTSIZE]);
3521 GLfloat scaleFactor;
3522 if(pointSize < 1.0f) {
3523 scaleFactor = pointSize * pointSize;
3524 } else {
3525 scaleFactor = 1.0f;
3528 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
3529 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
3530 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
3531 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
3532 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
3533 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
3534 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
3537 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
3538 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
3539 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
3541 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
3542 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
3543 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
3544 } else {
3545 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
3547 break;
3549 case WINED3DRS_COLORWRITEENABLE :
3551 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
3552 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
3553 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
3554 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
3555 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
3556 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
3557 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
3558 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
3559 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
3560 checkGLcall("glColorMask(...)");
3562 break;
3564 case WINED3DRS_LOCALVIEWER :
3566 GLint state = (Value) ? 1 : 0;
3567 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
3568 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
3570 break;
3572 case WINED3DRS_LASTPIXEL :
3574 if (Value) {
3575 TRACE("Last Pixel Drawing Enabled\n");
3576 } else {
3577 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
3580 break;
3582 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
3584 if (Value) {
3585 TRACE("Software Processing Enabled\n");
3586 } else {
3587 TRACE("Software Processing Disabled\n");
3590 break;
3592 /** not supported */
3593 case WINED3DRS_ZVISIBLE :
3595 LEAVE_GL();
3596 return D3DERR_INVALIDCALL;
3598 case WINED3DRS_POINTSPRITEENABLE :
3600 /* TODO: NV_POINT_SPRITE */
3601 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
3602 TRACE("Point sprites not supported\n");
3603 break;
3607 * Point sprites are always enabled. Value controls texture coordinate
3608 * replacement mode. Must be set true for point sprites to use
3609 * textures.
3611 glEnable(GL_POINT_SPRITE_ARB);
3612 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
3614 if (Value) {
3615 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
3616 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
3617 } else {
3618 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
3619 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
3621 break;
3623 case WINED3DRS_EDGEANTIALIAS :
3625 if(Value) {
3626 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3627 glEnable(GL_BLEND);
3628 checkGLcall("glEnable(GL_BLEND)");
3629 glEnable(GL_LINE_SMOOTH);
3630 checkGLcall("glEnable(GL_LINE_SMOOTH)");
3631 } else {
3632 glDisable(GL_BLEND);
3633 checkGLcall("glDisable(GL_BLEND)");
3634 glDisable(GL_LINE_SMOOTH);
3635 checkGLcall("glDisable(GL_LINE_SMOOTH)");
3637 break;
3639 case WINED3DRS_WRAP0 :
3640 case WINED3DRS_WRAP1 :
3641 case WINED3DRS_WRAP2 :
3642 case WINED3DRS_WRAP3 :
3643 case WINED3DRS_WRAP4 :
3644 case WINED3DRS_WRAP5 :
3645 case WINED3DRS_WRAP6 :
3646 case WINED3DRS_WRAP7 :
3648 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
3649 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
3650 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
3651 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
3652 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
3654 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
3656 TRACE("(%p)->(%d,%ld) Texture wraping not yet supported\n",This, State, Value);
3657 break;
3658 case WINED3DRS_MULTISAMPLEANTIALIAS :
3660 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
3661 TRACE("Multisample antialiasing not supported\n");
3662 break;
3665 if(Value) {
3666 glEnable(GL_MULTISAMPLE_ARB);
3667 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
3668 } else {
3669 glDisable(GL_MULTISAMPLE_ARB);
3670 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
3672 break;
3674 case WINED3DRS_MULTISAMPLEMASK :
3675 case WINED3DRS_PATCHEDGESTYLE :
3676 case WINED3DRS_PATCHSEGMENTS :
3677 case WINED3DRS_DEBUGMONITORTOKEN :
3678 case WINED3DRS_POSITIONORDER :
3679 case WINED3DRS_NORMALORDER :
3680 /*Put back later: FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value); */
3681 FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value);
3682 break;
3683 default:
3684 FIXME("(%p)->(%d,%ld) unrecognized\n", This, State, Value);
3687 LEAVE_GL();
3689 return D3D_OK;
3692 HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
3693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3694 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
3695 *pValue = This->stateBlock->renderState[State];
3696 return D3D_OK;
3699 /*****
3700 * Get / Set Sampler States
3701 * TODO: Verify against dx9 definitions
3702 *****/
3704 HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3707 * SetSampler is designed to allow for more than the standard up to 8 textures
3708 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3709 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3711 * http://developer.nvidia.com/object/General_FAQ.html#t6
3713 * There are two new settings for GForce
3714 * the sampler one:
3715 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3716 * and the texture one:
3717 * GL_MAX_TEXTURE_COORDS_ARB.
3718 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3719 ******************/
3720 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3721 TRACE("(%p) Sampler(%ld), Type(%d) Value(%ld)\n",This, Sampler ,Type, Value);
3723 if(Sampler > GL_LIMITS(samplers) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3724 FIXME("out of range %d %d sampler %ld type %u\n", GL_LIMITS(samplers), WINED3D_HIGHEST_SAMPLER_STATE, Sampler, Type);
3725 return D3DERR_INVALIDCALL;
3727 TRACE("Setting sampler %ld %d to %ld\n", Sampler, Type, Value);
3728 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3729 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3730 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3732 /* Handle recording of state blocks */
3733 if (This->isRecordingState) {
3734 TRACE("Recording... not performing anything\n");
3735 return D3D_OK;
3738 return D3D_OK;
3741 HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3743 /** TODO: check that sampler is in range **/
3744 *Value = This->updateStateBlock->samplerState[Sampler][Type];
3745 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
3747 return D3D_OK;
3750 HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3752 ENTER_GL();
3754 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3755 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3756 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
3757 LEAVE_GL();
3759 return D3D_OK;
3762 HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3764 GLint scissorBox[4];
3766 ENTER_GL();
3767 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3768 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3769 pRect->left = scissorBox[1];
3770 pRect->top = scissorBox[2];
3771 pRect->right = scissorBox[1] + scissorBox[3];
3772 pRect->bottom = scissorBox[2] + scissorBox[4];
3773 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3774 LEAVE_GL();
3775 return D3D_OK;
3778 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3780 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3782 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3784 This->updateStateBlock->vertexDecl = pDecl;
3785 This->updateStateBlock->changed.vertexDecl = TRUE;
3786 This->updateStateBlock->set.vertexDecl = TRUE;
3788 if (This->isRecordingState) {
3789 TRACE("Recording... not performing anything\n");
3792 if (NULL != pDecl) {
3793 IWineD3DVertexDeclaration_AddRef(pDecl);
3795 if (NULL != oldDecl) {
3796 IWineD3DVertexDeclaration_Release(oldDecl);
3798 return D3D_OK;
3801 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3804 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3806 *ppDecl = This->stateBlock->vertexDecl;
3807 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3808 return D3D_OK;
3811 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3813 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3815 This->updateStateBlock->vertexShader = pShader;
3816 This->updateStateBlock->changed.vertexShader = TRUE;
3817 This->updateStateBlock->set.vertexShader = TRUE;
3819 if (This->isRecordingState) {
3820 TRACE("Recording... not performing anything\n");
3823 if (NULL != pShader) {
3824 IWineD3DVertexShader_AddRef(pShader);
3826 if (NULL != oldShader) {
3827 IWineD3DVertexShader_Release(oldShader);
3830 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3832 * TODO: merge HAL shaders context switching from prototype
3834 return D3D_OK;
3837 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3840 if (NULL == ppShader) {
3841 return D3DERR_INVALIDCALL;
3843 *ppShader = This->stateBlock->vertexShader;
3844 if( NULL != *ppShader)
3845 IWineD3DVertexShader_AddRef(*ppShader);
3847 TRACE("(%p) : returning %p\n", This, *ppShader);
3848 return D3D_OK;
3851 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstant(IWineD3DDevice *iface, void *dstData, const void *srcData, UINT type, UINT start, UINT count, UINT registersize) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 int i;
3855 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
3857 TRACE("(iface %p, dstData %p, srcData %p, type %d, start %d, count %d, registersize %d)\n",
3858 iface, dstData, srcData, type, start, count, registersize);
3860 if (type != WINESHADERCNST_NONE) {
3861 if (srcData == NULL || cnt < 0) {
3862 return D3DERR_INVALIDCALL;
3865 CopyMemory((char *)dstData + (start * registersize), srcData, cnt * registersize);
3868 for (i = start; i < cnt + start; ++i) {
3869 This->updateStateBlock->changed.vertexShaderConstants[i] = TRUE;
3870 This->updateStateBlock->set.vertexShaderConstants[i] = TRUE;
3871 This->updateStateBlock->vertexShaderConstantT[i] = type;
3874 return D3D_OK;
3877 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstant(IWineD3DDevice *iface, void *dstData, const void *srcData, UINT type, UINT start, UINT count, UINT registersize) {
3878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 int i;
3881 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
3883 TRACE("(iface %p, dstData %p, srcData %p, type %d, start %d, count %d, registersize %d)\n",
3884 iface, dstData, srcData, type, start, count, registersize);
3886 /* Verify that the requested shader constant was populated with the correct type */
3887 for (i = start; i < cnt + start; ++i) {
3888 if (This->updateStateBlock->vertexShaderConstantT[i] != type) {
3889 TRACE("(%p) : Caller requested 0x%x while type is 0x%x. Returning D3DERR_INVALIDCALL\n",
3890 This, type, This->updateStateBlock->vertexShaderConstantT[i]);
3891 return D3DERR_INVALIDCALL;
3895 if (dstData == NULL || cnt < 0) {
3896 return D3DERR_INVALIDCALL;
3899 CopyMemory(dstData, (char *)srcData + (start * registersize), cnt * registersize);
3901 return D3D_OK;
3904 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(IWineD3DDevice *iface, UINT StartRegister, CONST BOOL *pConstantData, UINT BoolCount){
3905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3907 return IWineD3DDeviceImpl_SetVertexShaderConstant(iface,
3908 This->updateStateBlock->vertexShaderConstantB,
3909 pConstantData,
3910 WINESHADERCNST_BOOL,
3911 StartRegister,
3912 BoolCount,
3913 sizeof(*pConstantData));
3916 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(IWineD3DDevice *iface, UINT StartRegister, BOOL *pConstantData, UINT BoolCount){
3917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3919 return IWineD3DDeviceImpl_GetVertexShaderConstant(iface,
3920 pConstantData,
3921 This->updateStateBlock->vertexShaderConstantB,
3922 WINESHADERCNST_BOOL,
3923 StartRegister,
3924 BoolCount,
3925 sizeof(*pConstantData));
3928 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(IWineD3DDevice *iface, UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount){
3929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3931 return IWineD3DDeviceImpl_SetVertexShaderConstant(iface,
3932 This->updateStateBlock->vertexShaderConstantI,
3933 pConstantData,
3934 WINESHADERCNST_INTEGER,
3935 StartRegister,
3936 Vector4iCount,
3937 4 * sizeof(*pConstantData));
3940 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(IWineD3DDevice *iface, UINT StartRegister, int *pConstantData, UINT Vector4iCount){
3941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 return IWineD3DDeviceImpl_GetVertexShaderConstant(iface,
3944 pConstantData,
3945 This->updateStateBlock->vertexShaderConstantI,
3946 WINESHADERCNST_INTEGER,
3947 StartRegister,
3948 Vector4iCount,
3949 4 * sizeof(*pConstantData));
3953 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(IWineD3DDevice *iface, UINT StartRegister, CONST float *pConstantData, UINT Vector4fCount){
3954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 return IWineD3DDeviceImpl_SetVertexShaderConstant(iface,
3957 This->updateStateBlock->vertexShaderConstantF,
3958 pConstantData,
3959 WINESHADERCNST_FLOAT,
3960 StartRegister,
3961 Vector4fCount,
3962 4 * sizeof(*pConstantData));
3965 HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(IWineD3DDevice *iface, UINT StartRegister, float *pConstantData, UINT Vector4fCount){
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 return IWineD3DDeviceImpl_GetVertexShaderConstant(iface,
3969 pConstantData,
3970 This->updateStateBlock->vertexShaderConstantF,
3971 WINESHADERCNST_FLOAT,
3972 StartRegister,
3973 Vector4fCount,
3974 4 * sizeof(*pConstantData));
3977 HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantN(IWineD3DDevice *iface, UINT StartRegister, UINT VectorNCount){
3978 return IWineD3DDeviceImpl_SetVertexShaderConstant(iface,
3979 NULL,
3980 NULL,
3981 WINESHADERCNST_NONE,
3982 StartRegister,
3983 VectorNCount,
3987 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3990 This->updateStateBlock->pixelShader = pShader;
3991 This->updateStateBlock->changed.pixelShader = TRUE;
3992 This->updateStateBlock->set.pixelShader = TRUE;
3994 /* Handle recording of state blocks */
3995 if (This->isRecordingState) {
3996 TRACE("Recording... not performing anything\n");
3999 if (NULL != pShader) {
4000 IWineD3DPixelShader_AddRef(pShader);
4002 if (NULL != oldShader) {
4003 IWineD3DPixelShader_Release(oldShader);
4006 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4008 * TODO: merge HAL shaders context switching from prototype
4010 return D3D_OK;
4013 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 if (NULL == ppShader) {
4017 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4018 return D3DERR_INVALIDCALL;
4021 *ppShader = This->stateBlock->pixelShader;
4022 if (NULL != ppShader) {
4023 IWineD3DPixelShader_AddRef(*ppShader);
4025 TRACE("(%p) : returning %p\n", This, *ppShader);
4026 return D3D_OK;
4029 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstant(IWineD3DDevice *iface, void *dstData, const void *srcData, UINT type, UINT start, UINT count, UINT registersize) {
4030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int i;
4033 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4035 TRACE("(iface %p, dstData %p, srcData %p, type %d, start %d, count %d, registersize %d)\n",
4036 iface, dstData, srcData, type, start, count, registersize);
4038 if (type != WINESHADERCNST_NONE) {
4039 if (srcData == NULL || cnt < 0) {
4040 return D3DERR_INVALIDCALL;
4043 CopyMemory((char *)dstData + (start * registersize), srcData, cnt * registersize);
4046 for (i = start; i < cnt + start; ++i) {
4047 This->updateStateBlock->changed.pixelShaderConstants[i] = TRUE;
4048 This->updateStateBlock->set.pixelShaderConstants[i] = TRUE;
4049 This->updateStateBlock->pixelShaderConstantT[i] = type;
4052 return D3D_OK;
4055 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstant(IWineD3DDevice *iface, void *dstData, const void *srcData, UINT type, UINT start, UINT count, UINT registersize) {
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4058 int i;
4059 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4061 TRACE("(iface %p, dstData %p, srcData %p, type %d, start %d, count %d, registersize %d)\n",
4062 iface, dstData, srcData, type, start, count, registersize);
4064 /* Verify that the requested shader constant was populated with the correct type */
4065 for (i = start; i < cnt + start; ++i) {
4066 if (This->updateStateBlock->pixelShaderConstantT[i] != type) {
4067 TRACE("(%p) : Caller requested 0x%x while type is 0x%x. Returning D3DERR_INVALIDCALL\n",
4068 This, type, This->updateStateBlock->pixelShaderConstantT[i]);
4069 return D3DERR_INVALIDCALL;
4073 if (dstData == NULL || cnt < 0) {
4074 return D3DERR_INVALIDCALL;
4077 CopyMemory(dstData, (char *)srcData + (start * registersize), cnt * registersize);
4079 return D3D_OK;
4082 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(IWineD3DDevice *iface, UINT StartRegister, CONST BOOL *pConstantData, UINT BoolCount) {
4083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4085 return IWineD3DDeviceImpl_SetPixelShaderConstant(iface,
4086 This->updateStateBlock->pixelShaderConstantB,
4087 pConstantData,
4088 WINESHADERCNST_BOOL,
4089 StartRegister,
4090 BoolCount,
4091 sizeof(*pConstantData));
4094 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(IWineD3DDevice *iface, UINT StartRegister, BOOL *pConstantData, UINT BoolCount) {
4095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4097 return IWineD3DDeviceImpl_GetPixelShaderConstant(iface,
4098 pConstantData,
4099 This->updateStateBlock->pixelShaderConstantB,
4100 WINESHADERCNST_BOOL,
4101 StartRegister,
4102 BoolCount,
4103 sizeof(*pConstantData));
4106 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(IWineD3DDevice *iface, UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount) {
4107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 return IWineD3DDeviceImpl_SetPixelShaderConstant(iface,
4110 This->updateStateBlock->pixelShaderConstantI,
4111 pConstantData,
4112 WINESHADERCNST_INTEGER,
4113 StartRegister,
4114 Vector4iCount,
4115 4 * sizeof(*pConstantData));
4118 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(IWineD3DDevice *iface, UINT StartRegister, int *pConstantData, UINT Vector4iCount) {
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4121 return IWineD3DDeviceImpl_GetPixelShaderConstant(iface,
4122 pConstantData,
4123 This->updateStateBlock->pixelShaderConstantI,
4124 WINESHADERCNST_INTEGER,
4125 StartRegister,
4126 Vector4iCount,
4127 4 * sizeof(*pConstantData));
4130 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(IWineD3DDevice *iface, UINT StartRegister, CONST float *pConstantData, UINT Vector4fCount) {
4131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 return IWineD3DDeviceImpl_SetPixelShaderConstant(iface,
4134 This->updateStateBlock->pixelShaderConstantF,
4135 pConstantData,
4136 WINESHADERCNST_FLOAT,
4137 StartRegister,
4138 Vector4fCount,
4139 4 * sizeof(*pConstantData));
4142 HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(IWineD3DDevice *iface, UINT StartRegister, float *pConstantData, UINT Vector4fCount) {
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145 return IWineD3DDeviceImpl_GetPixelShaderConstant(iface,
4146 pConstantData,
4147 This->updateStateBlock->pixelShaderConstantF,
4148 WINESHADERCNST_FLOAT,
4149 StartRegister,
4150 Vector4fCount,
4151 4 * sizeof(*pConstantData));
4154 HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantN(IWineD3DDevice *iface, UINT StartRegister, UINT VectorNCount){
4155 return IWineD3DDeviceImpl_SetPixelShaderConstant(iface,
4156 NULL,
4157 NULL,
4158 WINESHADERCNST_NONE,
4159 StartRegister,
4160 VectorNCount,
4164 HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4166 FIXME("(%p) : stub\n", This);
4167 return D3D_OK;
4170 /*****
4171 * Apply / Get / Set Texture Stage States
4172 * TODO: Verify against dx9 definitions
4173 *****/
4175 /* NOTE: It's expected that this function is going to be called lots of times with the same stage active, so make it the callers responsibility to GLACTIVETEXTURE(Stage) for better state management. Set the correct Texture unit active before calling ApplyTextureStageState */
4176 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4178 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4179 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4181 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4183 /* Check that the stage is within limits */
4184 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
4185 TRACE("Attempt to access invalid texture rejected\n");
4186 return;
4189 ENTER_GL();
4191 switch (Type) {
4192 case WINED3DTSS_ALPHAOP :
4193 case WINED3DTSS_COLOROP :
4194 /* nothing to do as moved to drawprim for now */
4195 break;
4196 case WINED3DTSS_ADDRESSW :
4197 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
4198 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4199 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
4201 } else {
4202 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
4203 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
4204 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
4205 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
4207 #endif
4208 case WINED3DTSS_TEXCOORDINDEX :
4210 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
4212 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
4213 one flag, you can still specify an index value, which the system uses to
4214 determine the texture wrapping mode.
4215 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
4216 means use the vertex position (camera-space) as the input texture coordinates
4217 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
4218 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
4219 to the TEXCOORDINDEX value */
4222 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
4224 switch (Value & 0xFFFF0000) {
4225 case D3DTSS_TCI_PASSTHRU:
4226 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
4227 glDisable(GL_TEXTURE_GEN_S);
4228 glDisable(GL_TEXTURE_GEN_T);
4229 glDisable(GL_TEXTURE_GEN_R);
4230 glDisable(GL_TEXTURE_GEN_Q);
4231 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
4232 break;
4234 case D3DTSS_TCI_CAMERASPACEPOSITION:
4235 /* CameraSpacePosition means use the vertex position, transformed to camera space,
4236 as the input texture coordinates for this stage's texture transformation. This
4237 equates roughly to EYE_LINEAR */
4239 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4240 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4241 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4242 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4243 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
4245 glMatrixMode(GL_MODELVIEW);
4246 glPushMatrix();
4247 glLoadIdentity();
4248 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4249 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4250 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4251 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4252 glPopMatrix();
4254 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
4255 glEnable(GL_TEXTURE_GEN_S);
4256 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4257 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4258 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4259 glEnable(GL_TEXTURE_GEN_T);
4260 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4261 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4262 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4263 glEnable(GL_TEXTURE_GEN_R);
4264 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4265 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4266 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4268 break;
4270 case D3DTSS_TCI_CAMERASPACENORMAL:
4272 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4273 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4274 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4275 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4276 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4277 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
4279 glMatrixMode(GL_MODELVIEW);
4280 glPushMatrix();
4281 glLoadIdentity();
4282 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4283 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4284 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4285 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4286 glPopMatrix();
4288 glEnable(GL_TEXTURE_GEN_S);
4289 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4290 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4291 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4292 glEnable(GL_TEXTURE_GEN_T);
4293 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4294 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4295 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4296 glEnable(GL_TEXTURE_GEN_R);
4297 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4298 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4299 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4302 break;
4304 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
4306 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4307 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4308 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4309 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4310 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4311 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
4313 glMatrixMode(GL_MODELVIEW);
4314 glPushMatrix();
4315 glLoadIdentity();
4316 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4317 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4318 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4319 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4320 glPopMatrix();
4322 glEnable(GL_TEXTURE_GEN_S);
4323 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4324 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4325 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4326 glEnable(GL_TEXTURE_GEN_T);
4327 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4328 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4329 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4330 glEnable(GL_TEXTURE_GEN_R);
4331 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4332 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4333 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4336 break;
4338 /* Unhandled types: */
4339 default:
4340 /* Todo: */
4341 /* ? disable GL_TEXTURE_GEN_n ? */
4342 glDisable(GL_TEXTURE_GEN_S);
4343 glDisable(GL_TEXTURE_GEN_T);
4344 glDisable(GL_TEXTURE_GEN_R);
4345 glDisable(GL_TEXTURE_GEN_Q);
4346 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
4347 break;
4350 break;
4352 /* Unhandled */
4353 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4354 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
4355 break;
4357 case WINED3DTSS_BUMPENVMAT00 :
4358 case WINED3DTSS_BUMPENVMAT01 :
4359 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4360 break;
4361 case WINED3DTSS_BUMPENVMAT10 :
4362 case WINED3DTSS_BUMPENVMAT11 :
4363 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4364 break;
4366 case WINED3DTSS_BUMPENVLSCALE :
4367 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
4368 break;
4370 case WINED3DTSS_BUMPENVLOFFSET :
4371 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
4372 break;
4374 case WINED3DTSS_RESULTARG :
4375 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
4376 break;
4378 default:
4379 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
4380 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
4383 LEAVE_GL();
4385 return;
4388 /*****
4389 * Get / Set Texture Stage States
4390 * TODO: Verify against dx9 definitions
4391 *****/
4392 HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4397 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4399 /* Reject invalid texture units */
4400 if (Stage >= GL_LIMITS(textures)) {
4401 TRACE("Attempt to access invalid texture rejected\n");
4402 return D3DERR_INVALIDCALL;
4405 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4406 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4407 This->updateStateBlock->textureState[Stage][Type] = Value;
4409 return D3D_OK;
4412 HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4415 *pValue = This->updateStateBlock->textureState[Stage][Type];
4416 return D3D_OK;
4419 /*****
4420 * Get / Set Texture
4421 *****/
4422 HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 IWineD3DBaseTexture *oldTexture;
4427 oldTexture = This->updateStateBlock->textures[Stage];
4428 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
4430 #if 0 /* TODO: check so vertex textures */
4431 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4432 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4433 return D3D_OK;
4435 #endif
4437 /* Reject invalid texture units */
4438 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
4439 WARN("Attempt to access invalid texture rejected\n");
4440 return D3DERR_INVALIDCALL;
4443 if(pTexture != NULL) {
4444 /* SetTexture isn't allowed on textures in D3DPOOL_SCRATCH; The same is
4445 * the case for D3DPOOL_SYSTEMMEM textures unless D3DDEVCAPS_TEXTURESYSTEMMORY is set.
4446 * We don't check the caps as GetDeviceCaps is inefficient and we don't set the cap anyway.
4448 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == D3DPOOL_SCRATCH || ((IWineD3DTextureImpl*)pTexture)->resource.pool == D3DPOOL_SYSTEMMEM) {
4449 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4450 return D3DERR_INVALIDCALL;
4454 oldTexture = This->updateStateBlock->textures[Stage];
4455 TRACE("GL_LIMITS %d\n",GL_LIMITS(textures));
4456 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4458 This->updateStateBlock->set.textures[Stage] = TRUE;
4459 This->updateStateBlock->changed.textures[Stage] = TRUE;
4460 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4461 This->updateStateBlock->textures[Stage] = pTexture;
4463 /* Handle recording of state blocks */
4464 if (This->isRecordingState) {
4465 TRACE("Recording... not performing anything\n");
4466 return D3D_OK;
4469 /** NOTE: MSDN says that setTexture increases the reference count,
4470 * and the the application nust set the texture back to null (or have a leaky application),
4471 * This means we should pass the refcount up to the parent
4472 *******************************/
4473 if (NULL != This->updateStateBlock->textures[Stage]) {
4474 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4477 if (NULL != oldTexture) {
4478 IWineD3DBaseTexture_Release(oldTexture);
4481 return D3D_OK;
4484 HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4488 /* Reject invalid texture units */
4489 if (Stage >= GL_LIMITS(textures)) {
4490 TRACE("Attempt to access invalid texture rejected\n");
4491 return D3DERR_INVALIDCALL;
4493 *ppTexture=This->updateStateBlock->textures[Stage];
4494 if (*ppTexture)
4495 IWineD3DBaseTexture_AddRef(*ppTexture);
4496 else
4497 return D3DERR_INVALIDCALL;
4498 return D3D_OK;
4501 /*****
4502 * Get Back Buffer
4503 *****/
4504 HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, D3DBACKBUFFER_TYPE Type,
4505 IWineD3DSurface **ppBackBuffer) {
4506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4507 IWineD3DSwapChain *swapChain;
4508 HRESULT hr;
4510 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4512 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4513 if (hr == D3D_OK) {
4514 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4515 IWineD3DSwapChain_Release(swapChain);
4516 } else {
4517 *ppBackBuffer = NULL;
4519 return hr;
4522 HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 WARN("(%p) : stub, calling idirect3d for now\n", This);
4525 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4528 HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, D3DDISPLAYMODE* pMode) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 IWineD3DSwapChain *swapChain;
4531 HRESULT hr;
4533 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4534 if (hr == D3D_OK) {
4535 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4536 IWineD3DSwapChain_Release(swapChain);
4537 } else {
4538 FIXME("(%p) Error getting display mode\n", This);
4540 return hr;
4542 /*****
4543 * Stateblock related functions
4544 *****/
4546 HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 IWineD3DStateBlockImpl *object;
4549 TRACE("(%p)", This);
4551 if (This->isRecordingState) {
4552 return D3DERR_INVALIDCALL;
4555 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4556 if (NULL == object ) {
4557 FIXME("(%p)Error allocating memory for stateblock\n", This);
4558 return E_OUTOFMEMORY;
4560 TRACE("(%p) creted object %p\n", This, object);
4561 object->wineD3DDevice= This;
4562 /** FIXME: object->parent = parent; **/
4563 object->parent = NULL;
4564 object->blockType = WINED3DSBT_ALL;
4565 object->ref = 1;
4566 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4568 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4569 This->updateStateBlock = object;
4570 This->isRecordingState = TRUE;
4572 TRACE("(%p) recording stateblock %p\n",This , object);
4573 return D3D_OK;
4576 HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 if (!This->isRecordingState) {
4580 FIXME("(%p) not recording! returning error\n", This);
4581 *ppStateBlock = NULL;
4582 return D3DERR_INVALIDCALL;
4585 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4586 This->isRecordingState = FALSE;
4587 This->updateStateBlock = This->stateBlock;
4588 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4589 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4590 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4591 return D3D_OK;
4594 /*****
4595 * Scene related functions
4596 *****/
4597 HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4598 /* At the moment we have no need for any functionality at the beginning
4599 of a scene */
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4601 TRACE("(%p) : stub\n", This);
4602 return D3D_OK;
4605 HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 TRACE("(%p)\n", This);
4608 ENTER_GL();
4609 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4610 glFlush();
4611 checkGLcall("glFlush");
4613 TRACE("End Scene\n");
4614 if(This->renderTarget != NULL) {
4616 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4617 IUnknown *targetContainer = NULL;
4618 if (D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4619 || D3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
4620 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
4621 /** always dirtify for now. we must find a better way to see that surface have been modified
4622 (Modifications should will only occur via draw-primitive, but we do need better locking
4623 switching to render-to-texture should remove the overhead though.
4625 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
4626 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
4627 IWineD3DSurface_PreLoad(This->renderTarget);
4628 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
4629 IUnknown_Release(targetContainer);
4632 This->sceneEnded = TRUE;
4633 LEAVE_GL();
4634 return D3D_OK;
4637 HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4638 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4639 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 IWineD3DSwapChain *swapChain = NULL;
4642 int i;
4643 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4645 TRACE("(%p) Presenting the frame\n", This);
4647 for(i = 0 ; i < swapchains ; i ++) {
4649 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4650 TRACE("presentinng chain %d, %p\n", i, swapChain);
4651 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4652 IWineD3DSwapChain_Release(swapChain);
4655 return D3D_OK;
4658 HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
4659 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
4663 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
4664 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4665 GLbitfield glMask = 0;
4666 GLboolean old_ztest;
4667 GLfloat old_z_clear_value;
4668 GLint old_stencil_clear_value;
4669 GLfloat old_color_clear_value[4];
4670 unsigned int i;
4671 CONST D3DRECT* curRect;
4673 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
4674 Count, pRects, Flags, Z, Stencil);
4676 ENTER_GL();
4678 glEnable(GL_SCISSOR_TEST);
4679 checkGLcall("glEnable GL_SCISSOR_TEST");
4681 if (Count > 0 && pRects) {
4682 curRect = pRects;
4683 } else {
4684 curRect = NULL;
4687 /* Only set the values up once, as they are not changing */
4688 if (Flags & D3DCLEAR_STENCIL) {
4689 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4690 glClearStencil(Stencil);
4691 checkGLcall("glClearStencil");
4692 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4693 glStencilMask(0xFFFFFFFF);
4696 if (Flags & D3DCLEAR_ZBUFFER) {
4697 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4698 glDepthMask(GL_TRUE);
4699 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4700 glClearDepth(Z);
4701 checkGLcall("glClearDepth");
4702 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4705 if (Flags & D3DCLEAR_TARGET) {
4706 TRACE("Clearing screen with glClear to color %lx\n", Color);
4707 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4708 glClearColor(D3DCOLOR_R(Color),
4709 D3DCOLOR_G(Color),
4710 D3DCOLOR_B(Color),
4711 D3DCOLOR_A(Color));
4712 checkGLcall("glClearColor");
4714 /* Clear ALL colors! */
4715 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4716 glMask = glMask | GL_COLOR_BUFFER_BIT;
4719 /* Now process each rect in turn */
4720 for (i = 0; i < Count || i == 0; i++) {
4722 if (curRect) {
4723 /* Note gl uses lower left, width/height */
4724 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
4725 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4726 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
4727 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4728 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
4729 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4730 checkGLcall("glScissor");
4731 } else {
4732 glScissor(This->stateBlock->viewport.X,
4733 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
4734 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4735 This->stateBlock->viewport.Width,
4736 This->stateBlock->viewport.Height);
4737 checkGLcall("glScissor");
4740 /* Clear the selected rectangle (or full screen) */
4741 glClear(glMask);
4742 checkGLcall("glClear");
4744 /* Step to the next rectangle */
4745 if (curRect) curRect = curRect + sizeof(D3DRECT);
4748 /* Restore the old values (why..?) */
4749 if (Flags & D3DCLEAR_STENCIL) {
4750 glClearStencil(old_stencil_clear_value);
4751 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4753 if (Flags & D3DCLEAR_ZBUFFER) {
4754 glDepthMask(old_ztest);
4755 glClearDepth(old_z_clear_value);
4757 if (Flags & D3DCLEAR_TARGET) {
4758 glClearColor(old_color_clear_value[0],
4759 old_color_clear_value[1],
4760 old_color_clear_value[2],
4761 old_color_clear_value[3]);
4762 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4763 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4764 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4765 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4768 glDisable(GL_SCISSOR_TEST);
4769 checkGLcall("glDisable");
4770 LEAVE_GL();
4772 return D3D_OK;
4775 /*****
4776 * Drawing functions
4777 *****/
4778 HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4779 UINT PrimitiveCount) {
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 This->stateBlock->streamIsUP = FALSE;
4784 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4785 debug_d3dprimitivetype(PrimitiveType),
4786 StartVertex, PrimitiveCount);
4787 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4788 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4791 return D3D_OK;
4794 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4795 HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4796 D3DPRIMITIVETYPE PrimitiveType,
4797 INT baseVIndex, UINT minIndex,
4798 UINT NumVertices, UINT startIndex, UINT primCount) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 UINT idxStride = 2;
4802 IWineD3DIndexBuffer *pIB;
4803 D3DINDEXBUFFER_DESC IdxBufDsc;
4805 pIB = This->stateBlock->pIndexData;
4806 This->stateBlock->streamIsUP = FALSE;
4808 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
4809 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4810 minIndex, NumVertices, startIndex, baseVIndex, primCount);
4812 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4813 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4814 idxStride = 2;
4815 } else {
4816 idxStride = 4;
4819 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
4820 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4822 return D3D_OK;
4825 HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
4826 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4827 UINT VertexStreamZeroStride) {
4828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4830 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4831 debug_d3dprimitivetype(PrimitiveType),
4832 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4834 /* release the stream source */
4835 if (This->stateBlock->streamSource[0] != NULL) {
4836 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4839 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4840 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4841 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4842 This->stateBlock->streamIsUP = TRUE;
4844 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4845 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4846 /* stream zero settings set to null at end, as per the msdn
4847 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawPrimitiveUP.asp
4849 This->stateBlock->streamStride[0] = 0;
4850 This->stateBlock->streamSource[0] = NULL;
4852 /*stream zero settings set to null at end, as per the msdn */
4853 return D3D_OK;
4856 HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
4857 UINT MinVertexIndex, UINT NumVertices,
4858 UINT PrimitiveCount, CONST void* pIndexData,
4859 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4860 UINT VertexStreamZeroStride) {
4861 int idxStride;
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4865 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4866 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4867 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4869 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4870 idxStride = 2;
4871 } else {
4872 idxStride = 4;
4875 /* release the stream and index data */
4876 if (This->stateBlock->streamSource[0] != NULL) {
4877 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4879 if (This->stateBlock->pIndexData) {
4880 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
4883 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4884 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4885 This->stateBlock->streamIsUP = TRUE;
4886 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4888 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4889 /* stream zero settings set to null at end as per the msdn
4890 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawPrimitiveUP.asp
4893 /* stream zero settings set to null at end as per the msdn */
4894 This->stateBlock->streamSource[0] = NULL;
4895 This->stateBlock->streamStride[0] = 0;
4897 return D3D_OK;
4900 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4901 HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 HRESULT hr = D3D_OK;
4904 D3DRESOURCETYPE sourceType;
4905 D3DRESOURCETYPE destinationType;
4906 int i ,levels;
4908 /* TODO: think about moving the code into IWineD3DBaseTexture */
4910 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4912 /* verify that the source and destination textures aren't NULL */
4913 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4914 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning D3DERR_INVALIDCALL\n",
4915 This, pSourceTexture, pDestinationTexture);
4916 hr = D3DERR_INVALIDCALL;
4919 if (pSourceTexture == pDestinationTexture) {
4920 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning D3DERR_INVALIDCALL\n",
4921 This, pSourceTexture, pDestinationTexture);
4922 hr = D3DERR_INVALIDCALL;
4924 /* Verify that the source and destination textures are the same type */
4925 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4926 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4928 if (sourceType != destinationType) {
4929 WARN("(%p) Sorce and destination types must match, returning D3DERR_INVALIDCALL\n",
4930 This);
4931 hr = D3DERR_INVALIDCALL;
4934 /* check that both textures have the identical numbers of levels */
4935 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4936 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning D3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4937 hr = D3DERR_INVALIDCALL;
4940 if (D3D_OK == hr) {
4942 /* Make sure that the destination texture is loaded */
4943 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4945 /* Update every surface level of the texture */
4946 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4948 switch (sourceType) {
4949 case D3DRTYPE_TEXTURE:
4951 IWineD3DSurface *srcSurface;
4952 IWineD3DSurface *destSurface;
4954 for (i = 0 ; i < levels ; ++i) {
4955 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4956 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4957 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4958 IWineD3DSurface_Release(srcSurface);
4959 IWineD3DSurface_Release(destSurface);
4960 if (D3D_OK != hr) {
4961 WARN("(%p) : Call to update surface failed\n", This);
4962 return hr;
4966 break;
4967 case D3DRTYPE_CUBETEXTURE:
4969 IWineD3DSurface *srcSurface;
4970 IWineD3DSurface *destSurface;
4971 D3DCUBEMAP_FACES faceType;
4973 for (i = 0 ; i < levels ; ++i) {
4974 /* Update each cube face */
4975 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4976 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4977 if (D3D_OK != hr) {
4978 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4979 } else {
4980 TRACE("Got srcSurface %p\n", srcSurface);
4982 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4983 if (D3D_OK != hr) {
4984 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4985 } else {
4986 TRACE("Got desrSurface %p\n", destSurface);
4988 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4989 IWineD3DSurface_Release(srcSurface);
4990 IWineD3DSurface_Release(destSurface);
4991 if (D3D_OK != hr) {
4992 WARN("(%p) : Call to update surface failed\n", This);
4993 return hr;
4998 break;
4999 #if 0 /* TODO: Add support for volume textures */
5000 case D3DRTYPE_VOLUMETEXTURE:
5002 IWineD3DVolume srcVolume = NULL;
5003 IWineD3DSurface destVolume = NULL;
5005 for (i = 0 ; i < levels ; ++i) {
5006 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5007 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5008 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5009 IWineD3DVolume_Release(srcSurface);
5010 IWineD3DVolume_Release(destSurface);
5011 if (D3D_OK != hr) {
5012 WARN("(%p) : Call to update volume failed\n", This);
5013 return hr;
5017 break;
5018 #endif
5019 default:
5020 FIXME("(%p) : Unsupported source and destination type\n", This);
5021 hr = D3DERR_INVALIDCALL;
5025 return hr;
5028 HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5029 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5030 CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) {
5031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5033 TRACE("(%p) : stub\n", This);
5034 return D3D_OK;
5036 HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5038 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5039 * NOTE It may be best to move the code into surface to occomplish this
5040 ****************************************/
5042 WINED3DSURFACE_DESC surfaceDesc;
5043 unsigned int surfaceWidth, surfaceHeight;
5044 glDescriptor *targetGlDescription = NULL;
5045 glDescriptor *surfaceGlDescription = NULL;
5046 IWineD3DSwapChainImpl *container = NULL;
5048 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5049 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5050 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5052 surfaceDesc.Width = &surfaceWidth;
5053 surfaceDesc.Height = &surfaceHeight;
5054 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5055 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5057 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5058 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5059 ENTER_GL();
5060 /* TODO: opengl Context switching for swapchains etc... */
5061 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
5062 if (NULL != container && (pRenderTarget == container->backBuffer)) {
5063 glReadBuffer(GL_BACK);
5064 vcheckGLcall("glReadBuffer(GL_BACK)");
5065 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
5066 glReadBuffer(GL_FRONT);
5067 vcheckGLcall("glReadBuffer(GL_FRONT)");
5068 } else if (pRenderTarget == This->depthStencilBuffer) {
5069 FIXME("Reading of depthstencil not yet supported\n");
5072 glReadPixels(surfaceGlDescription->target,
5073 surfaceGlDescription->level,
5074 surfaceWidth,
5075 surfaceHeight,
5076 surfaceGlDescription->glFormat,
5077 surfaceGlDescription->glType,
5078 (void *)IWineD3DSurface_GetData(pSurface));
5079 vcheckGLcall("glReadPixels(...)");
5080 if(NULL != container ){
5081 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5083 } else {
5084 IWineD3DBaseTexture *container;
5085 GLenum textureDimensions = GL_TEXTURE_2D;
5087 if (D3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5088 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5089 IWineD3DBaseTexture_Release(container);
5091 /* TODO: 2D -> Cube surface coppies etc.. */
5092 if (surfaceGlDescription->target != textureDimensions) {
5093 FIXME("(%p) : Texture dimension mismatch\n", This);
5095 glEnable(textureDimensions);
5096 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5097 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5098 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5099 vcheckGLcall("glBindTexture");
5100 glGetTexImage(surfaceGlDescription->target,
5101 surfaceGlDescription->level,
5102 surfaceGlDescription->glFormat,
5103 surfaceGlDescription->glType,
5104 (void *)IWineD3DSurface_GetData(pSurface));
5105 glDisable(textureDimensions);
5106 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5109 LEAVE_GL();
5110 return D3D_OK;
5113 HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5114 IWineD3DSwapChain *swapChain;
5115 HRESULT hr;
5116 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5117 if(hr == D3D_OK) {
5118 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5119 IWineD3DSwapChain_Release(swapChain);
5121 return hr;
5124 HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 /* return a sensible default */
5127 *pNumPasses = 1;
5128 /* TODO: If the window is minimized then validate device should return something other than d3d_ok */
5129 FIXME("(%p) : stub\n", This);
5130 return D3D_OK;
5133 HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 int j;
5136 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5137 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5138 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5139 return D3DERR_INVALIDCALL;
5141 for (j = 0; j < 256; ++j) {
5142 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5143 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5144 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5145 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5147 TRACE("(%p) : returning\n", This);
5148 return D3D_OK;
5151 HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5153 int j;
5154 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5155 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5156 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5157 return D3DERR_INVALIDCALL;
5159 for (j = 0; j < 256; ++j) {
5160 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5161 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5162 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5163 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5165 TRACE("(%p) : returning\n", This);
5166 return D3D_OK;
5169 HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5172 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5173 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5174 return D3DERR_INVALIDCALL;
5176 /*TODO: stateblocks */
5177 This->currentPalette = PaletteNumber;
5178 TRACE("(%p) : returning\n", This);
5179 return D3D_OK;
5182 HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5184 if (PaletteNumber == NULL) {
5185 WARN("(%p) : returning Invalid Call\n", This);
5186 return D3DERR_INVALIDCALL;
5188 /*TODO: stateblocks */
5189 *PaletteNumber = This->currentPalette;
5190 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5191 return D3D_OK;
5194 HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 static BOOL showFixmes = TRUE;
5197 if (showFixmes) {
5198 FIXME("(%p) : stub\n", This);
5199 showFixmes = FALSE;
5202 This->softwareVertexProcessing = bSoftware;
5203 return D3D_OK;
5207 BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5209 static BOOL showFixmes = TRUE;
5210 if (showFixmes) {
5211 FIXME("(%p) : stub\n", This);
5212 showFixmes = FALSE;
5214 return This->softwareVertexProcessing;
5218 HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) {
5219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5220 IWineD3DSwapChain *swapChain;
5221 HRESULT hr;
5223 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5225 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5226 if(hr == D3D_OK){
5227 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5228 IWineD3DSwapChain_Release(swapChain);
5229 }else{
5230 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5232 return hr;
5236 HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 static BOOL showfixmes = TRUE;
5239 if(nSegments != 0.0f) {
5240 if( showfixmes) {
5241 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5242 showfixmes = FALSE;
5245 return D3D_OK;
5248 float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 static BOOL showfixmes = TRUE;
5251 if( showfixmes) {
5252 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5253 showfixmes = FALSE;
5255 return 0.0f;
5258 HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5260 /** TODO: remove casts to IWineD3DSurfaceImpl
5261 * NOTE: move code to surface to accomplish this
5262 ****************************************/
5263 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5264 int srcWidth, srcHeight;
5265 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5266 WINED3DFORMAT destFormat, srcFormat;
5267 UINT destSize;
5268 int destLeft, destTop;
5269 D3DPOOL srcPool, destPool;
5270 int offset = 0;
5271 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5272 glDescriptor *glDescription = NULL;
5273 GLenum textureDimensions = GL_TEXTURE_2D;
5274 IWineD3DBaseTexture *baseTexture;
5276 WINED3DSURFACE_DESC winedesc;
5278 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5279 memset(&winedesc, 0, sizeof(winedesc));
5280 winedesc.Width = &srcSurfaceWidth;
5281 winedesc.Height = &srcSurfaceHeight;
5282 winedesc.Pool = &srcPool;
5283 winedesc.Format = &srcFormat;
5285 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5287 winedesc.Width = &destSurfaceWidth;
5288 winedesc.Height = &destSurfaceHeight;
5289 winedesc.Pool = &destPool;
5290 winedesc.Format = &destFormat;
5291 winedesc.Size = &destSize;
5293 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5295 if(srcPool != D3DPOOL_SYSTEMMEM || destPool != D3DPOOL_DEFAULT){
5296 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning D3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5297 return D3DERR_INVALIDCALL;
5300 if (destFormat == WINED3DFMT_UNKNOWN) {
5301 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5302 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5304 /* Get the update surface description */
5305 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5308 /* Make sure the surface is loaded and up to date */
5309 IWineD3DSurface_PreLoad(pDestinationSurface);
5311 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5313 ENTER_GL();
5315 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5316 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5317 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5318 destLeft = pDestPoint ? pDestPoint->x : 0;
5319 destTop = pDestPoint ? pDestPoint->y : 0;
5322 /* This function doesn't support compressed textures
5323 the pitch is just bytesPerPixel * width */
5324 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5325 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5326 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5327 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5329 /* TODO DXT formats */
5331 if(pSourceRect != NULL && pSourceRect->top != 0){
5332 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5334 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5335 ,This
5336 ,glDescription->level
5337 ,destLeft
5338 ,destTop
5339 ,srcWidth
5340 ,srcHeight
5341 ,glDescription->glFormat
5342 ,glDescription->glType
5343 ,IWineD3DSurface_GetData(pSourceSurface)
5346 /* Sanity check */
5347 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5349 /* need to lock the surface to get the data */
5350 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5353 /* TODO: Cube and volume support */
5354 if(rowoffset != 0){
5355 /* not a whole row so we have to do it a line at a time */
5356 int j;
5358 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5359 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5361 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5363 glTexSubImage2D(glDescription->target
5364 ,glDescription->level
5365 ,destLeft
5367 ,srcWidth
5369 ,glDescription->glFormat
5370 ,glDescription->glType
5371 ,data /* could be quicker using */
5373 data += rowoffset;
5376 } else { /* Full width, so just write out the whole texture */
5378 if (WINED3DFMT_DXT1 == destFormat ||
5379 WINED3DFMT_DXT2 == destFormat ||
5380 WINED3DFMT_DXT3 == destFormat ||
5381 WINED3DFMT_DXT4 == destFormat ||
5382 WINED3DFMT_DXT5 == destFormat) {
5383 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5384 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5385 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
5386 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5387 } if (destFormat != srcFormat) {
5388 FIXME("Updating mixed format compressed texture is not curretly support\n");
5389 } else {
5390 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5391 glDescription->level,
5392 glDescription->glFormatInternal,
5393 srcWidth,
5394 srcHeight,
5396 destSize,
5397 IWineD3DSurface_GetData(pSourceSurface));
5399 } else {
5400 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5404 } else {
5405 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5407 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5408 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5409 data returned by GetData non-power2 width/height with hardware non-power2
5410 pow2Width/height are set to surface width height, repacking isn't needed so it
5411 doesn't matter which function gets called. */
5412 glTexSubImage2D(glDescription->target
5413 ,glDescription->level
5414 ,destLeft
5415 ,destTop
5416 ,srcWidth
5417 ,srcHeight
5418 ,glDescription->glFormat
5419 ,glDescription->glType
5420 ,IWineD3DSurface_GetData(pSourceSurface)
5422 } else {
5424 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5425 glTexSubImage2D(glDescription->target
5426 ,glDescription->level
5427 ,destLeft
5428 ,destTop
5429 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5430 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5431 ,glDescription->glFormat
5432 ,glDescription->glType
5433 ,IWineD3DSurface_GetData(pSourceSurface)
5439 checkGLcall("glTexSubImage2D");
5441 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5442 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5443 * surface bigger than it needs to be hmm.. */
5444 if (D3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5445 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5446 IWineD3DBaseTexture_Release(baseTexture);
5449 glDisable(textureDimensions); /* This needs to be managed better.... */
5450 LEAVE_GL();
5452 return D3D_OK;
5455 /* Used by DirectX 8 */
5456 HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
5457 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
5458 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
5460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5461 HRESULT hr = D3D_OK;
5462 WINED3DFORMAT srcFormat, destFormat;
5463 UINT srcWidth, destWidth;
5464 UINT srcHeight, destHeight;
5465 UINT srcSize;
5466 WINED3DSURFACE_DESC winedesc;
5468 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
5469 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
5472 /* Check that the source texture is in D3DPOOL_SYSTEMMEM and the destination texture is in D3DPOOL_DEFAULT */
5473 memset(&winedesc, 0, sizeof(winedesc));
5475 winedesc.Format = &srcFormat;
5476 winedesc.Width = &srcWidth;
5477 winedesc.Height = &srcHeight;
5478 winedesc.Size = &srcSize;
5479 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5481 winedesc.Format = &destFormat;
5482 winedesc.Width = &destWidth;
5483 winedesc.Height = &destHeight;
5484 winedesc.Size = NULL;
5485 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5487 /* Check that the source and destination formats match */
5488 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
5489 WARN("(%p) source %p format must match the dest %p format, returning D3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
5490 return D3DERR_INVALIDCALL;
5491 } else if (WINED3DFMT_UNKNOWN == destFormat) {
5492 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5493 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5494 destFormat = srcFormat;
5497 /* Quick if complete copy ... */
5498 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
5500 if (srcWidth == destWidth && srcHeight == destHeight) {
5501 D3DLOCKED_RECT lrSrc;
5502 D3DLOCKED_RECT lrDst;
5503 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, D3DLOCK_READONLY);
5504 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
5505 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
5507 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
5509 IWineD3DSurface_UnlockRect(pSourceSurface);
5510 IWineD3DSurface_UnlockRect(pDestinationSurface);
5511 TRACE("Unlocked src and dst\n");
5513 } else {
5515 FIXME("Wanted to copy all surfaces but size not compatible, returning D3DERR_INVALIDCALL\n");
5516 hr = D3DERR_INVALIDCALL;
5519 } else {
5521 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
5523 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
5524 unsigned int i;
5526 /* Copy rect by rect */
5527 for (i = 0; i < cRects; ++i) {
5528 CONST RECT* r = &pSourceRectsArray[i];
5529 CONST POINT* p = &pDestPointsArray[i];
5530 int copyperline;
5531 int j;
5532 D3DLOCKED_RECT lrSrc;
5533 D3DLOCKED_RECT lrDst;
5534 RECT dest_rect;
5536 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
5537 if (srcFormat == WINED3DFMT_DXT1) {
5538 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
5539 } else {
5540 copyperline = ((r->right - r->left) * bytesPerPixel);
5543 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, D3DLOCK_READONLY);
5544 dest_rect.left = p->x;
5545 dest_rect.top = p->y;
5546 dest_rect.right = p->x + (r->right - r->left);
5547 dest_rect.bottom= p->y + (r->bottom - r->top);
5548 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
5549 TRACE("Locked src and dst\n");
5551 /* Find where to start */
5552 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
5553 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
5555 IWineD3DSurface_UnlockRect(pSourceSurface);
5556 IWineD3DSurface_UnlockRect(pDestinationSurface);
5557 TRACE("Unlocked src and dst\n");
5559 } else {
5560 FIXME("Wanted to copy partial surfaces not implemented, returning D3DERR_INVALIDCALL\n");
5561 hr = D3DERR_INVALIDCALL;
5565 return hr;
5568 /* Implementation details at http://developer.nvidia.com/attach/6494
5570 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5571 hmm.. no longer supported use
5572 OpenGL evaluators or tessellate surfaces within your application.
5575 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5576 HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST D3DRECTPATCH_INFO* pRectPatchInfo) {
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5578 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5579 FIXME("(%p) : Stub\n", This);
5580 return D3D_OK;
5584 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5585 HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST D3DTRIPATCH_INFO* pTriPatchInfo) {
5586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5587 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5588 FIXME("(%p) : Stub\n", This);
5589 return D3D_OK;
5592 HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 TRACE("(%p) Handle(%d)\n", This, Handle);
5595 FIXME("(%p) : Stub\n", This);
5596 return D3D_OK;
5599 HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
5600 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
5601 fill a surface with a block of color! */
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
5604 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
5605 IWineD3DSwapChainImpl *container = NULL;
5606 BOOL isRenderTarget = FALSE;
5607 unsigned int width, height;
5608 unsigned int top, left;
5609 unsigned int u, v;
5610 DWORD *data;
5611 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
5613 if (surface->resource.pool != D3DPOOL_DEFAULT) {
5614 FIXME("call to colorfill with non D3DPOOL_DEFAULT surface\n");
5615 return D3DERR_INVALIDCALL;
5618 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
5619 if (D3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
5620 if (D3DUSAGE_RENDERTARGET & surface->resource.usage) {
5621 /* TODO: make sure we set everything back to the way it was, and context management!
5622 glGetIntegerv(GL_READ_BUFFER, &prev_read);
5623 vcheckGLcall("glIntegerv");
5624 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
5625 vcheckGLcall("glIntegerv");
5627 TRACE("Color fill to render targets may cause some graphics issues\n");
5628 if (pSurface == container->frontBuffer) {
5629 glDrawBuffer(GL_FRONT);
5630 } else {
5631 glDrawBuffer(GL_BACK);
5633 } else {
5634 if (D3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
5635 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
5636 } else {
5637 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
5639 if (container != NULL) {
5640 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
5642 /* we can use GL_STENCIL_INDEX etc...*/
5643 return D3D_OK;
5645 if (container != NULL) {
5646 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
5648 isRenderTarget = TRUE;
5650 /* TODO: drawing to GL_FRONT and GL_BACK */
5651 /* TODO: see if things can be speeded up by using the correct
5652 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
5653 if (pRect == NULL) {
5654 top = 0;
5655 left = 0;
5656 width = surface->currentDesc.Width;
5657 height = surface->currentDesc.Height;
5658 } else {
5659 left = pRect->x1;
5660 top = pRect->y1;
5661 width = pRect->x2 - left;
5662 height = pRect->y2 - top;
5665 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
5666 /* Create a 'line' of color color, in the correct format for the surface */
5667 for (u = 0 ; u < width ; u ++) {
5668 data[u] = color;
5671 ENTER_GL();
5672 if (isRenderTarget == FALSE) {
5673 glDescriptor *glDesc;
5674 IWineD3DSurface_PreLoad(pSurface);
5676 /* draw a block of the coloured line on the sufrace */
5677 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
5678 for (v = 0 ; v< height;v++) {
5679 glTexSubImage2D(glDesc->target
5680 ,glDesc->level /* level */
5681 ,left
5682 ,top + v
5683 ,width
5684 ,1 /* height */
5685 ,GL_RGBA
5686 ,GL_UNSIGNED_BYTE
5687 ,data
5690 checkGLcall("glTexSubImage2D");
5691 /* clean up */
5692 glDisable(glDesc->target);
5693 } else {
5694 /** FIXME: Using GLClear may be faster **/
5695 glRasterPos2i(left, top);
5696 glPixelZoom((float)width ,(float)height);
5697 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
5698 checkGLcall("glDrawPixels");
5700 HeapFree(GetProcessHeap(), 0, data);
5701 LEAVE_GL();
5702 return D3D_OK;
5706 /* rendertarget and deptth stencil functions */
5707 HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 /* FIXME: Implelent RenderTargetIndex >0 */
5711 if(RenderTargetIndex > 0)
5712 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
5714 *ppRenderTarget = This->renderTarget;
5715 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5716 /* Note inc ref on returned surface */
5717 if(*ppRenderTarget != NULL)
5718 IWineD3DSurface_AddRef(*ppRenderTarget);
5719 return D3D_OK;
5722 HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 *ppZStencilSurface = This->depthStencilBuffer;
5725 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5727 if(*ppZStencilSurface != NULL) {
5728 /* Note inc ref on returned surface */
5729 IWineD3DSurface_AddRef(*ppZStencilSurface);
5731 return D3D_OK;
5734 /* internal static helper functions */
5735 HRESULT WINAPI static IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5736 IWineD3DSurface *RenderSurface);
5738 HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 HRESULT hr = D3D_OK;
5741 WINED3DVIEWPORT viewport;
5743 TRACE("(%p) Swapping rendertarget\n",This);
5744 if (RenderTargetIndex > 0) {
5745 FIXME("(%p) Render targets other than the first are not supported\n",This);
5746 RenderTargetIndex = 0;
5749 /* MSDN says that null disables the render target
5750 but a device must always be associated with a render target
5751 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5753 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5754 for more details
5756 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5757 FIXME("Trying to set render target 0 to NULL\n");
5758 return D3DERR_INVALIDCALL;
5760 /* TODO: replace Impl* usage with interface usage */
5761 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & D3DUSAGE_RENDERTARGET) {
5762 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of D3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5763 return D3DERR_INVALIDCALL;
5765 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5766 * builds, but I think wine counts as a 'debug' build for now.
5767 ******************************/
5768 /* If we are trying to set what we already have, don't bother */
5769 if (pRenderTarget == This->renderTarget) {
5770 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5771 } else {
5772 /* Otherwise, set the render target up */
5774 if (FALSE == This->sceneEnded) {
5775 IWineD3DDevice_EndScene(iface);
5777 TRACE("clearing renderer\n");
5778 /* IWineD3DDeviceImpl_CleanRender(iface); */
5779 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5780 depending on the renter target implementation being used.
5781 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5782 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5783 stencil buffer and incure an extra memory overhead */
5784 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5787 if (SUCCEEDED(hr)) {
5788 /* Finally, reset the viewport as the MSDN states. */
5789 /* TODO: Replace impl usage */
5790 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
5791 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
5792 viewport.X = 0;
5793 viewport.Y = 0;
5794 viewport.MaxZ = 1.0f;
5795 viewport.MinZ = 0.0f;
5796 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5797 } else {
5798 FIXME("Unknown error setting the render target\n");
5800 This->sceneEnded = FALSE;
5801 return hr;
5804 HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5806 HRESULT hr = D3D_OK;
5807 IWineD3DSurface *tmp;
5809 TRACE("(%p) Swapping z-buffer\n",This);
5811 if (pNewZStencil == This->stencilBufferTarget) {
5812 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5813 } else {
5814 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5815 * depending on the renter target implementation being used.
5816 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5817 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5818 * stencil buffer and incure an extra memory overhead
5819 ******************************************************/
5822 tmp = This->stencilBufferTarget;
5823 This->stencilBufferTarget = pNewZStencil;
5824 /* should we be calling the parent or the wined3d surface? */
5825 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5826 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5827 hr = D3D_OK;
5828 /** TODO: glEnable/glDisable on depth/stencil depending on
5829 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5830 **********************************************************/
5833 return hr;
5837 #ifdef GL_VERSION_1_3
5838 /* Internal functions not in DirectX */
5839 /** TODO: move this off to the opengl context manager
5840 *(the swapchain doesn't need to know anything about offscreen rendering!)
5841 ****************************************************/
5843 HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5847 TRACE("(%p), %p\n", This, swapchain);
5849 if (swapchain->win != swapchain->drawable) {
5850 /* Set everything back the way it ws */
5851 swapchain->render_ctx = swapchain->glCtx;
5852 swapchain->drawable = swapchain->win;
5854 return D3D_OK;
5857 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5858 HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5860 int i;
5861 unsigned int width;
5862 unsigned int height;
5863 WINED3DFORMAT format;
5864 WINED3DSURFACE_DESC surfaceDesc;
5865 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5866 surfaceDesc.Width = &width;
5867 surfaceDesc.Height = &height;
5868 surfaceDesc.Format = &format;
5869 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5870 *context = NULL;
5871 /* I need a get width/height function (and should do something with the format) */
5872 for (i = 0; i < CONTEXT_CACHE; ++i) {
5873 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
5874 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
5875 the pSurface can be set to 0 allowing it to be reused from cache **/
5876 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
5877 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
5878 *context = &This->contextCache[i];
5879 break;
5881 if (This->contextCache[i].Width == 0) {
5882 This->contextCache[i].pSurface = pSurface;
5883 This->contextCache[i].Width = width;
5884 This->contextCache[i].Height = height;
5885 *context = &This->contextCache[i];
5886 break;
5889 if (i == CONTEXT_CACHE) {
5890 int minUsage = 0x7FFFFFFF; /* MAX_INT */
5891 glContext *dropContext = 0;
5892 for (i = 0; i < CONTEXT_CACHE; i++) {
5893 if (This->contextCache[i].usedcount < minUsage) {
5894 dropContext = &This->contextCache[i];
5895 minUsage = This->contextCache[i].usedcount;
5898 /* clean up the context (this doesn't work for ATI at the moment */
5899 #if 0
5900 glXDestroyContext(swapchain->display, dropContext->context);
5901 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
5902 #endif
5903 FIXME("Leak\n");
5904 dropContext->Width = 0;
5905 dropContext->pSurface = pSurface;
5906 *context = dropContext;
5907 } else {
5908 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
5909 for (i = 0; i < CONTEXT_CACHE; i++) {
5910 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
5914 if (*context != NULL)
5915 return D3D_OK;
5916 else
5917 return E_OUTOFMEMORY;
5919 #endif
5921 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
5922 * the functionality needs splitting up so that we don't do more than we should do.
5923 * this only seems to impact performance a little.
5924 ******************************/
5925 HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5926 IWineD3DSurface *RenderSurface) {
5927 HRESULT ret = D3DERR_INVALIDCALL;
5930 * Currently only active for GLX >= 1.3
5931 * for others versions we'll have to use GLXPixmaps
5933 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
5934 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
5935 * so only check OpenGL version
5936 * ..........................
5937 * I don't believe that it is a problem with NVidia headers,
5938 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
5939 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
5940 * ATI Note:
5941 * Your application will report GLX version 1.2 on glXQueryVersion.
5942 * However, it is safe to call the GLX 1.3 functions as described below.
5944 #if defined(GL_VERSION_1_3)
5946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5947 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
5948 IWineD3DSurface *tmp;
5949 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
5950 GLXFBConfig* cfgs = NULL;
5951 int nCfgs = 0;
5952 int attribs[256];
5953 int nAttribs = 0;
5954 IWineD3DSwapChain *currentSwapchain;
5955 IWineD3DSwapChainImpl *swapchain;
5956 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
5957 * but switch them off if the StencilSurface is set to NULL
5958 ** *********************************************************/
5959 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
5960 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
5962 /**TODO:
5963 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
5964 it StencilSurface != NULL && zBufferTarget == NULL switch it on
5967 #define PUSH1(att) attribs[nAttribs++] = (att);
5968 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
5970 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
5972 /** TODO: remove the reff to Impl (context manager should fix this!) **/
5973 IWineD3DSwapChainImpl *impSwapChain;
5974 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
5975 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
5976 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
5979 ENTER_GL();
5981 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
5982 PUSH2(GLX_X_RENDERABLE, TRUE);
5983 PUSH2(GLX_DOUBLEBUFFER, TRUE);
5984 TRACE("calling makeglcfg\n");
5985 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
5986 PUSH1(None);
5988 TRACE("calling chooseFGConfig\n");
5989 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
5990 attribs, &nCfgs);
5992 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
5993 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
5994 why we failed and only show this message once! */
5995 MESSAGE("Failed to find exact match, finding alternative but you may suffer performance issues, try changing xfree's depth to match the requested depth\n"); /**/
5996 nAttribs = 0;
5997 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
5998 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
5999 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6000 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6001 TRACE("calling makeglcfg\n");
6002 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6003 PUSH1(None);
6004 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
6005 attribs, &nCfgs);
6008 if (NULL != cfgs) {
6009 #ifdef EXTRA_TRACES
6010 int i;
6011 for (i = 0; i < nCfgs; ++i) {
6012 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6013 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6014 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6017 if (NULL != This->renderTarget) {
6018 glFlush();
6019 vcheckGLcall("glFlush");
6020 /** This is only useful if the old render target was a swapchain,
6021 * we need to supercede this with a function that displays
6022 * the current buffer on the screen. This is easy to do in glx1.3 but
6023 * we need to do copy-write pixels in glx 1.2.
6024 ************************************************/
6025 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
6027 printf("Hit Enter to get next frame ...\n");
6028 getchar();
6030 #endif
6033 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != D3D_OK) {
6034 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
6035 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6039 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6040 * renderTarget = swapchain->backBuffer bit and anything to do with *glContexts
6041 **********************************************************************/
6042 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == D3D_OK) {
6043 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6044 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
6045 TRACE("making swapchain active\n");
6046 if (RenderSurface != This->renderTarget) {
6047 if (RenderSurface == swapchain->backBuffer) {
6048 } else {
6049 /* This could be flagged so that some operations work directly with the front buffer */
6050 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6052 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
6053 == False) {
6054 TRACE("Error in setting current context: context %p drawable %ld !\n",
6055 impSwapChain->glCtx, impSwapChain->win);
6058 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
6060 checkGLcall("glXMakeContextCurrent");
6062 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6064 else if (pbuffer_support == TRUE && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
6066 /** ********************************************************************
6067 * This is a quickly hacked out implementation of offscreen textures.
6068 * It will work in most cases but there may be problems if the client
6069 * modifies the texture directly, or expects the contents of the rendertarget
6070 * to be persistent.
6072 * There are some real speed vs compatibility issues here:
6073 * we should really use a new context for every texture, but that eats ram.
6074 * we should also be restoring the texture to the pbuffer but that eats CPU
6075 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6076 * but if this means reusing the display backbuffer then we need to make sure that
6077 * states are correctly preserved.
6078 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6079 * and gain a good performance increase at the cost of compatibility.
6080 * I would suggest that, when this is the case, a user configurable flag be made
6081 * available, allowing the user to choose the best emulated experience for them.
6082 *********************************************************************/
6084 XVisualInfo *visinfo;
6085 glContext *newContext;
6087 /* Here were using a shared context model */
6088 if (D3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6089 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6092 /* If the context doesn't exist then create a new one */
6093 /* TODO: This should really be part of findGlContext */
6094 if (NULL == newContext->context) {
6096 TRACE("making new buffer\n");
6097 nAttribs = 0;
6098 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
6099 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
6100 PUSH1(None);
6102 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
6104 /** ****************************************
6105 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6106 *they note:
6107 * In future releases, we may provide the calls glXCreateNewContext,
6108 * glXQueryDrawable and glXMakeContextCurrent.
6109 * so until then we have to use glXGetVisualFromFBConfig &co..
6110 ********************************************/
6113 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
6114 if (!visinfo) {
6115 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6116 } else {
6117 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
6118 XFree(visinfo);
6121 if (NULL == newContext || NULL == newContext->context) {
6122 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6123 } else {
6124 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6125 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
6126 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
6129 /* Clean up the old context */
6130 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
6131 /* Set the current context of the swapchain to the new context */
6132 impSwapChain->drawable = newContext->drawable;
6133 impSwapChain->render_ctx = newContext->context;
6137 #if 1 /* Apply the stateblock to the new context
6138 FIXME: This is a bit of a hack, each context should know it's own state,
6139 the directX current directX state should then be applied to the context */
6141 BOOL oldRecording;
6142 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6143 oldUpdateStateBlock = This->updateStateBlock;
6144 oldRecording= This->isRecordingState;
6145 This->isRecordingState = FALSE;
6146 This->updateStateBlock = This->stateBlock;
6147 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
6149 This->isRecordingState = oldRecording;
6150 This->updateStateBlock = oldUpdateStateBlock;
6152 #endif
6155 /* clean up the current rendertargets swapchain (if it belonged to one) */
6156 if (currentSwapchain != NULL) {
6157 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
6160 /* Were done with the opengl context management, setup the rendertargets */
6162 tmp = This->renderTarget;
6163 This->renderTarget = RenderSurface;
6164 IWineD3DSurface_AddRef(This->renderTarget);
6165 IWineD3DSurface_Release(tmp);
6170 DWORD value;
6171 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
6172 /* Check that the container is not a swapchain member */
6174 IWineD3DSwapChain *tmpSwapChain;
6175 if (D3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
6176 This->renderUpsideDown = TRUE;
6177 }else{
6178 This->renderUpsideDown = FALSE;
6179 IWineD3DSwapChain_Release(tmpSwapChain);
6181 /* Force updating the cull mode */
6182 TRACE("setting render state\n");
6183 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
6184 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
6186 /* Force updating projection matrix */
6187 This->last_was_rhw = FALSE;
6188 This->proj_valid = FALSE;
6191 ret = D3D_OK;
6193 if (cfgs != NULL) {
6194 XFree(cfgs);
6195 } else {
6196 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
6197 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6200 #undef PUSH1
6201 #undef PUSH2
6202 if ( NULL != impSwapChain) {
6203 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
6205 LEAVE_GL();
6207 #endif
6208 return ret;
6211 HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6212 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6214 /* TODO: the use of Impl is deprecated. */
6215 /* some basic validation checks */
6216 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6218 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6220 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6221 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6222 return D3DERR_INVALIDCALL;
6224 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
6225 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
6226 return D3DERR_INVALIDCALL;
6228 /* TODO: make the cursor 'real' */
6230 This->xHotSpot = XHotSpot;
6231 This->yHotSpot = YHotSpot;
6233 return D3D_OK;
6236 void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6238 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6240 This->xScreenSpace = XScreenSpace;
6241 This->yScreenSpace = YScreenSpace;
6243 return;
6247 BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6249 TRACE("(%p) : visible(%d)\n", This, bShow);
6251 This->bCursorVisible = bShow;
6253 return D3D_OK;
6256 HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6258 TRACE("(%p) : state (%lu)\n", This, This->state);
6259 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6260 switch (This->state) {
6261 case D3D_OK:
6262 return D3D_OK;
6263 case D3DERR_DEVICELOST:
6265 ResourceList *resourceList = This->resources;
6266 while (NULL != resourceList) {
6267 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == D3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6268 return D3DERR_DEVICENOTRESET;
6269 resourceList = resourceList->next;
6271 return D3DERR_DEVICELOST;
6273 case D3DERR_DRIVERINTERNALERROR:
6274 return D3DERR_DRIVERINTERNALERROR;
6277 /* Unknown state */
6278 return D3DERR_DRIVERINTERNALERROR;
6282 HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6284 /** FIXME: Resource tracking needs to be done,
6285 * The closes we can do to this is set the priorities of all managed textures low
6286 * and then reset them.
6287 ***********************************************************/
6288 FIXME("(%p) : stub\n", This);
6289 return D3D_OK;
6292 HRESULT WINAPI IWineD3DDeviceImpl_Rest(IWineD3DDevice* iface, D3DPRESENT_PARAMETERS* pPresentationParameters) {
6293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6294 /** FIXME: Resource trascking needs to be done.
6295 * in effect this pulls all non only default
6296 * textures out of video memory and deletes all glTextures (glDeleteTextures)
6297 * and should clear down the context and set it up according to pPresentationParameters
6298 ***********************************************************/
6299 FIXME("(%p) : stub\n", This);
6300 return D3D_OK;
6303 HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6305 /** FIXME: always true at the moment **/
6306 if(bEnableDialogs == FALSE) {
6307 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6309 return D3D_OK;
6313 HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, D3DDEVICE_CREATION_PARAMETERS *pParameters) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6316 FIXME("(%p) : stub\n", This);
6317 /* Setup some reasonable defaults */
6318 pParameters->AdapterOrdinal = 0; /* always for now */
6319 pParameters->DeviceType = D3DDEVTYPE_HAL; /* always for now */
6320 pParameters->hFocusWindow = 0;
6321 pParameters->BehaviorFlags =0;
6322 return D3D_OK;
6325 void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST D3DGAMMARAMP* pRamp) {
6326 IWineD3DSwapChain *swapchain;
6327 HRESULT hrc = D3D_OK;
6329 TRACE("Relaying to swapchain\n");
6331 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == D3D_OK) {
6332 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (D3DGAMMARAMP *)pRamp);
6333 IWineD3DSwapChain_Release(swapchain);
6335 return;
6338 void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, D3DGAMMARAMP* pRamp) {
6339 IWineD3DSwapChain *swapchain;
6340 HRESULT hrc = D3D_OK;
6342 TRACE("Relaying to swapchain\n");
6344 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == D3D_OK) {
6345 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6346 IWineD3DSwapChain_Release(swapchain);
6348 return;
6352 /** ********************************************************
6353 * Notification functions
6354 ** ********************************************************/
6355 /** This function must be called in the release of a resource when ref == 0,
6356 * the contents of resource must still be correct,
6357 * any handels to other resource held by the caller must be closed
6358 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6359 *****************************************************/
6360 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6362 ResourceList* resourceList;
6364 TRACE("(%p) : resource %p\n", This, resource);
6365 #if 0
6366 EnterCriticalSection(&resourceStoreCriticalSection);
6367 #endif
6368 /* add a new texture to the frot of the linked list */
6369 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6370 resourceList->resource = resource;
6372 /* Get the old head */
6373 resourceList->next = This->resources;
6375 This->resources = resourceList;
6376 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6378 #if 0
6379 LeaveCriticalSection(&resourceStoreCriticalSection);
6380 #endif
6381 return;
6384 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 ResourceList* resourceList = NULL;
6387 ResourceList* previousResourceList = NULL;
6389 TRACE("(%p) : resource %p\n", This, resource);
6391 #if 0
6392 EnterCriticalSection(&resourceStoreCriticalSection);
6393 #endif
6394 resourceList = This->resources;
6396 while (resourceList != NULL) {
6397 if(resourceList->resource == resource) break;
6398 previousResourceList = resourceList;
6399 resourceList = resourceList->next;
6402 if (resourceList == NULL) {
6403 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6404 #if 0
6405 LeaveCriticalSection(&resourceStoreCriticalSection);
6406 #endif
6407 return;
6408 } else {
6409 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6411 /* make sure we don't leave a hole in the list */
6412 if (previousResourceList != NULL) {
6413 previousResourceList->next = resourceList->next;
6414 } else {
6415 This->resources = resourceList->next;
6418 #if 0
6419 LeaveCriticalSection(&resourceStoreCriticalSection);
6420 #endif
6421 return;
6425 void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6427 int counter;
6429 TRACE("(%p) : resource %p\n", This, resource);
6430 switch(IWineD3DResource_GetType(resource)){
6431 case D3DRTYPE_SURFACE:
6432 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6433 break;
6434 case D3DRTYPE_TEXTURE:
6435 case D3DRTYPE_CUBETEXTURE:
6436 case D3DRTYPE_VOLUMETEXTURE:
6437 for (counter = 0; counter < GL_LIMITS(textures); counter++) {
6438 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6439 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6440 This->stateBlock->textures[counter] = NULL;
6442 if (This->updateStateBlock != This->stateBlock ){
6443 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6444 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6445 This->updateStateBlock->textures[counter] = NULL;
6449 break;
6450 case D3DRTYPE_VOLUME:
6451 /* TODO: nothing really? */
6452 break;
6453 case D3DRTYPE_VERTEXBUFFER:
6454 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6456 int streamNumber;
6457 TRACE("Cleaning up stream pointers\n");
6459 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6460 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6461 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6463 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6464 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6465 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
6466 This->updateStateBlock->streamSource[streamNumber] = 0;
6467 /* Set changed flag? */
6470 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6471 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6472 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
6473 This->stateBlock->streamSource[streamNumber] = 0;
6476 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6477 else { /* This shouldn't happen */
6478 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6480 #endif
6484 break;
6485 case D3DRTYPE_INDEXBUFFER:
6486 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6487 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6488 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6489 This->updateStateBlock->pIndexData = NULL;
6492 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6493 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6494 This->stateBlock->pIndexData = NULL;
6498 break;
6499 default:
6500 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6501 break;
6505 /* Remove the resoruce from the resourceStore */
6506 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6508 TRACE("Resource released\n");
6513 /** This function is to be called by the swapchain when it is released and it's ref = 0
6514 *****************************************************/
6515 void WINAPI IWineD3DDeviceImpl_SwapChainReleased(IWineD3DDevice *iface, IWineD3DSwapChain *swapChain){
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6517 SwapChainList **nextSwapchain;
6518 nextSwapchain = &This->swapchains;
6520 /* Check to see if the swapchian is being used as the render target */
6521 if (This->renderTarget != NULL) {
6522 IWineD3DSurface *swapchainBackBuffer;
6524 IWineD3DSwapChain_GetBackBuffer(swapChain, 0 ,( D3DBACKBUFFER_TYPE) 0, &swapchainBackBuffer);
6525 if (This->renderTarget == swapchainBackBuffer) {
6526 /* Don't know what to do, so warn and carry on as usual (which in this case leaves the renderterget in limbo) */
6527 FIXME("Atempting to release a swapchain that is currently beuing used as a render target, behaviour is undefined\n");
6531 /* Go through the swapchain list and try to find the swapchain being released */
6532 while(*nextSwapchain != NULL && (*nextSwapchain)->swapchain != swapChain) {
6533 nextSwapchain = &(*nextSwapchain)->next;
6536 /* Check to see if we found the swapchain */
6537 if (NULL != *nextSwapchain) {
6538 /* We found the swapchain so remove it from the list */
6539 TRACE("(%p) releasing swapchain(%p)\n", iface, swapChain);
6540 HeapFree(GetProcessHeap(), 0 , *nextSwapchain);
6541 *nextSwapchain = (*nextSwapchain)->next;
6542 } else {
6543 /* We didn't find the swapchain on the list, this can only heppen because of a programming error in wined3d */
6544 FIXME("(%p) Attempting to release a swapchain (%p) that hasn't been stored\n", iface, swapChain);
6547 TRACE("swapchain (%p) released\n", swapChain);
6548 return;
6551 /**********************************************************
6552 * IWineD3DDevice VTbl follows
6553 **********************************************************/
6555 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6557 /*** IUnknown methods ***/
6558 IWineD3DDeviceImpl_QueryInterface,
6559 IWineD3DDeviceImpl_AddRef,
6560 IWineD3DDeviceImpl_Release,
6561 /*** IWineD3DDevice methods ***/
6562 IWineD3DDeviceImpl_GetParent,
6563 /*** Creation methods**/
6564 IWineD3DDeviceImpl_CreateVertexBuffer,
6565 IWineD3DDeviceImpl_CreateIndexBuffer,
6566 IWineD3DDeviceImpl_CreateStateBlock,
6567 IWineD3DDeviceImpl_CreateSurface,
6568 IWineD3DDeviceImpl_CreateTexture,
6569 IWineD3DDeviceImpl_CreateVolumeTexture,
6570 IWineD3DDeviceImpl_CreateVolume,
6571 IWineD3DDeviceImpl_CreateCubeTexture,
6572 IWineD3DDeviceImpl_CreateQuery,
6573 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6574 IWineD3DDeviceImpl_CreateVertexDeclaration,
6575 IWineD3DDeviceImpl_CreateVertexShader,
6576 IWineD3DDeviceImpl_CreatePixelShader,
6577 /*** Odd functions **/
6578 IWineD3DDeviceImpl_EvictManagedResources,
6579 IWineD3DDeviceImpl_GetAvailableTextureMem,
6580 IWineD3DDeviceImpl_GetBackBuffer,
6581 IWineD3DDeviceImpl_GetCreationParameters,
6582 IWineD3DDeviceImpl_GetDeviceCaps,
6583 IWineD3DDeviceImpl_GetDirect3D,
6584 IWineD3DDeviceImpl_GetDisplayMode,
6585 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6586 IWineD3DDeviceImpl_GetRasterStatus,
6587 IWineD3DDeviceImpl_GetSwapChain,
6588 IWineD3DDeviceImpl_Reset,
6589 IWineD3DDeviceImpl_SetDialogBoxMode,
6590 IWineD3DDeviceImpl_SetCursorProperties,
6591 IWineD3DDeviceImpl_SetCursorPosition,
6592 IWineD3DDeviceImpl_ShowCursor,
6593 IWineD3DDeviceImpl_TestCooperativeLevel,
6594 /*** Getters and setters **/
6595 IWineD3DDeviceImpl_SetClipPlane,
6596 IWineD3DDeviceImpl_GetClipPlane,
6597 IWineD3DDeviceImpl_SetClipStatus,
6598 IWineD3DDeviceImpl_GetClipStatus,
6599 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6600 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6601 IWineD3DDeviceImpl_SetDepthStencilSurface,
6602 IWineD3DDeviceImpl_GetDepthStencilSurface,
6603 IWineD3DDeviceImpl_SetFVF,
6604 IWineD3DDeviceImpl_GetFVF,
6605 IWineD3DDeviceImpl_SetGammaRamp,
6606 IWineD3DDeviceImpl_GetGammaRamp,
6607 IWineD3DDeviceImpl_SetIndices,
6608 IWineD3DDeviceImpl_GetIndices,
6609 IWineD3DDeviceImpl_SetLight,
6610 IWineD3DDeviceImpl_GetLight,
6611 IWineD3DDeviceImpl_SetLightEnable,
6612 IWineD3DDeviceImpl_GetLightEnable,
6613 IWineD3DDeviceImpl_SetMaterial,
6614 IWineD3DDeviceImpl_GetMaterial,
6615 IWineD3DDeviceImpl_SetNPatchMode,
6616 IWineD3DDeviceImpl_GetNPatchMode,
6617 IWineD3DDeviceImpl_SetPaletteEntries,
6618 IWineD3DDeviceImpl_GetPaletteEntries,
6619 IWineD3DDeviceImpl_SetPixelShader,
6620 IWineD3DDeviceImpl_GetPixelShader,
6621 IWineD3DDeviceImpl_SetPixelShaderConstant,
6622 IWineD3DDeviceImpl_GetPixelShaderConstant,
6623 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6624 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6625 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6626 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6627 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6628 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6629 IWineD3DDeviceImpl_SetPixelShaderConstantN,
6630 IWineD3DDeviceImpl_SetRenderState,
6631 IWineD3DDeviceImpl_GetRenderState,
6632 IWineD3DDeviceImpl_SetRenderTarget,
6633 IWineD3DDeviceImpl_GetRenderTarget,
6634 IWineD3DDeviceImpl_SetSamplerState,
6635 IWineD3DDeviceImpl_GetSamplerState,
6636 IWineD3DDeviceImpl_SetScissorRect,
6637 IWineD3DDeviceImpl_GetScissorRect,
6638 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6639 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6640 IWineD3DDeviceImpl_SetStreamSource,
6641 IWineD3DDeviceImpl_GetStreamSource,
6642 IWineD3DDeviceImpl_SetStreamSourceFreq,
6643 IWineD3DDeviceImpl_GetStreamSourceFreq,
6644 IWineD3DDeviceImpl_SetTexture,
6645 IWineD3DDeviceImpl_GetTexture,
6646 IWineD3DDeviceImpl_SetTextureStageState,
6647 IWineD3DDeviceImpl_GetTextureStageState,
6648 IWineD3DDeviceImpl_SetTransform,
6649 IWineD3DDeviceImpl_GetTransform,
6650 IWineD3DDeviceImpl_SetVertexDeclaration,
6651 IWineD3DDeviceImpl_GetVertexDeclaration,
6652 IWineD3DDeviceImpl_SetVertexShader,
6653 IWineD3DDeviceImpl_GetVertexShader,
6654 IWineD3DDeviceImpl_SetVertexShaderConstant,
6655 IWineD3DDeviceImpl_GetVertexShaderConstant,
6656 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6657 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6658 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6659 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6660 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6661 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6662 IWineD3DDeviceImpl_SetVertexShaderConstantN,
6663 IWineD3DDeviceImpl_SetViewport,
6664 IWineD3DDeviceImpl_GetViewport,
6665 IWineD3DDeviceImpl_MultiplyTransform,
6666 IWineD3DDeviceImpl_ValidateDevice,
6667 IWineD3DDeviceImpl_ProcessVertices,
6668 /*** State block ***/
6669 IWineD3DDeviceImpl_BeginStateBlock,
6670 IWineD3DDeviceImpl_EndStateBlock,
6671 /*** Scene management ***/
6672 IWineD3DDeviceImpl_BeginScene,
6673 IWineD3DDeviceImpl_EndScene,
6674 IWineD3DDeviceImpl_Present,
6675 IWineD3DDeviceImpl_Clear,
6676 /*** Drawing ***/
6677 IWineD3DDeviceImpl_DrawPrimitive,
6678 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6679 IWineD3DDeviceImpl_DrawPrimitiveUP,
6680 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6681 IWineD3DDeviceImpl_DrawRectPatch,
6682 IWineD3DDeviceImpl_DrawTriPatch,
6683 IWineD3DDeviceImpl_DeletePatch,
6684 IWineD3DDeviceImpl_ColorFill,
6685 IWineD3DDeviceImpl_UpdateTexture,
6686 IWineD3DDeviceImpl_UpdateSurface,
6687 IWineD3DDeviceImpl_CopyRects,
6688 IWineD3DDeviceImpl_StretchRect,
6689 IWineD3DDeviceImpl_GetRenderTargetData,
6690 IWineD3DDeviceImpl_GetFrontBufferData,
6691 /*** Internal use IWineD3DDevice methods ***/
6692 IWineD3DDeviceImpl_SetupTextureStates,
6693 /*** object tracking ***/
6694 IWineD3DDeviceImpl_SwapChainReleased,
6695 IWineD3DDeviceImpl_ResourceReleased
6699 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6700 WINED3DRS_ALPHABLENDENABLE ,
6701 WINED3DRS_ALPHAFUNC ,
6702 WINED3DRS_ALPHAREF ,
6703 WINED3DRS_ALPHATESTENABLE ,
6704 WINED3DRS_BLENDOP ,
6705 WINED3DRS_COLORWRITEENABLE ,
6706 WINED3DRS_DESTBLEND ,
6707 WINED3DRS_DITHERENABLE ,
6708 WINED3DRS_FILLMODE ,
6709 WINED3DRS_FOGDENSITY ,
6710 WINED3DRS_FOGEND ,
6711 WINED3DRS_FOGSTART ,
6712 WINED3DRS_LASTPIXEL ,
6713 WINED3DRS_SHADEMODE ,
6714 WINED3DRS_SRCBLEND ,
6715 WINED3DRS_STENCILENABLE ,
6716 WINED3DRS_STENCILFAIL ,
6717 WINED3DRS_STENCILFUNC ,
6718 WINED3DRS_STENCILMASK ,
6719 WINED3DRS_STENCILPASS ,
6720 WINED3DRS_STENCILREF ,
6721 WINED3DRS_STENCILWRITEMASK ,
6722 WINED3DRS_STENCILZFAIL ,
6723 WINED3DRS_TEXTUREFACTOR ,
6724 WINED3DRS_WRAP0 ,
6725 WINED3DRS_WRAP1 ,
6726 WINED3DRS_WRAP2 ,
6727 WINED3DRS_WRAP3 ,
6728 WINED3DRS_WRAP4 ,
6729 WINED3DRS_WRAP5 ,
6730 WINED3DRS_WRAP6 ,
6731 WINED3DRS_WRAP7 ,
6732 WINED3DRS_ZENABLE ,
6733 WINED3DRS_ZFUNC ,
6734 WINED3DRS_ZWRITEENABLE
6737 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6738 WINED3DTSS_ADDRESSW ,
6739 WINED3DTSS_ALPHAARG0 ,
6740 WINED3DTSS_ALPHAARG1 ,
6741 WINED3DTSS_ALPHAARG2 ,
6742 WINED3DTSS_ALPHAOP ,
6743 WINED3DTSS_BUMPENVLOFFSET ,
6744 WINED3DTSS_BUMPENVLSCALE ,
6745 WINED3DTSS_BUMPENVMAT00 ,
6746 WINED3DTSS_BUMPENVMAT01 ,
6747 WINED3DTSS_BUMPENVMAT10 ,
6748 WINED3DTSS_BUMPENVMAT11 ,
6749 WINED3DTSS_COLORARG0 ,
6750 WINED3DTSS_COLORARG1 ,
6751 WINED3DTSS_COLORARG2 ,
6752 WINED3DTSS_COLOROP ,
6753 WINED3DTSS_RESULTARG ,
6754 WINED3DTSS_TEXCOORDINDEX ,
6755 WINED3DTSS_TEXTURETRANSFORMFLAGS
6758 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6759 WINED3DSAMP_ADDRESSU ,
6760 WINED3DSAMP_ADDRESSV ,
6761 WINED3DSAMP_ADDRESSW ,
6762 WINED3DSAMP_BORDERCOLOR ,
6763 WINED3DSAMP_MAGFILTER ,
6764 WINED3DSAMP_MINFILTER ,
6765 WINED3DSAMP_MIPFILTER ,
6766 WINED3DSAMP_MIPMAPLODBIAS ,
6767 WINED3DSAMP_MAXMIPLEVEL ,
6768 WINED3DSAMP_MAXANISOTROPY ,
6769 WINED3DSAMP_SRGBTEXTURE ,
6770 WINED3DSAMP_ELEMENTINDEX
6773 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6774 WINED3DRS_AMBIENT ,
6775 WINED3DRS_AMBIENTMATERIALSOURCE ,
6776 WINED3DRS_CLIPPING ,
6777 WINED3DRS_CLIPPLANEENABLE ,
6778 WINED3DRS_COLORVERTEX ,
6779 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6780 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6781 WINED3DRS_FOGDENSITY ,
6782 WINED3DRS_FOGEND ,
6783 WINED3DRS_FOGSTART ,
6784 WINED3DRS_FOGTABLEMODE ,
6785 WINED3DRS_FOGVERTEXMODE ,
6786 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6787 WINED3DRS_LIGHTING ,
6788 WINED3DRS_LOCALVIEWER ,
6789 WINED3DRS_MULTISAMPLEANTIALIAS ,
6790 WINED3DRS_MULTISAMPLEMASK ,
6791 WINED3DRS_NORMALIZENORMALS ,
6792 WINED3DRS_PATCHEDGESTYLE ,
6793 WINED3DRS_POINTSCALE_A ,
6794 WINED3DRS_POINTSCALE_B ,
6795 WINED3DRS_POINTSCALE_C ,
6796 WINED3DRS_POINTSCALEENABLE ,
6797 WINED3DRS_POINTSIZE ,
6798 WINED3DRS_POINTSIZE_MAX ,
6799 WINED3DRS_POINTSIZE_MIN ,
6800 WINED3DRS_POINTSPRITEENABLE ,
6801 WINED3DRS_RANGEFOGENABLE ,
6802 WINED3DRS_SPECULARMATERIALSOURCE ,
6803 WINED3DRS_TWEENFACTOR ,
6804 WINED3DRS_VERTEXBLEND
6807 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6808 WINED3DTSS_TEXCOORDINDEX ,
6809 WINED3DTSS_TEXTURETRANSFORMFLAGS
6812 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6813 WINED3DSAMP_DMAPOFFSET