push 28d280983c7275cb2fcf76673d2636eedeed51f9
[wine/hacks.git] / dlls / wined3d / device.c
blob09f3808d6c8528205c6f9b887055641c5af511c9
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 HeapFree(GetProcessHeap(), 0, This->render_targets);
196 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
197 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
199 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
201 /* TODO: Clean up all the surfaces and textures! */
202 /* NOTE: You must release the parent if the object was created via a callback
203 ** ***************************/
205 /* Release the update stateblock */
206 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
207 if(This->updateStateBlock != This->stateBlock)
208 FIXME("(%p) Something's still holding the Update stateblock\n",This);
210 This->updateStateBlock = NULL;
211 { /* because were not doing proper internal refcounts releasing the primary state block
212 causes recursion with the extra checks in ResourceReleased, to avoid this we have
213 to set this->stateBlock = NULL; first */
214 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
215 This->stateBlock = NULL;
217 /* Release the stateblock */
218 if(IWineD3DStateBlock_Release(stateBlock) > 0){
219 FIXME("(%p) Something's still holding the Update stateblock\n",This);
223 if (This->resources != NULL ) {
224 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
225 dumpResources(This->resources);
228 if(This->contexts) ERR("Context array not freed!\n");
229 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
230 This->haveHardwareCursor = FALSE;
232 IWineD3D_Release(This->wineD3D);
233 This->wineD3D = NULL;
234 HeapFree(GetProcessHeap(), 0, This);
235 TRACE("Freed device %p\n", This);
236 This = NULL;
238 return refCount;
241 /**********************************************************
242 * IWineD3DDevice implementation follows
243 **********************************************************/
244 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
246 *pParent = This->parent;
247 IUnknown_AddRef(This->parent);
248 return WINED3D_OK;
251 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
252 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
253 GLenum error, glUsage;
254 DWORD vboUsage = object->resource.usage;
255 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
256 WARN("Creating a vbo failed once, not trying again\n");
257 return;
260 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
262 ENTER_GL();
263 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
264 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
266 /* Make sure that the gl error is cleared. Do not use checkGLcall
267 * here because checkGLcall just prints a fixme and continues. However,
268 * if an error during VBO creation occurs we can fall back to non-vbo operation
269 * with full functionality(but performance loss)
271 while(glGetError() != GL_NO_ERROR);
273 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
274 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
275 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
276 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
277 * to check if the rhw and color values are in the correct format.
280 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
281 error = glGetError();
282 if(object->vbo == 0 || error != GL_NO_ERROR) {
283 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
284 goto error;
287 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
288 error = glGetError();
289 if(error != GL_NO_ERROR) {
290 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
291 goto error;
294 /* Don't use static, because dx apps tend to update the buffer
295 * quite often even if they specify 0 usage. Because we always keep the local copy
296 * we never read from the vbo and can create a write only opengl buffer.
298 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
299 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
300 case WINED3DUSAGE_DYNAMIC:
301 TRACE("Gl usage = GL_STREAM_DRAW\n");
302 glUsage = GL_STREAM_DRAW_ARB;
303 break;
304 case WINED3DUSAGE_WRITEONLY:
305 default:
306 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
307 glUsage = GL_DYNAMIC_DRAW_ARB;
308 break;
311 /* Reserve memory for the buffer. The amount of data won't change
312 * so we are safe with calling glBufferData once with a NULL ptr and
313 * calling glBufferSubData on updates
315 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
316 error = glGetError();
317 if(error != GL_NO_ERROR) {
318 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
319 goto error;
322 LEAVE_GL();
324 return;
325 error:
326 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
327 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
328 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
329 object->vbo = 0;
330 object->Flags |= VBFLAG_VBOCREATEFAIL;
331 LEAVE_GL();
332 return;
335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
336 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
337 IUnknown *parent) {
338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
339 IWineD3DVertexBufferImpl *object;
340 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
341 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
342 BOOL conv;
344 if(Size == 0) {
345 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
346 *ppVertexBuffer = NULL;
347 return WINED3DERR_INVALIDCALL;
350 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
352 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
353 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
355 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
356 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
358 object->fvf = FVF;
360 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
361 * drawStridedFast (half-life 2).
363 * Basically converting the vertices in the buffer is quite expensive, and observations
364 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
365 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
367 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
368 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
369 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
370 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
371 * dx7 apps.
372 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
373 * more. In this call we can convert dx7 buffers too.
375 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
376 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
377 (dxVersion > 7 || !conv) ) {
378 CreateVBO(object);
380 return WINED3D_OK;
383 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
384 GLenum error, glUsage;
385 TRACE("Creating VBO for Index Buffer %p\n", object);
387 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
388 * restored on the next draw
390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
392 ENTER_GL();
393 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
394 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
396 while(glGetError());
398 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
399 error = glGetError();
400 if(error != GL_NO_ERROR || object->vbo == 0) {
401 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
402 goto out;
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
406 error = glGetError();
407 if(error != GL_NO_ERROR) {
408 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
409 goto out;
412 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
413 * copy no readback will be needed
415 glUsage = GL_STATIC_DRAW_ARB;
416 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
417 error = glGetError();
418 if(error != GL_NO_ERROR) {
419 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
420 goto out;
422 LEAVE_GL();
423 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
424 return;
426 out:
427 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
428 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
429 LEAVE_GL();
430 object->vbo = 0;
433 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
434 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
435 HANDLE *sharedHandle, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DIndexBufferImpl *object;
438 TRACE("(%p) Creating index buffer\n", This);
440 /* Allocate the storage for the device */
441 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
443 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
444 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
447 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
448 CreateIndexBufferVBO(This, object);
451 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
452 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
453 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
455 return WINED3D_OK;
458 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
461 IWineD3DStateBlockImpl *object;
462 int i, j;
463 HRESULT temp_result;
465 D3DCREATEOBJECTINSTANCE(object, StateBlock)
466 object->blockType = Type;
468 for(i = 0; i < LIGHTMAP_SIZE; i++) {
469 list_init(&object->lightMap[i]);
472 /* Special case - Used during initialization to produce a placeholder stateblock
473 so other functions called can update a state block */
474 if (Type == WINED3DSBT_INIT) {
475 /* Don't bother increasing the reference count otherwise a device will never
476 be freed due to circular dependencies */
477 return WINED3D_OK;
480 temp_result = allocate_shader_constants(object);
481 if (WINED3D_OK != temp_result)
482 return temp_result;
484 /* Otherwise, might as well set the whole state block to the appropriate values */
485 if (This->stateBlock != NULL)
486 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
487 else
488 memset(object->streamFreq, 1, sizeof(object->streamFreq));
490 /* Reset the ref and type after kludging it */
491 object->wineD3DDevice = This;
492 object->ref = 1;
493 object->blockType = Type;
495 TRACE("Updating changed flags appropriate for type %d\n", Type);
497 if (Type == WINED3DSBT_ALL) {
499 TRACE("ALL => Pretend everything has changed\n");
500 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
502 /* Lights are not part of the changed / set structure */
503 for(j = 0; j < LIGHTMAP_SIZE; j++) {
504 struct list *e;
505 LIST_FOR_EACH(e, &object->lightMap[j]) {
506 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
507 light->changed = TRUE;
508 light->enabledChanged = TRUE;
511 } else if (Type == WINED3DSBT_PIXELSTATE) {
513 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
514 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
516 object->changed.pixelShader = TRUE;
518 /* Pixel Shader Constants */
519 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
520 object->changed.pixelShaderConstantsF[i] = TRUE;
521 for (i = 0; i < MAX_CONST_B; ++i)
522 object->changed.pixelShaderConstantsB[i] = TRUE;
523 for (i = 0; i < MAX_CONST_I; ++i)
524 object->changed.pixelShaderConstantsI[i] = TRUE;
526 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
527 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
529 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
530 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
531 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
534 for (j = 0 ; j < 16; j++) {
535 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
537 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
541 } else if (Type == WINED3DSBT_VERTEXSTATE) {
543 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
544 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
546 object->changed.vertexShader = TRUE;
548 /* Vertex Shader Constants */
549 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
550 object->changed.vertexShaderConstantsF[i] = TRUE;
551 for (i = 0; i < MAX_CONST_B; ++i)
552 object->changed.vertexShaderConstantsB[i] = TRUE;
553 for (i = 0; i < MAX_CONST_I; ++i)
554 object->changed.vertexShaderConstantsI[i] = TRUE;
556 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
557 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
559 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
560 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
561 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
564 for (j = 0 ; j < 16; j++){
565 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
566 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
570 for(j = 0; j < LIGHTMAP_SIZE; j++) {
571 struct list *e;
572 LIST_FOR_EACH(e, &object->lightMap[j]) {
573 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
574 light->changed = TRUE;
575 light->enabledChanged = TRUE;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int pow2Width, pow2Height;
601 unsigned int Size = 1;
602 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
603 TRACE("(%p) Create surface\n",This);
605 /** FIXME: Check ranges on the inputs are valid
606 * MSDN
607 * MultisampleQuality
608 * [in] Quality level. The valid range is between zero and one less than the level
609 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
610 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
611 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 * must all match.
613 *******************************/
617 * TODO: Discard MSDN
618 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
620 * If this flag is set, the contents of the depth stencil buffer will be
621 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
622 * with a different depth surface.
624 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
625 ***************************/
627 if(MultisampleQuality < 0) {
628 FIXME("Invalid multisample level %d\n", MultisampleQuality);
629 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
632 if(MultisampleQuality > 0) {
633 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
634 MultisampleQuality=0;
637 /** FIXME: Check that the format is supported
638 * by the device.
639 *******************************/
641 /* Non-power2 support */
642 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
643 pow2Width = Width;
644 pow2Height = Height;
645 } else {
646 /* Find the nearest pow2 match */
647 pow2Width = pow2Height = 1;
648 while (pow2Width < Width) pow2Width <<= 1;
649 while (pow2Height < Height) pow2Height <<= 1;
652 if (pow2Width > Width || pow2Height > Height) {
653 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
654 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
655 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
656 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
657 This, Width, Height);
658 return WINED3DERR_NOTAVAILABLE;
662 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
663 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
664 * space!
665 *********************************/
666 if (WINED3DFMT_UNKNOWN == Format) {
667 Size = 0;
668 } else if (Format == WINED3DFMT_DXT1) {
669 /* DXT1 is half byte per pixel */
670 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
672 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
673 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
674 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
675 } else {
676 /* The pitch is a multiple of 4 bytes */
677 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
678 Size *= Height;
681 /** Create and initialise the surface resource **/
682 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
683 /* "Standalone" surface */
684 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
686 object->currentDesc.Width = Width;
687 object->currentDesc.Height = Height;
688 object->currentDesc.MultiSampleType = MultiSample;
689 object->currentDesc.MultiSampleQuality = MultisampleQuality;
691 /* Setup some glformat defaults */
692 object->glDescription.glFormat = tableEntry->glFormat;
693 object->glDescription.glFormatInternal = tableEntry->glInternal;
694 object->glDescription.glType = tableEntry->glType;
696 object->glDescription.textureName = 0;
697 object->glDescription.level = Level;
698 object->glDescription.target = GL_TEXTURE_2D;
700 /* Internal data */
701 object->pow2Width = pow2Width;
702 object->pow2Height = pow2Height;
704 /* Flags */
705 object->Flags = 0;
706 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
707 object->Flags |= Discard ? SFLAG_DISCARD : 0;
708 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
709 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
712 if (WINED3DFMT_UNKNOWN != Format) {
713 object->bytesPerPixel = tableEntry->bpp;
714 } else {
715 object->bytesPerPixel = 0;
718 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
720 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
722 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
723 * this function is too deep to need to care about things like this.
724 * Levels need to be checked too, and possibly Type since they all affect what can be done.
725 * ****************************************/
726 switch(Pool) {
727 case WINED3DPOOL_SCRATCH:
728 if(!Lockable)
729 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
730 "which are mutually exclusive, setting lockable to TRUE\n");
731 Lockable = TRUE;
732 break;
733 case WINED3DPOOL_SYSTEMMEM:
734 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
735 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
736 case WINED3DPOOL_MANAGED:
737 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
738 "Usage of DYNAMIC which are mutually exclusive, not doing "
739 "anything just telling you.\n");
740 break;
741 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
742 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
743 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
744 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
745 break;
746 default:
747 FIXME("(%p) Unknown pool %d\n", This, Pool);
748 break;
751 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
752 FIXME("Trying to create a render target that isn't in the default pool\n");
755 /* mark the texture as dirty so that it gets loaded first time around*/
756 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
757 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
758 This, Width, Height, Format, debug_d3dformat(Format),
759 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
761 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
762 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
763 This->ddraw_primary = (IWineD3DSurface *) object;
765 /* Look at the implementation and set the correct Vtable */
766 switch(Impl) {
767 case SURFACE_OPENGL:
768 /* Nothing to do, it's set already */
769 break;
771 case SURFACE_GDI:
772 object->lpVtbl = &IWineGDISurface_Vtbl;
773 break;
775 default:
776 /* To be sure to catch this */
777 ERR("Unknown requested surface implementation %d!\n", Impl);
778 IWineD3DSurface_Release((IWineD3DSurface *) object);
779 return WINED3DERR_INVALIDCALL;
782 list_init(&object->renderbuffers);
784 /* Call the private setup routine */
785 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
789 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
790 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
791 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
792 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DTextureImpl *object;
796 unsigned int i;
797 UINT tmpW;
798 UINT tmpH;
799 HRESULT hr;
800 unsigned int pow2Width;
801 unsigned int pow2Height;
804 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
805 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
806 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
808 /* TODO: It should only be possible to create textures for formats
809 that are reported as supported */
810 if (WINED3DFMT_UNKNOWN >= Format) {
811 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
812 return WINED3DERR_INVALIDCALL;
815 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
816 D3DINITIALIZEBASETEXTURE(object->baseTexture);
817 object->width = Width;
818 object->height = Height;
820 /** Non-power2 support **/
821 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
822 pow2Width = Width;
823 pow2Height = Height;
824 } else {
825 /* Find the nearest pow2 match */
826 pow2Width = pow2Height = 1;
827 while (pow2Width < Width) pow2Width <<= 1;
828 while (pow2Height < Height) pow2Height <<= 1;
831 /** FIXME: add support for real non-power-two if it's provided by the video card **/
832 /* Precalculated scaling for 'faked' non power of two texture coords */
833 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
834 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
835 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
837 /* Calculate levels for mip mapping */
838 if (Levels == 0) {
839 TRACE("calculating levels %d\n", object->baseTexture.levels);
840 object->baseTexture.levels++;
841 tmpW = Width;
842 tmpH = Height;
843 while (tmpW > 1 || tmpH > 1) {
844 tmpW = max(1, tmpW >> 1);
845 tmpH = max(1, tmpH >> 1);
846 object->baseTexture.levels++;
848 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
851 /* Generate all the surfaces */
852 tmpW = Width;
853 tmpH = Height;
854 for (i = 0; i < object->baseTexture.levels; i++)
856 /* use the callback to create the texture surface */
857 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
858 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
859 FIXME("Failed to create surface %p\n", object);
860 /* clean up */
861 object->surfaces[i] = NULL;
862 IWineD3DTexture_Release((IWineD3DTexture *)object);
864 *ppTexture = NULL;
865 return hr;
868 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
869 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
870 /* calculate the next mipmap level */
871 tmpW = max(1, tmpW >> 1);
872 tmpH = max(1, tmpH >> 1);
875 TRACE("(%p) : Created texture %p\n", This, object);
876 return WINED3D_OK;
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
880 UINT Width, UINT Height, UINT Depth,
881 UINT Levels, DWORD Usage,
882 WINED3DFORMAT Format, WINED3DPOOL Pool,
883 IWineD3DVolumeTexture **ppVolumeTexture,
884 HANDLE *pSharedHandle, IUnknown *parent,
885 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
888 IWineD3DVolumeTextureImpl *object;
889 unsigned int i;
890 UINT tmpW;
891 UINT tmpH;
892 UINT tmpD;
894 /* TODO: It should only be possible to create textures for formats
895 that are reported as supported */
896 if (WINED3DFMT_UNKNOWN >= Format) {
897 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
898 return WINED3DERR_INVALIDCALL;
901 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
902 D3DINITIALIZEBASETEXTURE(object->baseTexture);
904 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
905 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
907 object->width = Width;
908 object->height = Height;
909 object->depth = Depth;
911 /* Calculate levels for mip mapping */
912 if (Levels == 0) {
913 object->baseTexture.levels++;
914 tmpW = Width;
915 tmpH = Height;
916 tmpD = Depth;
917 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
918 tmpW = max(1, tmpW >> 1);
919 tmpH = max(1, tmpH >> 1);
920 tmpD = max(1, tmpD >> 1);
921 object->baseTexture.levels++;
923 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
926 /* Generate all the surfaces */
927 tmpW = Width;
928 tmpH = Height;
929 tmpD = Depth;
931 for (i = 0; i < object->baseTexture.levels; i++)
933 HRESULT hr;
934 /* Create the volume */
935 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
936 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
938 if(FAILED(hr)) {
939 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
940 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
941 *ppVolumeTexture = NULL;
942 return hr;
945 /* Set its container to this object */
946 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
948 /* calcualte the next mipmap level */
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
954 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
955 TRACE("(%p) : Created volume texture %p\n", This, object);
956 return WINED3D_OK;
959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
960 UINT Width, UINT Height, UINT Depth,
961 DWORD Usage,
962 WINED3DFORMAT Format, WINED3DPOOL Pool,
963 IWineD3DVolume** ppVolume,
964 HANDLE* pSharedHandle, IUnknown *parent) {
966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
967 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
968 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
970 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
972 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
973 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
975 object->currentDesc.Width = Width;
976 object->currentDesc.Height = Height;
977 object->currentDesc.Depth = Depth;
978 object->bytesPerPixel = formatDesc->bpp;
980 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
981 object->lockable = TRUE;
982 object->locked = FALSE;
983 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
984 object->dirty = TRUE;
986 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
990 UINT Levels, DWORD Usage,
991 WINED3DFORMAT Format, WINED3DPOOL Pool,
992 IWineD3DCubeTexture **ppCubeTexture,
993 HANDLE *pSharedHandle, IUnknown *parent,
994 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
998 unsigned int i, j;
999 UINT tmpW;
1000 HRESULT hr;
1001 unsigned int pow2EdgeLength = EdgeLength;
1003 /* TODO: It should only be possible to create textures for formats
1004 that are reported as supported */
1005 if (WINED3DFMT_UNKNOWN >= Format) {
1006 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1011 WARN("(%p) : Tried to create not supported cube texture\n", This);
1012 return WINED3DERR_INVALIDCALL;
1015 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1016 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1018 TRACE("(%p) Create Cube Texture\n", This);
1020 /** Non-power2 support **/
1022 /* Find the nearest pow2 match */
1023 pow2EdgeLength = 1;
1024 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1026 object->edgeLength = EdgeLength;
1027 /* TODO: support for native non-power 2 */
1028 /* Precalculated scaling for 'faked' non power of two texture coords */
1029 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1031 /* Calculate levels for mip mapping */
1032 if (Levels == 0) {
1033 object->baseTexture.levels++;
1034 tmpW = EdgeLength;
1035 while (tmpW > 1) {
1036 tmpW = max(1, tmpW >> 1);
1037 object->baseTexture.levels++;
1039 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1042 /* Generate all the surfaces */
1043 tmpW = EdgeLength;
1044 for (i = 0; i < object->baseTexture.levels; i++) {
1046 /* Create the 6 faces */
1047 for (j = 0; j < 6; j++) {
1049 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1050 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1052 if(hr!= WINED3D_OK) {
1053 /* clean up */
1054 int k;
1055 int l;
1056 for (l = 0; l < j; l++) {
1057 IWineD3DSurface_Release(object->surfaces[j][i]);
1059 for (k = 0; k < i; k++) {
1060 for (l = 0; l < 6; l++) {
1061 IWineD3DSurface_Release(object->surfaces[l][j]);
1065 FIXME("(%p) Failed to create surface\n",object);
1066 HeapFree(GetProcessHeap(),0,object);
1067 *ppCubeTexture = NULL;
1068 return hr;
1070 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1071 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1073 tmpW = max(1, tmpW >> 1);
1076 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1077 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1078 return WINED3D_OK;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1083 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1084 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1086 /* Just a check to see if we support this type of query */
1087 switch(Type) {
1088 case WINED3DQUERYTYPE_OCCLUSION:
1089 TRACE("(%p) occlusion query\n", This);
1090 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1091 hr = WINED3D_OK;
1092 else
1093 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1094 break;
1096 case WINED3DQUERYTYPE_EVENT:
1097 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1098 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1099 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1101 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1103 hr = WINED3D_OK;
1104 break;
1106 case WINED3DQUERYTYPE_VCACHE:
1107 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1108 case WINED3DQUERYTYPE_VERTEXSTATS:
1109 case WINED3DQUERYTYPE_TIMESTAMP:
1110 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1111 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1112 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1113 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1114 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1115 case WINED3DQUERYTYPE_PIXELTIMINGS:
1116 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1117 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1118 default:
1119 FIXME("(%p) Unhandled query type %d\n", This, Type);
1121 if(NULL == ppQuery || hr != WINED3D_OK) {
1122 return hr;
1125 D3DCREATEOBJECTINSTANCE(object, Query)
1126 object->type = Type;
1127 /* allocated the 'extended' data based on the type of query requested */
1128 switch(Type){
1129 case WINED3DQUERYTYPE_OCCLUSION:
1130 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1131 TRACE("(%p) Allocating data for an occlusion query\n", This);
1132 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1133 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1134 break;
1136 case WINED3DQUERYTYPE_EVENT:
1137 /* TODO: GL_APPLE_fence */
1138 if(GL_SUPPORT(APPLE_FENCE)) {
1139 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1140 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1141 checkGLcall("glGenFencesAPPLE");
1142 } else if(GL_SUPPORT(NV_FENCE)) {
1143 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1144 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1145 checkGLcall("glGenFencesNV");
1147 break;
1149 case WINED3DQUERYTYPE_VCACHE:
1150 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1151 case WINED3DQUERYTYPE_VERTEXSTATS:
1152 case WINED3DQUERYTYPE_TIMESTAMP:
1153 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1154 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1155 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1156 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1157 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1158 case WINED3DQUERYTYPE_PIXELTIMINGS:
1159 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1160 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1161 default:
1162 object->extendedData = 0;
1163 FIXME("(%p) Unhandled query type %d\n",This , Type);
1165 TRACE("(%p) : Created Query %p\n", This, object);
1166 return WINED3D_OK;
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_SetupFullscreenWindow
1172 * Helper function that modifies a HWND's Style and ExStyle for proper
1173 * fullscreen use.
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 LONG style, exStyle;
1184 /* Don't do anything if an original style is stored.
1185 * That shouldn't happen
1187 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1188 if (This->style || This->exStyle) {
1189 ERR("(%p): Want to change the window parameters of HWND %p, but "
1190 "another style is stored for restoration afterwards\n", This, window);
1193 /* Get the parameters and save them */
1194 style = GetWindowLongW(window, GWL_STYLE);
1195 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1196 This->style = style;
1197 This->exStyle = exStyle;
1199 /* Filter out window decorations */
1200 style &= ~WS_CAPTION;
1201 style &= ~WS_THICKFRAME;
1202 exStyle &= ~WS_EX_WINDOWEDGE;
1203 exStyle &= ~WS_EX_CLIENTEDGE;
1205 /* Make sure the window is managed, otherwise we won't get keyboard input */
1206 style |= WS_POPUP | WS_SYSMENU;
1208 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1209 This->style, This->exStyle, style, exStyle);
1211 SetWindowLongW(window, GWL_STYLE, style);
1212 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1214 /* Inform the window about the update. */
1215 SetWindowPos(window, HWND_TOP, 0, 0,
1216 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1217 ShowWindow(window, SW_NORMAL);
1220 /*****************************************************************************
1221 * IWineD3DDeviceImpl_RestoreWindow
1223 * Helper function that restores a windows' properties when taking it out
1224 * of fullscreen mode
1226 * Params:
1227 * iface: Pointer to the IWineD3DDevice interface
1228 * window: Window to setup
1230 *****************************************************************************/
1231 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1235 * switch, do nothing
1237 if (!This->style && !This->exStyle) return;
1239 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1240 This, window, This->style, This->exStyle);
1242 SetWindowLongW(window, GWL_STYLE, This->style);
1243 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1245 /* Delete the old values */
1246 This->style = 0;
1247 This->exStyle = 0;
1249 /* Inform the window about the update */
1250 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1251 0, 0, 0, 0, /* Pos, Size, ignored */
1252 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1255 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1256 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1257 IUnknown* parent,
1258 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1259 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1262 HDC hDc;
1263 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1264 HRESULT hr = WINED3D_OK;
1265 IUnknown *bufferParent;
1266 Display *display;
1268 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1270 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1271 * does a device hold a reference to a swap chain giving them a lifetime of the device
1272 * or does the swap chain notify the device of its destruction.
1273 *******************************/
1275 /* Check the params */
1276 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1277 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1278 return WINED3DERR_INVALIDCALL;
1279 } else if (pPresentationParameters->BackBufferCount > 1) {
1280 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1283 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1285 /*********************
1286 * Lookup the window Handle and the relating X window handle
1287 ********************/
1289 /* Setup hwnd we are using, plus which display this equates to */
1290 object->win_handle = pPresentationParameters->hDeviceWindow;
1291 if (!object->win_handle) {
1292 object->win_handle = This->createParms.hFocusWindow;
1295 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1296 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1297 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1298 return WINED3DERR_NOTAVAILABLE;
1300 hDc = GetDC(object->win_handle);
1301 display = get_display(hDc);
1302 ReleaseDC(object->win_handle, hDc);
1303 TRACE("Using a display of %p %p\n", display, hDc);
1305 if (NULL == display || NULL == hDc) {
1306 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1307 return WINED3DERR_NOTAVAILABLE;
1310 if (object->win == 0) {
1311 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1312 return WINED3DERR_NOTAVAILABLE;
1315 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1316 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1317 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1319 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1320 * then the corresponding dimension of the client area of the hDeviceWindow
1321 * (or the focus window, if hDeviceWindow is NULL) is taken.
1322 **********************/
1324 if (pPresentationParameters->Windowed &&
1325 ((pPresentationParameters->BackBufferWidth == 0) ||
1326 (pPresentationParameters->BackBufferHeight == 0))) {
1328 RECT Rect;
1329 GetClientRect(object->win_handle, &Rect);
1331 if (pPresentationParameters->BackBufferWidth == 0) {
1332 pPresentationParameters->BackBufferWidth = Rect.right;
1333 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1335 if (pPresentationParameters->BackBufferHeight == 0) {
1336 pPresentationParameters->BackBufferHeight = Rect.bottom;
1337 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1341 /* Put the correct figures in the presentation parameters */
1342 TRACE("Copying across presentation parameters\n");
1343 object->presentParms = *pPresentationParameters;
1345 TRACE("calling rendertarget CB\n");
1346 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1347 parent,
1348 object->presentParms.BackBufferWidth,
1349 object->presentParms.BackBufferHeight,
1350 object->presentParms.BackBufferFormat,
1351 object->presentParms.MultiSampleType,
1352 object->presentParms.MultiSampleQuality,
1353 TRUE /* Lockable */,
1354 &object->frontBuffer,
1355 NULL /* pShared (always null)*/);
1356 if (object->frontBuffer != NULL) {
1357 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1358 } else {
1359 ERR("Failed to create the front buffer\n");
1360 goto error;
1364 * Create an opengl context for the display visual
1365 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1366 * use different properties after that point in time. FIXME: How to handle when requested format
1367 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1368 * it chooses is identical to the one already being used!
1369 **********************************/
1370 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1372 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1373 if(!object->context)
1374 return E_OUTOFMEMORY;
1375 object->num_contexts = 1;
1377 ENTER_GL();
1378 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1379 LEAVE_GL();
1381 if (!object->context[0]) {
1382 ERR("Failed to create a new context\n");
1383 hr = WINED3DERR_NOTAVAILABLE;
1384 goto error;
1385 } else {
1386 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1387 object->win_handle, object->context[0]->glCtx, object->win);
1390 /*********************
1391 * Windowed / Fullscreen
1392 *******************/
1395 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1396 * so we should really check to see if there is a fullscreen swapchain already
1397 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1398 **************************************/
1400 if (!pPresentationParameters->Windowed) {
1402 DEVMODEW devmode;
1403 HDC hdc;
1404 int bpp = 0;
1405 RECT clip_rc;
1407 /* Get info on the current display setup */
1408 hdc = GetDC(0);
1409 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 ReleaseDC(0, hdc);
1412 /* Change the display settings */
1413 memset(&devmode, 0, sizeof(DEVMODEW));
1414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1415 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1416 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1417 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1418 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1419 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1421 /* For GetDisplayMode */
1422 This->ddraw_width = devmode.dmPelsWidth;
1423 This->ddraw_height = devmode.dmPelsHeight;
1424 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1426 IWineD3DDevice_SetFullscreen(iface, TRUE);
1428 /* And finally clip mouse to our screen */
1429 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1430 ClipCursor(&clip_rc);
1433 /*********************
1434 * Create the back, front and stencil buffers
1435 *******************/
1436 if(object->presentParms.BackBufferCount > 0) {
1437 int i;
1439 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1440 if(!object->backBuffer) {
1441 ERR("Out of memory\n");
1442 hr = E_OUTOFMEMORY;
1443 goto error;
1446 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1447 TRACE("calling rendertarget CB\n");
1448 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1449 parent,
1450 object->presentParms.BackBufferWidth,
1451 object->presentParms.BackBufferHeight,
1452 object->presentParms.BackBufferFormat,
1453 object->presentParms.MultiSampleType,
1454 object->presentParms.MultiSampleQuality,
1455 TRUE /* Lockable */,
1456 &object->backBuffer[i],
1457 NULL /* pShared (always null)*/);
1458 if(hr == WINED3D_OK && object->backBuffer[i]) {
1459 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1460 } else {
1461 ERR("Cannot create new back buffer\n");
1462 goto error;
1464 ENTER_GL();
1465 glDrawBuffer(GL_BACK);
1466 checkGLcall("glDrawBuffer(GL_BACK)");
1467 LEAVE_GL();
1469 } else {
1470 object->backBuffer = NULL;
1472 /* Single buffering - draw to front buffer */
1473 ENTER_GL();
1474 glDrawBuffer(GL_FRONT);
1475 checkGLcall("glDrawBuffer(GL_FRONT)");
1476 LEAVE_GL();
1479 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1480 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1481 TRACE("Creating depth stencil buffer\n");
1482 if (This->depthStencilBuffer == NULL ) {
1483 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1484 parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.AutoDepthStencilFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 FALSE /* FIXME: Discard */,
1491 &This->depthStencilBuffer,
1492 NULL /* pShared (always null)*/ );
1493 if (This->depthStencilBuffer != NULL)
1494 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1497 /** TODO: A check on width, height and multisample types
1498 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1499 ****************************/
1500 object->wantsDepthStencilBuffer = TRUE;
1501 } else {
1502 object->wantsDepthStencilBuffer = FALSE;
1505 TRACE("Created swapchain %p\n", object);
1506 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1507 return WINED3D_OK;
1509 error:
1510 if (object->backBuffer) {
1511 int i;
1512 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1513 if(object->backBuffer[i]) {
1514 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1515 IUnknown_Release(bufferParent); /* once for the get parent */
1516 if (IUnknown_Release(bufferParent) > 0) {
1517 FIXME("(%p) Something's still holding the back buffer\n",This);
1521 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1522 object->backBuffer = NULL;
1524 if(object->context[0])
1525 DestroyContext(This, object->context[0]);
1526 if(object->frontBuffer) {
1527 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1528 IUnknown_Release(bufferParent); /* once for the get parent */
1529 if (IUnknown_Release(bufferParent) > 0) {
1530 FIXME("(%p) Something's still holding the front buffer\n",This);
1533 HeapFree(GetProcessHeap(), 0, object);
1534 return hr;
1537 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1538 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 TRACE("(%p)\n", This);
1542 return This->NumberOfSwapChains;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1549 if(iSwapChain < This->NumberOfSwapChains) {
1550 *pSwapChain = This->swapchains[iSwapChain];
1551 IWineD3DSwapChain_AddRef(*pSwapChain);
1552 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 return WINED3D_OK;
1554 } else {
1555 TRACE("Swapchain out of range\n");
1556 *pSwapChain = NULL;
1557 return WINED3DERR_INVALIDCALL;
1561 /*****
1562 * Vertex Declaration
1563 *****/
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1565 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1567 IWineD3DVertexDeclarationImpl *object = NULL;
1568 HRESULT hr = WINED3D_OK;
1570 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1571 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1573 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1575 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1577 return hr;
1580 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1582 unsigned int idx, idx2;
1583 unsigned int offset;
1584 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1585 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1586 BOOL has_blend_idx = has_blend &&
1587 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1588 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1589 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1590 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1591 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1592 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1593 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1595 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1596 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1598 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1599 WINED3DVERTEXELEMENT *elements = NULL;
1601 unsigned int size;
1602 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1603 if (has_blend_idx) num_blends--;
1605 /* Compute declaration size */
1606 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1607 has_psize + has_diffuse + has_specular + num_textures + 1;
1609 /* convert the declaration */
1610 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1611 if (!elements)
1612 return 0;
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 idx = 0;
1616 if (has_pos) {
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1621 else {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1626 idx++;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1631 else
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
1635 idx++;
1637 if (has_blend_idx) {
1638 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1639 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1640 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1641 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1642 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1643 else
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1647 idx++;
1649 if (has_normal) {
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1653 idx++;
1655 if (has_psize) {
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1659 idx++;
1661 if (has_diffuse) {
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1665 idx++;
1667 if (has_specular) {
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
1671 idx++;
1673 for (idx2 = 0; idx2 < num_textures; idx2++) {
1674 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1675 switch (numcoords) {
1676 case WINED3DFVF_TEXTUREFORMAT1:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1684 break;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 break;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
1691 idx++;
1694 /* Now compute offsets, and initialize the rest of the fields */
1695 for (idx = 0, offset = 0; idx < size-1; idx++) {
1696 elements[idx].Stream = 0;
1697 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1698 elements[idx].Offset = offset;
1699 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1702 *ppVertexElements = elements;
1703 return size;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
1708 size_t size;
1709 DWORD hr;
1711 size = ConvertFvfToDeclaration(Fvf, &elements);
1712 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1714 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1715 HeapFree(GetProcessHeap(), 0, elements);
1716 if (hr != S_OK) return hr;
1718 return WINED3D_OK;
1721 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1725 HRESULT hr = WINED3D_OK;
1726 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1727 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1729 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1731 if (vertex_declaration) {
1732 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1735 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1737 if (WINED3D_OK != hr) {
1738 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1739 IWineD3DVertexShader_Release(*ppVertexShader);
1740 return WINED3DERR_INVALIDCALL;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1749 HRESULT hr = WINED3D_OK;
1751 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1752 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1753 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1754 if (WINED3D_OK == hr) {
1755 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1756 } else {
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1760 return hr;
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
1766 HRESULT hr;
1767 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1769 /* Create the new object */
1770 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1771 if(!object) {
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
1777 object->ref = 1;
1778 object->Flags = Flags;
1779 object->parent = Parent;
1780 object->wineD3DDevice = This;
1781 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1783 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1785 if(!object->hpal) {
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1791 if(FAILED(hr)) {
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1793 return hr;
1796 *Palette = (IWineD3DPalette *) object;
1798 return WINED3D_OK;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
1804 HRESULT hr;
1805 DWORD state;
1807 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1808 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1810 /* TODO: Test if OpenGL is compiled in and loaded */
1812 /* Initialize the texture unit mapping to a 1:1 mapping */
1813 for(state = 0; state < MAX_SAMPLERS; state++) {
1814 This->texUnitMap[state] = state;
1816 This->oneToOneTexUnitMap = TRUE;
1818 /* Setup the implicit swapchain */
1819 TRACE("Creating implicit swapchain\n");
1820 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1821 if (FAILED(hr) || !swapchain) {
1822 WARN("Failed to create implicit swapchain\n");
1823 return hr;
1826 This->NumberOfSwapChains = 1;
1827 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1828 if(!This->swapchains) {
1829 ERR("Out of memory!\n");
1830 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1831 return E_OUTOFMEMORY;
1833 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1835 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1837 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1838 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1839 This->render_targets[0] = swapchain->backBuffer[0];
1840 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1842 else {
1843 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1844 This->render_targets[0] = swapchain->frontBuffer;
1845 This->lastActiveRenderTarget = swapchain->frontBuffer;
1847 IWineD3DSurface_AddRef(This->render_targets[0]);
1848 This->activeContext = swapchain->context[0];
1850 /* Depth Stencil support */
1851 This->stencilBufferTarget = This->depthStencilBuffer;
1852 if (NULL != This->stencilBufferTarget) {
1853 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1856 /* Set up some starting GL setup */
1857 ENTER_GL();
1859 /* Setup all the devices defaults */
1860 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1861 #if 0
1862 IWineD3DImpl_CheckGraphicsMemory();
1863 #endif
1865 { /* Set a default viewport */
1866 WINED3DVIEWPORT vp;
1867 vp.X = 0;
1868 vp.Y = 0;
1869 vp.Width = pPresentationParameters->BackBufferWidth;
1870 vp.Height = pPresentationParameters->BackBufferHeight;
1871 vp.MinZ = 0.0f;
1872 vp.MaxZ = 1.0f;
1873 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1876 /* Initialize the current view state */
1877 This->view_ident = 1;
1878 This->contexts[0]->last_was_rhw = 0;
1879 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1880 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1882 switch(wined3d_settings.offscreen_rendering_mode) {
1883 case ORM_FBO:
1884 case ORM_PBUFFER:
1885 This->offscreenBuffer = GL_BACK;
1886 break;
1888 case ORM_BACKBUFFER:
1890 if(GL_LIMITS(aux_buffers) > 0) {
1891 TRACE("Using auxilliary buffer for offscreen rendering\n");
1892 This->offscreenBuffer = GL_AUX0;
1893 } else {
1894 TRACE("Using back buffer for offscreen rendering\n");
1895 This->offscreenBuffer = GL_BACK;
1900 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1901 LEAVE_GL();
1903 /* Clear the screen */
1904 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1905 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1906 0x00, 1.0, 0);
1908 This->d3d_initialized = TRUE;
1909 return WINED3D_OK;
1912 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1914 int sampler;
1915 uint i;
1916 TRACE("(%p)\n", This);
1918 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1920 ENTER_GL();
1921 /* I don't think that the interface guarants that the device is destroyed from the same thread
1922 * it was created. Thus make sure a context is active for the glDelete* calls
1924 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1925 LEAVE_GL();
1927 /* Delete the pbuffer context if there is any */
1928 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1930 /* Delete the mouse cursor texture */
1931 if(This->cursorTexture) {
1932 ENTER_GL();
1933 glDeleteTextures(1, &This->cursorTexture);
1934 LEAVE_GL();
1935 This->cursorTexture = 0;
1938 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1939 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1942 /* Release the buffers (with sanity checks)*/
1943 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1944 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1945 if(This->depthStencilBuffer != This->stencilBufferTarget)
1946 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1948 This->stencilBufferTarget = NULL;
1950 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1951 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1952 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1954 TRACE("Setting rendertarget to NULL\n");
1955 This->render_targets[0] = NULL;
1957 if (This->depthStencilBuffer) {
1958 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1959 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1961 This->depthStencilBuffer = NULL;
1964 for(i=0; i < This->NumberOfSwapChains; i++) {
1965 TRACE("Releasing the implicit swapchain %d\n", i);
1966 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1967 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1971 HeapFree(GetProcessHeap(), 0, This->swapchains);
1972 This->swapchains = NULL;
1973 This->NumberOfSwapChains = 0;
1975 This->d3d_initialized = FALSE;
1976 return WINED3D_OK;
1979 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1981 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1983 /* Setup the window for fullscreen mode */
1984 if(fullscreen && !This->ddraw_fullscreen) {
1985 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1986 } else if(!fullscreen && This->ddraw_fullscreen) {
1987 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1990 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1991 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1992 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1993 * separately.
1995 This->ddraw_fullscreen = fullscreen;
1998 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1999 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2000 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2002 * There is no way to deactivate thread safety once it is enabled
2004 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 FIXME("No thread safety in wined3d yet\n");
2008 /*For now just store the flag(needed in case of ddraw) */
2009 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2011 return;
2014 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2015 DEVMODEW devmode;
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2017 LONG ret;
2018 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2019 RECT clip_rc;
2021 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2023 /* Resize the screen even without a window:
2024 * The app could have unset it with SetCooperativeLevel, but not called
2025 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2026 * but we don't have any hwnd
2029 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2030 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2031 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2032 devmode.dmPelsWidth = pMode->Width;
2033 devmode.dmPelsHeight = pMode->Height;
2035 devmode.dmDisplayFrequency = pMode->RefreshRate;
2036 if (pMode->RefreshRate != 0) {
2037 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2040 /* Only change the mode if necessary */
2041 if( (This->ddraw_width == pMode->Width) &&
2042 (This->ddraw_height == pMode->Height) &&
2043 (This->ddraw_format == pMode->Format) &&
2044 (pMode->RefreshRate == 0) ) {
2045 return WINED3D_OK;
2048 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2049 if (ret != DISP_CHANGE_SUCCESSFUL) {
2050 if(devmode.dmDisplayFrequency != 0) {
2051 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2052 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2053 devmode.dmDisplayFrequency = 0;
2054 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2056 if(ret != DISP_CHANGE_SUCCESSFUL) {
2057 return WINED3DERR_NOTAVAILABLE;
2061 /* Store the new values */
2062 This->ddraw_width = pMode->Width;
2063 This->ddraw_height = pMode->Height;
2064 This->ddraw_format = pMode->Format;
2066 /* Only do this with a window of course */
2067 if(This->ddraw_window)
2068 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2070 /* And finally clip mouse to our screen */
2071 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2072 ClipCursor(&clip_rc);
2074 return WINED3D_OK;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 *ppD3D= This->wineD3D;
2080 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2081 IWineD3D_AddRef(*ppD3D);
2082 return WINED3D_OK;
2085 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2086 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2087 * into the video ram as possible and seeing how many fit
2088 * you can also get the correct initial value from nvidia and ATI's driver via X
2089 * texture memory is video memory + AGP memory
2090 *******************/
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2092 static BOOL showfixmes = TRUE;
2093 if (showfixmes) {
2094 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2095 (wined3d_settings.emulated_textureram/(1024*1024)),
2096 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2097 showfixmes = FALSE;
2099 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2100 (wined3d_settings.emulated_textureram/(1024*1024)),
2101 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2102 /* return simulated texture memory left */
2103 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2108 /*****
2109 * Get / Set FVF
2110 *****/
2111 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 /* Update the current state block */
2115 This->updateStateBlock->changed.fvf = TRUE;
2116 This->updateStateBlock->set.fvf = TRUE;
2118 if(This->updateStateBlock->fvf == fvf) {
2119 TRACE("Application is setting the old fvf over, nothing to do\n");
2120 return WINED3D_OK;
2123 This->updateStateBlock->fvf = fvf;
2124 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2126 return WINED3D_OK;
2130 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2133 *pfvf = This->stateBlock->fvf;
2134 return WINED3D_OK;
2137 /*****
2138 * Get / Set Stream Source
2139 *****/
2140 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2142 IWineD3DVertexBuffer *oldSrc;
2144 if (StreamNumber >= MAX_STREAMS) {
2145 WARN("Stream out of range %d\n", StreamNumber);
2146 return WINED3DERR_INVALIDCALL;
2149 oldSrc = This->stateBlock->streamSource[StreamNumber];
2150 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2152 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2153 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2155 if(oldSrc == pStreamData &&
2156 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2157 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2158 TRACE("Application is setting the old values over, nothing to do\n");
2159 return WINED3D_OK;
2162 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2163 if (pStreamData) {
2164 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2165 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2168 /* Handle recording of state blocks */
2169 if (This->isRecordingState) {
2170 TRACE("Recording... not performing anything\n");
2171 return WINED3D_OK;
2174 /* Need to do a getParent and pass the reffs up */
2175 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2176 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2177 so for now, just count internally */
2178 if (pStreamData != NULL) {
2179 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2180 InterlockedIncrement(&vbImpl->bindCount);
2182 if (oldSrc != NULL) {
2183 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2188 return WINED3D_OK;
2191 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2195 This->stateBlock->streamSource[StreamNumber],
2196 This->stateBlock->streamOffset[StreamNumber],
2197 This->stateBlock->streamStride[StreamNumber]);
2199 if (StreamNumber >= MAX_STREAMS) {
2200 WARN("Stream out of range %d\n", StreamNumber);
2201 return WINED3DERR_INVALIDCALL;
2203 *pStream = This->stateBlock->streamSource[StreamNumber];
2204 *pStride = This->stateBlock->streamStride[StreamNumber];
2205 if (pOffset) {
2206 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2209 if (*pStream != NULL) {
2210 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2212 return WINED3D_OK;
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2217 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2218 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2220 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2221 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2223 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2224 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2227 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2228 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2232 return WINED3D_OK;
2235 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2238 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2239 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2241 TRACE("(%p) : returning %d\n", This, *Divider);
2243 return WINED3D_OK;
2246 /*****
2247 * Get / Set & Multiply Transform
2248 *****/
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 /* Most of this routine, comments included copied from ddraw tree initially: */
2253 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2255 /* Handle recording of state blocks */
2256 if (This->isRecordingState) {
2257 TRACE("Recording... not performing anything\n");
2258 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2259 This->updateStateBlock->set.transform[d3dts] = TRUE;
2260 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2261 return WINED3D_OK;
2265 * If the new matrix is the same as the current one,
2266 * we cut off any further processing. this seems to be a reasonable
2267 * optimization because as was noticed, some apps (warcraft3 for example)
2268 * tend towards setting the same matrix repeatedly for some reason.
2270 * From here on we assume that the new matrix is different, wherever it matters.
2272 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2273 TRACE("The app is setting the same matrix over again\n");
2274 return WINED3D_OK;
2275 } else {
2276 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2280 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2281 where ViewMat = Camera space, WorldMat = world space.
2283 In OpenGL, camera and world space is combined into GL_MODELVIEW
2284 matrix. The Projection matrix stay projection matrix.
2287 /* Capture the times we can just ignore the change for now */
2288 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2289 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2290 /* Handled by the state manager */
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2294 return WINED3D_OK;
2297 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2300 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2301 return WINED3D_OK;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2305 WINED3DMATRIX *mat = NULL;
2306 WINED3DMATRIX temp;
2308 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2309 * below means it will be recorded in a state block change, but it
2310 * works regardless where it is recorded.
2311 * If this is found to be wrong, change to StateBlock.
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2316 if (State < HIGHEST_TRANSFORMSTATE)
2318 mat = &This->updateStateBlock->transforms[State];
2319 } else {
2320 FIXME("Unhandled transform state!!\n");
2323 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2325 /* Apply change via set transform - will reapply to eg. lights this way */
2326 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2329 /*****
2330 * Get / Set Light
2331 *****/
2332 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2333 you can reference any indexes you want as long as that number max are enabled at any
2334 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2335 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2336 but when recording, just build a chain pretty much of commands to be replayed. */
2338 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2339 float rho;
2340 PLIGHTINFOEL *object = NULL;
2341 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2342 struct list *e;
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2347 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2348 * the gl driver.
2350 if(!pLight) {
2351 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2352 return WINED3DERR_INVALIDCALL;
2355 switch(pLight->Type) {
2356 case WINED3DLIGHT_POINT:
2357 case WINED3DLIGHT_SPOT:
2358 case WINED3DLIGHT_PARALLELPOINT:
2359 case WINED3DLIGHT_GLSPOT:
2360 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2361 * most wanted
2363 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2364 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL;
2367 break;
2369 case WINED3DLIGHT_DIRECTIONAL:
2370 /* Ignores attenuation */
2371 break;
2373 default:
2374 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2375 return WINED3DERR_INVALIDCALL;
2378 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2379 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2380 if(object->OriginalIndex == Index) break;
2381 object = NULL;
2384 if(!object) {
2385 TRACE("Adding new light\n");
2386 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2387 if(!object) {
2388 ERR("Out of memory error when allocating a light\n");
2389 return E_OUTOFMEMORY;
2391 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2392 object->glIndex = -1;
2393 object->OriginalIndex = Index;
2394 object->changed = TRUE;
2397 /* Initialize the object */
2398 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2399 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2400 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2401 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2402 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2403 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2404 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2406 /* Save away the information */
2407 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2409 switch (pLight->Type) {
2410 case WINED3DLIGHT_POINT:
2411 /* Position */
2412 object->lightPosn[0] = pLight->Position.x;
2413 object->lightPosn[1] = pLight->Position.y;
2414 object->lightPosn[2] = pLight->Position.z;
2415 object->lightPosn[3] = 1.0f;
2416 object->cutoff = 180.0f;
2417 /* FIXME: Range */
2418 break;
2420 case WINED3DLIGHT_DIRECTIONAL:
2421 /* Direction */
2422 object->lightPosn[0] = -pLight->Direction.x;
2423 object->lightPosn[1] = -pLight->Direction.y;
2424 object->lightPosn[2] = -pLight->Direction.z;
2425 object->lightPosn[3] = 0.0;
2426 object->exponent = 0.0f;
2427 object->cutoff = 180.0f;
2428 break;
2430 case WINED3DLIGHT_SPOT:
2431 /* Position */
2432 object->lightPosn[0] = pLight->Position.x;
2433 object->lightPosn[1] = pLight->Position.y;
2434 object->lightPosn[2] = pLight->Position.z;
2435 object->lightPosn[3] = 1.0;
2437 /* Direction */
2438 object->lightDirn[0] = pLight->Direction.x;
2439 object->lightDirn[1] = pLight->Direction.y;
2440 object->lightDirn[2] = pLight->Direction.z;
2441 object->lightDirn[3] = 1.0;
2444 * opengl-ish and d3d-ish spot lights use too different models for the
2445 * light "intensity" as a function of the angle towards the main light direction,
2446 * so we only can approximate very roughly.
2447 * however spot lights are rather rarely used in games (if ever used at all).
2448 * furthermore if still used, probably nobody pays attention to such details.
2450 if (pLight->Falloff == 0) {
2451 rho = 6.28f;
2452 } else {
2453 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2455 if (rho < 0.0001) rho = 0.0001f;
2456 object->exponent = -0.3/log(cos(rho/2));
2457 if (object->exponent > 128.0) {
2458 object->exponent = 128.0;
2460 object->cutoff = pLight->Phi*90/M_PI;
2462 /* FIXME: Range */
2463 break;
2465 default:
2466 FIXME("Unrecognized light type %d\n", pLight->Type);
2469 /* Update the live definitions if the light is currently assigned a glIndex */
2470 if (object->glIndex != -1 && !This->isRecordingState) {
2471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2473 return WINED3D_OK;
2476 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2477 PLIGHTINFOEL *lightInfo = NULL;
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2480 struct list *e;
2481 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2483 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2484 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2485 if(lightInfo->OriginalIndex == Index) break;
2486 lightInfo = NULL;
2489 if (lightInfo == NULL) {
2490 TRACE("Light information requested but light not defined\n");
2491 return WINED3DERR_INVALIDCALL;
2494 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2495 return WINED3D_OK;
2498 /*****
2499 * Get / Set Light Enable
2500 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2503 PLIGHTINFOEL *lightInfo = NULL;
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2506 struct list *e;
2507 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2509 /* Tests show true = 128...not clear why */
2510 Enable = Enable? 128: 0;
2512 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2513 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2514 if(lightInfo->OriginalIndex == Index) break;
2515 lightInfo = NULL;
2517 TRACE("Found light: %p\n", lightInfo);
2519 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2520 if (lightInfo == NULL) {
2522 TRACE("Light enabled requested but light not defined, so defining one!\n");
2523 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2525 /* Search for it again! Should be fairly quick as near head of list */
2526 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2527 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2528 if(lightInfo->OriginalIndex == Index) break;
2529 lightInfo = NULL;
2531 if (lightInfo == NULL) {
2532 FIXME("Adding default lights has failed dismally\n");
2533 return WINED3DERR_INVALIDCALL;
2537 lightInfo->enabledChanged = TRUE;
2538 if(!Enable) {
2539 if(lightInfo->glIndex != -1) {
2540 if(!This->isRecordingState) {
2541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2544 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2545 lightInfo->glIndex = -1;
2546 } else {
2547 TRACE("Light already disabled, nothing to do\n");
2549 } else {
2550 if (lightInfo->glIndex != -1) {
2551 /* nop */
2552 TRACE("Nothing to do as light was enabled\n");
2553 } else {
2554 int i;
2555 /* Find a free gl light */
2556 for(i = 0; i < This->maxConcurrentLights; i++) {
2557 if(This->stateBlock->activeLights[i] == NULL) {
2558 This->stateBlock->activeLights[i] = lightInfo;
2559 lightInfo->glIndex = i;
2560 break;
2563 if(lightInfo->glIndex == -1) {
2564 ERR("Too many concurrently active lights\n");
2565 return WINED3DERR_INVALIDCALL;
2568 /* i == lightInfo->glIndex */
2569 if(!This->isRecordingState) {
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2575 return WINED3D_OK;
2578 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2580 PLIGHTINFOEL *lightInfo = NULL;
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 struct list *e;
2583 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2584 TRACE("(%p) : for idx(%d)\n", This, Index);
2586 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2587 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2588 if(lightInfo->OriginalIndex == Index) break;
2589 lightInfo = NULL;
2592 if (lightInfo == NULL) {
2593 TRACE("Light enabled state requested but light not defined\n");
2594 return WINED3DERR_INVALIDCALL;
2596 /* true is 128 according to SetLightEnable */
2597 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2598 return WINED3D_OK;
2601 /*****
2602 * Get / Set Clip Planes
2603 *****/
2604 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2608 /* Validate Index */
2609 if (Index >= GL_LIMITS(clipplanes)) {
2610 TRACE("Application has requested clipplane this device doesn't support\n");
2611 return WINED3DERR_INVALIDCALL;
2614 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2615 This->updateStateBlock->set.clipplane[Index] = TRUE;
2617 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2618 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2619 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2620 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2621 TRACE("Application is setting old values over, nothing to do\n");
2622 return WINED3D_OK;
2625 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2626 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2627 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2628 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2630 /* Handle recording of state blocks */
2631 if (This->isRecordingState) {
2632 TRACE("Recording... not performing anything\n");
2633 return WINED3D_OK;
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : for idx %d\n", This, Index);
2645 /* Validate Index */
2646 if (Index >= GL_LIMITS(clipplanes)) {
2647 TRACE("Application has requested clipplane this device doesn't support\n");
2648 return WINED3DERR_INVALIDCALL;
2651 pPlane[0] = This->stateBlock->clipplane[Index][0];
2652 pPlane[1] = This->stateBlock->clipplane[Index][1];
2653 pPlane[2] = This->stateBlock->clipplane[Index][2];
2654 pPlane[3] = This->stateBlock->clipplane[Index][3];
2655 return WINED3D_OK;
2658 /*****
2659 * Get / Set Clip Plane Status
2660 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2661 *****/
2662 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 FIXME("(%p) : stub\n", This);
2665 if (NULL == pClipStatus) {
2666 return WINED3DERR_INVALIDCALL;
2668 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2669 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2670 return WINED3D_OK;
2673 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 FIXME("(%p) : stub\n", This);
2676 if (NULL == pClipStatus) {
2677 return WINED3DERR_INVALIDCALL;
2679 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2680 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2681 return WINED3D_OK;
2684 /*****
2685 * Get / Set Material
2686 *****/
2687 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 This->updateStateBlock->changed.material = TRUE;
2691 This->updateStateBlock->set.material = TRUE;
2692 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2700 ENTER_GL();
2701 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2702 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2703 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2704 pMaterial->Ambient.b, pMaterial->Ambient.a);
2705 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2706 pMaterial->Specular.b, pMaterial->Specular.a);
2707 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2708 pMaterial->Emissive.b, pMaterial->Emissive.a);
2709 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2711 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2712 checkGLcall("glMaterialfv(GL_AMBIENT)");
2713 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2714 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2716 /* Only change material color if specular is enabled, otherwise it is set to black */
2717 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2718 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2719 checkGLcall("glMaterialfv(GL_SPECULAR");
2720 } else {
2721 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2722 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2723 checkGLcall("glMaterialfv(GL_SPECULAR");
2725 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2726 checkGLcall("glMaterialfv(GL_EMISSION)");
2727 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2728 checkGLcall("glMaterialf(GL_SHININESS");
2730 LEAVE_GL();
2731 return WINED3D_OK;
2734 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2737 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2738 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2739 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2740 pMaterial->Ambient.b, pMaterial->Ambient.a);
2741 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2742 pMaterial->Specular.b, pMaterial->Specular.a);
2743 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2744 pMaterial->Emissive.b, pMaterial->Emissive.a);
2745 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2747 return WINED3D_OK;
2750 /*****
2751 * Get / Set Indices
2752 *****/
2753 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 IWineD3DIndexBuffer *oldIdxs;
2757 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2758 oldIdxs = This->updateStateBlock->pIndexData;
2760 This->updateStateBlock->changed.indices = TRUE;
2761 This->updateStateBlock->set.indices = TRUE;
2762 This->updateStateBlock->pIndexData = pIndexData;
2764 /* Handle recording of state blocks */
2765 if (This->isRecordingState) {
2766 TRACE("Recording... not performing anything\n");
2767 return WINED3D_OK;
2770 if(oldIdxs != pIndexData) {
2771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 *ppIndexData = This->stateBlock->pIndexData;
2781 /* up ref count on ppindexdata */
2782 if (*ppIndexData) {
2783 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2784 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2785 }else{
2786 TRACE("(%p) No index data set\n", This);
2788 TRACE("Returning %p\n", *ppIndexData);
2790 return WINED3D_OK;
2793 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 TRACE("(%p)->(%d)\n", This, BaseIndex);
2798 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2799 TRACE("Application is setting the old value over, nothing to do\n");
2800 return WINED3D_OK;
2803 This->updateStateBlock->baseVertexIndex = BaseIndex;
2805 if (This->isRecordingState) {
2806 TRACE("Recording... not performing anything\n");
2807 return WINED3D_OK;
2809 /* The base vertex index affects the stream sources */
2810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2811 return WINED3D_OK;
2814 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 TRACE("(%p) : base_index %p\n", This, base_index);
2818 *base_index = This->stateBlock->baseVertexIndex;
2820 TRACE("Returning %u\n", *base_index);
2822 return WINED3D_OK;
2825 /*****
2826 * Get / Set Viewports
2827 *****/
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 TRACE("(%p)\n", This);
2832 This->updateStateBlock->changed.viewport = TRUE;
2833 This->updateStateBlock->set.viewport = TRUE;
2834 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2836 /* Handle recording of state blocks */
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2839 return WINED3D_OK;
2842 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2843 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2846 return WINED3D_OK;
2850 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 TRACE("(%p)\n", This);
2853 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2854 return WINED3D_OK;
2857 /*****
2858 * Get / Set Render States
2859 * TODO: Verify against dx9 definitions
2860 *****/
2861 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 DWORD oldValue = This->stateBlock->renderState[State];
2866 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2868 This->updateStateBlock->changed.renderState[State] = TRUE;
2869 This->updateStateBlock->set.renderState[State] = TRUE;
2870 This->updateStateBlock->renderState[State] = Value;
2872 /* Handle recording of state blocks */
2873 if (This->isRecordingState) {
2874 TRACE("Recording... not performing anything\n");
2875 return WINED3D_OK;
2878 /* Compared here and not before the assignment to allow proper stateblock recording */
2879 if(Value == oldValue) {
2880 TRACE("Application is setting the old value over, nothing to do\n");
2881 } else {
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2891 *pValue = This->stateBlock->renderState[State];
2892 return WINED3D_OK;
2895 /*****
2896 * Get / Set Sampler States
2897 * TODO: Verify against dx9 definitions
2898 *****/
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2905 * SetSampler is designed to allow for more than the standard up to 8 textures
2906 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2907 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2909 * http://developer.nvidia.com/object/General_FAQ.html#t6
2911 * There are two new settings for GForce
2912 * the sampler one:
2913 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2914 * and the texture one:
2915 * GL_MAX_TEXTURE_COORDS_ARB.
2916 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2917 ******************/
2919 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2920 debug_d3dsamplerstate(Type), Type, Value);
2921 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2922 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2923 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2925 /* Handle recording of state blocks */
2926 if (This->isRecordingState) {
2927 TRACE("Recording... not performing anything\n");
2928 return WINED3D_OK;
2931 if(oldValue == Value) {
2932 TRACE("Application is setting the old value over, nothing to do\n");
2933 return WINED3D_OK;
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2938 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 *Value = This->stateBlock->samplerState[Sampler][Type];
2944 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2946 return WINED3D_OK;
2949 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 This->updateStateBlock->set.scissorRect = TRUE;
2953 This->updateStateBlock->changed.scissorRect = TRUE;
2954 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2955 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2956 return WINED3D_OK;
2958 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2960 if(This->isRecordingState) {
2961 TRACE("Recording... not performing anything\n");
2962 return WINED3D_OK;
2965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2974 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2980 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2982 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2984 This->updateStateBlock->vertexDecl = pDecl;
2985 This->updateStateBlock->changed.vertexDecl = TRUE;
2986 This->updateStateBlock->set.vertexDecl = TRUE;
2988 if (This->isRecordingState) {
2989 TRACE("Recording... not performing anything\n");
2990 return WINED3D_OK;
2991 } else if(pDecl == oldDecl) {
2992 /* Checked after the assignment to allow proper stateblock recording */
2993 TRACE("Application is setting the old declaration over, nothing to do\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3006 *ppDecl = This->stateBlock->vertexDecl;
3007 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3015 This->updateStateBlock->vertexShader = pShader;
3016 This->updateStateBlock->changed.vertexShader = TRUE;
3017 This->updateStateBlock->set.vertexShader = TRUE;
3019 if (This->isRecordingState) {
3020 TRACE("Recording... not performing anything\n");
3021 return WINED3D_OK;
3022 } else if(oldShader == pShader) {
3023 /* Checked here to allow proper stateblock recording */
3024 TRACE("App is setting the old shader over, nothing to do\n");
3025 return WINED3D_OK;
3028 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 if (NULL == ppShader) {
3039 return WINED3DERR_INVALIDCALL;
3041 *ppShader = This->stateBlock->vertexShader;
3042 if( NULL != *ppShader)
3043 IWineD3DVertexShader_AddRef(*ppShader);
3045 TRACE("(%p) : returning %p\n", This, *ppShader);
3046 return WINED3D_OK;
3049 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3050 IWineD3DDevice *iface,
3051 UINT start,
3052 CONST BOOL *srcData,
3053 UINT count) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 int i, cnt = min(count, MAX_CONST_B - start);
3058 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3059 iface, srcData, start, count);
3061 if (srcData == NULL || cnt < 0)
3062 return WINED3DERR_INVALIDCALL;
3064 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3065 for (i = 0; i < cnt; i++)
3066 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3068 for (i = start; i < cnt + start; ++i) {
3069 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3070 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3075 return WINED3D_OK;
3078 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3079 IWineD3DDevice *iface,
3080 UINT start,
3081 BOOL *dstData,
3082 UINT count) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 int cnt = min(count, MAX_CONST_B - start);
3087 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3088 iface, dstData, start, count);
3090 if (dstData == NULL || cnt < 0)
3091 return WINED3DERR_INVALIDCALL;
3093 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3098 IWineD3DDevice *iface,
3099 UINT start,
3100 CONST int *srcData,
3101 UINT count) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 int i, cnt = min(count, MAX_CONST_I - start);
3106 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3107 iface, srcData, start, count);
3109 if (srcData == NULL || cnt < 0)
3110 return WINED3DERR_INVALIDCALL;
3112 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3113 for (i = 0; i < cnt; i++)
3114 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3115 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3117 for (i = start; i < cnt + start; ++i) {
3118 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3119 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3128 IWineD3DDevice *iface,
3129 UINT start,
3130 int *dstData,
3131 UINT count) {
3133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 int cnt = min(count, MAX_CONST_I - start);
3136 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3137 iface, dstData, start, count);
3139 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3140 return WINED3DERR_INVALIDCALL;
3142 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3143 return WINED3D_OK;
3146 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3147 IWineD3DDevice *iface,
3148 UINT start,
3149 CONST float *srcData,
3150 UINT count) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 int i;
3155 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3156 iface, srcData, start, count);
3158 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3159 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3160 return WINED3DERR_INVALIDCALL;
3162 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3163 if(TRACE_ON(d3d)) {
3164 for (i = 0; i < count; i++)
3165 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3166 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3169 for (i = start; i < count + start; ++i) {
3170 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3171 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3172 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3173 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3174 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3176 ptr->idx[ptr->count++] = i;
3177 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3179 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3184 return WINED3D_OK;
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3188 IWineD3DDevice *iface,
3189 UINT start,
3190 float *dstData,
3191 UINT count) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3196 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3197 iface, dstData, start, count);
3199 if (dstData == NULL || cnt < 0)
3200 return WINED3DERR_INVALIDCALL;
3202 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3203 return WINED3D_OK;
3206 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3207 DWORD i;
3208 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3213 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3214 DWORD i, tex;
3215 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3216 * it is never called.
3218 * Rules are:
3219 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3220 * that would be really messy and require shader recompilation
3221 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3222 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3223 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3224 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3226 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3227 if(This->oneToOneTexUnitMap) {
3228 TRACE("Not touching 1:1 map\n");
3229 return;
3231 TRACE("Restoring 1:1 texture unit mapping\n");
3232 /* Restore a 1:1 mapping */
3233 for(i = 0; i < MAX_SAMPLERS; i++) {
3234 if(This->texUnitMap[i] != i) {
3235 This->texUnitMap[i] = i;
3236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3237 markTextureStagesDirty(This, i);
3240 This->oneToOneTexUnitMap = TRUE;
3241 return;
3242 } else {
3243 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3244 * First, see if we can succeed at all
3246 tex = 0;
3247 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3248 if(This->stateBlock->textures[i] == NULL) tex++;
3251 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3252 FIXME("Too many bound textures to support the combiner settings\n");
3253 return;
3256 /* Now work out the mapping */
3257 tex = 0;
3258 This->oneToOneTexUnitMap = FALSE;
3259 WARN("Non 1:1 mapping UNTESTED!\n");
3260 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3261 /* Skip NULL textures */
3262 if (!This->stateBlock->textures[i]) {
3263 /* Map to -1, so the check below doesn't fail if a non-NULL
3264 * texture is set on this stage */
3265 TRACE("Mapping texture stage %d to -1\n", i);
3266 This->texUnitMap[i] = -1;
3268 continue;
3271 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3272 if(This->texUnitMap[i] != tex) {
3273 This->texUnitMap[i] = tex;
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3275 markTextureStagesDirty(This, i);
3278 ++tex;
3283 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3285 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3286 This->updateStateBlock->pixelShader = pShader;
3287 This->updateStateBlock->changed.pixelShader = TRUE;
3288 This->updateStateBlock->set.pixelShader = TRUE;
3290 /* Handle recording of state blocks */
3291 if (This->isRecordingState) {
3292 TRACE("Recording... not performing anything\n");
3295 if (This->isRecordingState) {
3296 TRACE("Recording... not performing anything\n");
3297 return WINED3D_OK;
3300 if(pShader == oldShader) {
3301 TRACE("App is setting the old pixel shader over, nothing to do\n");
3302 return WINED3D_OK;
3305 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3308 return WINED3D_OK;
3311 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3314 if (NULL == ppShader) {
3315 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3316 return WINED3DERR_INVALIDCALL;
3319 *ppShader = This->stateBlock->pixelShader;
3320 if (NULL != *ppShader) {
3321 IWineD3DPixelShader_AddRef(*ppShader);
3323 TRACE("(%p) : returning %p\n", This, *ppShader);
3324 return WINED3D_OK;
3327 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3328 IWineD3DDevice *iface,
3329 UINT start,
3330 CONST BOOL *srcData,
3331 UINT count) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 int i, cnt = min(count, MAX_CONST_B - start);
3336 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3337 iface, srcData, start, count);
3339 if (srcData == NULL || cnt < 0)
3340 return WINED3DERR_INVALIDCALL;
3342 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3343 for (i = 0; i < cnt; i++)
3344 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3346 for (i = start; i < cnt + start; ++i) {
3347 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3348 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3353 return WINED3D_OK;
3356 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3357 IWineD3DDevice *iface,
3358 UINT start,
3359 BOOL *dstData,
3360 UINT count) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 int cnt = min(count, MAX_CONST_B - start);
3365 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3366 iface, dstData, start, count);
3368 if (dstData == NULL || cnt < 0)
3369 return WINED3DERR_INVALIDCALL;
3371 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3372 return WINED3D_OK;
3375 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3376 IWineD3DDevice *iface,
3377 UINT start,
3378 CONST int *srcData,
3379 UINT count) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 int i, cnt = min(count, MAX_CONST_I - start);
3384 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3385 iface, srcData, start, count);
3387 if (srcData == NULL || cnt < 0)
3388 return WINED3DERR_INVALIDCALL;
3390 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3391 for (i = 0; i < cnt; i++)
3392 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3393 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3395 for (i = start; i < cnt + start; ++i) {
3396 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3397 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3402 return WINED3D_OK;
3405 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3406 IWineD3DDevice *iface,
3407 UINT start,
3408 int *dstData,
3409 UINT count) {
3411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3412 int cnt = min(count, MAX_CONST_I - start);
3414 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3415 iface, dstData, start, count);
3417 if (dstData == NULL || cnt < 0)
3418 return WINED3DERR_INVALIDCALL;
3420 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3421 return WINED3D_OK;
3424 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3425 IWineD3DDevice *iface,
3426 UINT start,
3427 CONST float *srcData,
3428 UINT count) {
3430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 int i;
3433 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3434 iface, srcData, start, count);
3436 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3437 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3438 return WINED3DERR_INVALIDCALL;
3440 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3441 if(TRACE_ON(d3d)) {
3442 for (i = 0; i < count; i++)
3443 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3444 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3447 for (i = start; i < count + start; ++i) {
3448 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3449 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3450 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3451 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3452 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3454 ptr->idx[ptr->count++] = i;
3455 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3457 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3462 return WINED3D_OK;
3465 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3466 IWineD3DDevice *iface,
3467 UINT start,
3468 float *dstData,
3469 UINT count) {
3471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3472 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3474 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3475 iface, dstData, start, count);
3477 if (dstData == NULL || cnt < 0)
3478 return WINED3DERR_INVALIDCALL;
3480 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3481 return WINED3D_OK;
3484 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3485 static HRESULT
3486 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3487 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3488 unsigned int i;
3489 DWORD DestFVF = dest->fvf;
3490 WINED3DVIEWPORT vp;
3491 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3492 BOOL doClip;
3493 int numTextures;
3495 if (lpStrideData->u.s.normal.lpData) {
3496 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3499 if (lpStrideData->u.s.position.lpData == NULL) {
3500 ERR("Source has no position mask\n");
3501 return WINED3DERR_INVALIDCALL;
3504 /* We might access VBOs from this code, so hold the lock */
3505 ENTER_GL();
3507 if (dest->resource.allocatedMemory == NULL) {
3508 /* This may happen if we do direct locking into a vbo. Unlikely,
3509 * but theoretically possible(ddraw processvertices test)
3511 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3512 if(!dest->resource.allocatedMemory) {
3513 LEAVE_GL();
3514 ERR("Out of memory\n");
3515 return E_OUTOFMEMORY;
3517 if(dest->vbo) {
3518 void *src;
3519 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3520 checkGLcall("glBindBufferARB");
3521 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3522 if(src) {
3523 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3525 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3526 checkGLcall("glUnmapBufferARB");
3530 /* Get a pointer into the destination vbo(create one if none exists) and
3531 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3533 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3534 CreateVBO(dest);
3537 if(dest->vbo) {
3538 unsigned char extrabytes = 0;
3539 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3540 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3541 * this may write 4 extra bytes beyond the area that should be written
3543 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3544 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3545 if(!dest_conv_addr) {
3546 ERR("Out of memory\n");
3547 /* Continue without storing converted vertices */
3549 dest_conv = dest_conv_addr;
3552 /* Should I clip?
3553 * a) WINED3DRS_CLIPPING is enabled
3554 * b) WINED3DVOP_CLIP is passed
3556 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3557 static BOOL warned = FALSE;
3559 * The clipping code is not quite correct. Some things need
3560 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3561 * so disable clipping for now.
3562 * (The graphics in Half-Life are broken, and my processvertices
3563 * test crashes with IDirect3DDevice3)
3564 doClip = TRUE;
3566 doClip = FALSE;
3567 if(!warned) {
3568 warned = TRUE;
3569 FIXME("Clipping is broken and disabled for now\n");
3571 } else doClip = FALSE;
3572 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3574 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3575 WINED3DTS_VIEW,
3576 &view_mat);
3577 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3578 WINED3DTS_PROJECTION,
3579 &proj_mat);
3580 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3581 WINED3DTS_WORLDMATRIX(0),
3582 &world_mat);
3584 TRACE("View mat:\n");
3585 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3586 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3587 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3588 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3590 TRACE("Proj mat:\n");
3591 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3592 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3593 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3594 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3596 TRACE("World mat:\n");
3597 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3598 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3599 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3600 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3602 /* Get the viewport */
3603 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3604 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3605 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3607 multiply_matrix(&mat,&view_mat,&world_mat);
3608 multiply_matrix(&mat,&proj_mat,&mat);
3610 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3612 for (i = 0; i < dwCount; i+= 1) {
3613 unsigned int tex_index;
3615 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3616 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3617 /* The position first */
3618 float *p =
3619 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3620 float x, y, z, rhw;
3621 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3623 /* Multiplication with world, view and projection matrix */
3624 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
3625 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
3626 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
3627 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
3629 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3631 /* WARNING: The following things are taken from d3d7 and were not yet checked
3632 * against d3d8 or d3d9!
3635 /* Clipping conditions: From
3636 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3638 * A vertex is clipped if it does not match the following requirements
3639 * -rhw < x <= rhw
3640 * -rhw < y <= rhw
3641 * 0 < z <= rhw
3642 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3644 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3645 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3649 if( !doClip ||
3650 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3651 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3652 ( rhw > eps ) ) ) {
3654 /* "Normal" viewport transformation (not clipped)
3655 * 1) The values are divided by rhw
3656 * 2) The y axis is negative, so multiply it with -1
3657 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3658 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3659 * 4) Multiply x with Width/2 and add Width/2
3660 * 5) The same for the height
3661 * 6) Add the viewpoint X and Y to the 2D coordinates and
3662 * The minimum Z value to z
3663 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3665 * Well, basically it's simply a linear transformation into viewport
3666 * coordinates
3669 x /= rhw;
3670 y /= rhw;
3671 z /= rhw;
3673 y *= -1;
3675 x *= vp.Width / 2;
3676 y *= vp.Height / 2;
3677 z *= vp.MaxZ - vp.MinZ;
3679 x += vp.Width / 2 + vp.X;
3680 y += vp.Height / 2 + vp.Y;
3681 z += vp.MinZ;
3683 rhw = 1 / rhw;
3684 } else {
3685 /* That vertex got clipped
3686 * Contrary to OpenGL it is not dropped completely, it just
3687 * undergoes a different calculation.
3689 TRACE("Vertex got clipped\n");
3690 x += rhw;
3691 y += rhw;
3693 x /= 2;
3694 y /= 2;
3696 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3697 * outside of the main vertex buffer memory. That needs some more
3698 * investigation...
3702 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3705 ( (float *) dest_ptr)[0] = x;
3706 ( (float *) dest_ptr)[1] = y;
3707 ( (float *) dest_ptr)[2] = z;
3708 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3710 dest_ptr += 3 * sizeof(float);
3712 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3713 dest_ptr += sizeof(float);
3716 if(dest_conv) {
3717 float w = 1 / rhw;
3718 ( (float *) dest_conv)[0] = x * w;
3719 ( (float *) dest_conv)[1] = y * w;
3720 ( (float *) dest_conv)[2] = z * w;
3721 ( (float *) dest_conv)[3] = w;
3723 dest_conv += 3 * sizeof(float);
3725 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3726 dest_conv += sizeof(float);
3730 if (DestFVF & WINED3DFVF_PSIZE) {
3731 dest_ptr += sizeof(DWORD);
3732 if(dest_conv) dest_conv += sizeof(DWORD);
3734 if (DestFVF & WINED3DFVF_NORMAL) {
3735 float *normal =
3736 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3737 /* AFAIK this should go into the lighting information */
3738 FIXME("Didn't expect the destination to have a normal\n");
3739 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3740 if(dest_conv) {
3741 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3745 if (DestFVF & WINED3DFVF_DIFFUSE) {
3746 DWORD *color_d =
3747 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3748 if(!color_d) {
3749 static BOOL warned = FALSE;
3751 if(!warned) {
3752 ERR("No diffuse color in source, but destination has one\n");
3753 warned = TRUE;
3756 *( (DWORD *) dest_ptr) = 0xffffffff;
3757 dest_ptr += sizeof(DWORD);
3759 if(dest_conv) {
3760 *( (DWORD *) dest_conv) = 0xffffffff;
3761 dest_conv += sizeof(DWORD);
3764 else {
3765 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3766 if(dest_conv) {
3767 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3768 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3769 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3770 dest_conv += sizeof(DWORD);
3775 if (DestFVF & WINED3DFVF_SPECULAR) {
3776 /* What's the color value in the feedback buffer? */
3777 DWORD *color_s =
3778 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3779 if(!color_s) {
3780 static BOOL warned = FALSE;
3782 if(!warned) {
3783 ERR("No specular color in source, but destination has one\n");
3784 warned = TRUE;
3787 *( (DWORD *) dest_ptr) = 0xFF000000;
3788 dest_ptr += sizeof(DWORD);
3790 if(dest_conv) {
3791 *( (DWORD *) dest_conv) = 0xFF000000;
3792 dest_conv += sizeof(DWORD);
3795 else {
3796 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3797 if(dest_conv) {
3798 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3799 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3800 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3801 dest_conv += sizeof(DWORD);
3806 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3807 float *tex_coord =
3808 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3809 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3810 if(!tex_coord) {
3811 ERR("No source texture, but destination requests one\n");
3812 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3813 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3815 else {
3816 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3817 if(dest_conv) {
3818 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3824 if(dest_conv) {
3825 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3826 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3827 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3828 dwCount * get_flexible_vertex_size(DestFVF),
3829 dest_conv_addr));
3830 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3831 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3834 LEAVE_GL();
3836 return WINED3D_OK;
3838 #undef copy_and_next
3840 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 WineDirect3DVertexStridedData strided;
3843 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3844 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3846 if(pVertexDecl) {
3847 ERR("Output vertex declaration not implemented yet\n");
3850 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3851 * and this call is quite performance critical, so don't call needlessly
3853 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3854 ENTER_GL();
3855 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3856 LEAVE_GL();
3859 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3860 * control the streamIsUP flag, thus restore it afterwards.
3862 This->stateBlock->streamIsUP = FALSE;
3863 memset(&strided, 0, sizeof(strided));
3864 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3865 This->stateBlock->streamIsUP = streamWasUP;
3867 if(vbo || SrcStartIndex) {
3868 unsigned int i;
3869 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3870 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3872 * Also get the start index in, but only loop over all elements if there's something to add at all.
3874 #define FIXSRC(type) \
3875 if(strided.u.s.type.VBO) { \
3876 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3877 strided.u.s.type.VBO = 0; \
3878 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3879 ENTER_GL(); \
3880 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3881 vb->vbo = 0; \
3882 LEAVE_GL(); \
3884 if(strided.u.s.type.lpData) { \
3885 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3887 FIXSRC(position);
3888 FIXSRC(blendWeights);
3889 FIXSRC(blendMatrixIndices);
3890 FIXSRC(normal);
3891 FIXSRC(pSize);
3892 FIXSRC(diffuse);
3893 FIXSRC(specular);
3894 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3895 FIXSRC(texCoords[i]);
3897 FIXSRC(position2);
3898 FIXSRC(normal2);
3899 FIXSRC(tangent);
3900 FIXSRC(binormal);
3901 FIXSRC(tessFactor);
3902 FIXSRC(fog);
3903 FIXSRC(depth);
3904 FIXSRC(sample);
3905 #undef FIXSRC
3908 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3911 /*****
3912 * Get / Set Texture Stage States
3913 * TODO: Verify against dx9 definitions
3914 *****/
3915 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3917 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3919 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3921 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3923 if (Stage >= MAX_TEXTURES) {
3924 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3925 return WINED3D_OK;
3928 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3929 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3930 This->updateStateBlock->textureState[Stage][Type] = Value;
3932 if (This->isRecordingState) {
3933 TRACE("Recording... not performing anything\n");
3934 return WINED3D_OK;
3937 /* Checked after the assignments to allow proper stateblock recording */
3938 if(oldValue == Value) {
3939 TRACE("App is setting the old value over, nothing to do\n");
3940 return WINED3D_OK;
3943 if(Stage > This->stateBlock->lowest_disabled_stage &&
3944 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3945 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3946 * Changes in other states are important on disabled stages too
3948 return WINED3D_OK;
3951 if(Type == WINED3DTSS_COLOROP) {
3952 int i;
3954 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3955 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3956 * they have to be disabled
3958 * The current stage is dirtified below.
3960 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3961 TRACE("Additionally dirtifying stage %d\n", i);
3962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3964 This->stateBlock->lowest_disabled_stage = Stage;
3965 TRACE("New lowest disabled: %d\n", Stage);
3966 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3967 /* Previously disabled stage enabled. Stages above it may need enabling
3968 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3969 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3971 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3974 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3975 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3976 break;
3978 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3981 This->stateBlock->lowest_disabled_stage = i;
3982 TRACE("New lowest disabled: %d\n", i);
3984 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3985 /* TODO: Built a stage -> texture unit mapping for register combiners */
3989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3991 return WINED3D_OK;
3994 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3996 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3997 *pValue = This->updateStateBlock->textureState[Stage][Type];
3998 return WINED3D_OK;
4001 /*****
4002 * Get / Set Texture
4003 *****/
4004 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4007 IWineD3DBaseTexture *oldTexture;
4009 oldTexture = This->updateStateBlock->textures[Stage];
4010 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4012 #if 0 /* TODO: check so vertex textures */
4013 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4014 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4015 return WINED3D_OK;
4017 #endif
4019 if(pTexture != NULL) {
4020 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4022 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4023 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4024 return WINED3DERR_INVALIDCALL;
4026 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4029 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4030 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4032 This->updateStateBlock->set.textures[Stage] = TRUE;
4033 This->updateStateBlock->changed.textures[Stage] = TRUE;
4034 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4035 This->updateStateBlock->textures[Stage] = pTexture;
4037 /* Handle recording of state blocks */
4038 if (This->isRecordingState) {
4039 TRACE("Recording... not performing anything\n");
4040 return WINED3D_OK;
4043 if(oldTexture == pTexture) {
4044 TRACE("App is setting the same texture again, nothing to do\n");
4045 return WINED3D_OK;
4048 /** NOTE: MSDN says that setTexture increases the reference count,
4049 * and the the application must set the texture back to null (or have a leaky application),
4050 * This means we should pass the refcount up to the parent
4051 *******************************/
4052 if (NULL != This->updateStateBlock->textures[Stage]) {
4053 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4054 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4056 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4057 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4058 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4059 * so the COLOROP and ALPHAOP have to be dirtified.
4061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4064 if(bindCount == 1) {
4065 new->baseTexture.sampler = Stage;
4067 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4071 if (NULL != oldTexture) {
4072 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4073 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4075 IWineD3DBaseTexture_Release(oldTexture);
4076 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4081 if(bindCount && old->baseTexture.sampler == Stage) {
4082 int i;
4083 /* Have to do a search for the other sampler(s) where the texture is bound to
4084 * Shouldn't happen as long as apps bind a texture only to one stage
4086 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4087 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4088 if(This->updateStateBlock->textures[i] == oldTexture) {
4089 old->baseTexture.sampler = i;
4090 break;
4096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4098 return WINED3D_OK;
4101 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4105 *ppTexture=This->stateBlock->textures[Stage];
4106 if (*ppTexture)
4107 IWineD3DBaseTexture_AddRef(*ppTexture);
4109 return WINED3D_OK;
4112 /*****
4113 * Get Back Buffer
4114 *****/
4115 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4116 IWineD3DSurface **ppBackBuffer) {
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 IWineD3DSwapChain *swapChain;
4119 HRESULT hr;
4121 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4123 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4124 if (hr == WINED3D_OK) {
4125 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4126 IWineD3DSwapChain_Release(swapChain);
4127 } else {
4128 *ppBackBuffer = NULL;
4130 return hr;
4133 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4135 WARN("(%p) : stub, calling idirect3d for now\n", This);
4136 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4139 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4141 IWineD3DSwapChain *swapChain;
4142 HRESULT hr;
4144 if(iSwapChain > 0) {
4145 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4146 if (hr == WINED3D_OK) {
4147 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4148 IWineD3DSwapChain_Release(swapChain);
4149 } else {
4150 FIXME("(%p) Error getting display mode\n", This);
4152 } else {
4153 /* Don't read the real display mode,
4154 but return the stored mode instead. X11 can't change the color
4155 depth, and some apps are pretty angry if they SetDisplayMode from
4156 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4158 Also don't relay to the swapchain because with ddraw it's possible
4159 that there isn't a swapchain at all */
4160 pMode->Width = This->ddraw_width;
4161 pMode->Height = This->ddraw_height;
4162 pMode->Format = This->ddraw_format;
4163 pMode->RefreshRate = 0;
4164 hr = WINED3D_OK;
4167 return hr;
4170 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 TRACE("(%p)->(%p)\n", This, hWnd);
4174 if(This->ddraw_fullscreen) {
4175 if(This->ddraw_window && This->ddraw_window != hWnd) {
4176 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4178 if(hWnd && This->ddraw_window != hWnd) {
4179 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4183 This->ddraw_window = hWnd;
4184 return WINED3D_OK;
4187 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4189 TRACE("(%p)->(%p)\n", This, hWnd);
4191 *hWnd = This->ddraw_window;
4192 return WINED3D_OK;
4195 /*****
4196 * Stateblock related functions
4197 *****/
4199 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4201 IWineD3DStateBlockImpl *object;
4202 HRESULT temp_result;
4203 int i;
4205 TRACE("(%p)\n", This);
4207 if (This->isRecordingState) {
4208 return WINED3DERR_INVALIDCALL;
4211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4212 if (NULL == object ) {
4213 FIXME("(%p)Error allocating memory for stateblock\n", This);
4214 return E_OUTOFMEMORY;
4216 TRACE("(%p) created object %p\n", This, object);
4217 object->wineD3DDevice= This;
4218 /** FIXME: object->parent = parent; **/
4219 object->parent = NULL;
4220 object->blockType = WINED3DSBT_ALL;
4221 object->ref = 1;
4222 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4224 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4225 list_init(&object->lightMap[i]);
4228 temp_result = allocate_shader_constants(object);
4229 if (WINED3D_OK != temp_result)
4230 return temp_result;
4232 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4233 This->updateStateBlock = object;
4234 This->isRecordingState = TRUE;
4236 TRACE("(%p) recording stateblock %p\n",This , object);
4237 return WINED3D_OK;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 if (!This->isRecordingState) {
4244 FIXME("(%p) not recording! returning error\n", This);
4245 *ppStateBlock = NULL;
4246 return WINED3DERR_INVALIDCALL;
4249 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4250 This->isRecordingState = FALSE;
4251 This->updateStateBlock = This->stateBlock;
4252 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4253 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4254 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4255 return WINED3D_OK;
4258 /*****
4259 * Scene related functions
4260 *****/
4261 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4262 /* At the moment we have no need for any functionality at the beginning
4263 of a scene */
4264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4265 TRACE("(%p)\n", This);
4267 if(This->inScene) {
4268 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4269 return WINED3DERR_INVALIDCALL;
4271 This->inScene = TRUE;
4272 return WINED3D_OK;
4275 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4277 TRACE("(%p)\n", This);
4279 if(!This->inScene) {
4280 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4281 return WINED3DERR_INVALIDCALL;
4284 ENTER_GL();
4285 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4286 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4288 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4289 glFlush();
4290 checkGLcall("glFlush");
4291 LEAVE_GL();
4293 This->inScene = FALSE;
4294 return WINED3D_OK;
4297 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4298 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4299 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4301 IWineD3DSwapChain *swapChain = NULL;
4302 int i;
4303 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4305 TRACE("(%p) Presenting the frame\n", This);
4307 for(i = 0 ; i < swapchains ; i ++) {
4309 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4310 TRACE("presentinng chain %d, %p\n", i, swapChain);
4311 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4312 IWineD3DSwapChain_Release(swapChain);
4315 return WINED3D_OK;
4318 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4319 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4323 GLbitfield glMask = 0;
4324 unsigned int i;
4325 CONST WINED3DRECT* curRect;
4327 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4328 Count, pRects, Flags, Color, Z, Stencil);
4330 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4331 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4332 /* TODO: What about depth stencil buffers without stencil bits? */
4333 return WINED3DERR_INVALIDCALL;
4336 ENTER_GL();
4337 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4338 * and not the last active one.
4341 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4342 apply_fbo_state(iface);
4345 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4347 glEnable(GL_SCISSOR_TEST);
4348 checkGLcall("glEnable GL_SCISSOR_TEST");
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4352 if (Count > 0 && pRects) {
4353 curRect = pRects;
4354 } else {
4355 curRect = NULL;
4358 /* Only set the values up once, as they are not changing */
4359 if (Flags & WINED3DCLEAR_STENCIL) {
4360 glClearStencil(Stencil);
4361 checkGLcall("glClearStencil");
4362 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4363 glStencilMask(0xFFFFFFFF);
4366 if (Flags & WINED3DCLEAR_ZBUFFER) {
4367 glDepthMask(GL_TRUE);
4368 glClearDepth(Z);
4369 checkGLcall("glClearDepth");
4370 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4374 if (Flags & WINED3DCLEAR_TARGET) {
4375 TRACE("Clearing screen with glClear to color %x\n", Color);
4376 glClearColor(D3DCOLOR_R(Color),
4377 D3DCOLOR_G(Color),
4378 D3DCOLOR_B(Color),
4379 D3DCOLOR_A(Color));
4380 checkGLcall("glClearColor");
4382 /* Clear ALL colors! */
4383 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4384 glMask = glMask | GL_COLOR_BUFFER_BIT;
4387 if (!curRect) {
4388 /* In drawable flag is set below */
4390 glScissor(This->stateBlock->viewport.X,
4391 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4392 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4393 This->stateBlock->viewport.Width,
4394 This->stateBlock->viewport.Height);
4395 checkGLcall("glScissor");
4396 glClear(glMask);
4397 checkGLcall("glClear");
4398 } else {
4399 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4400 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4402 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4403 curRect[0].x2 < target->currentDesc.Width ||
4404 curRect[0].y2 < target->currentDesc.Height) {
4405 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4406 blt_to_drawable(This, target);
4410 /* Now process each rect in turn */
4411 for (i = 0; i < Count; i++) {
4412 /* Note gl uses lower left, width/height */
4413 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4414 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4415 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4416 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4418 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4419 * The rectangle is not cleared, no error is returned, but further rectanlges are
4420 * still cleared if they are valid
4422 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4423 TRACE("Rectangle with negative dimensions, ignoring\n");
4424 continue;
4427 if(This->render_offscreen) {
4428 glScissor(curRect[i].x1, curRect[i].y1,
4429 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4430 } else {
4431 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4432 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4434 checkGLcall("glScissor");
4436 glClear(glMask);
4437 checkGLcall("glClear");
4441 /* Restore the old values (why..?) */
4442 if (Flags & WINED3DCLEAR_STENCIL) {
4443 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4445 if (Flags & WINED3DCLEAR_TARGET) {
4446 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4447 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4448 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4449 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4450 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4453 LEAVE_GL();
4455 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4456 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4458 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4459 target->Flags |= SFLAG_INTEXTURE;
4460 target->Flags &= ~SFLAG_INSYSMEM;
4461 } else {
4462 target->Flags |= SFLAG_INDRAWABLE;
4463 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4465 return WINED3D_OK;
4468 /*****
4469 * Drawing functions
4470 *****/
4471 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4472 UINT PrimitiveCount) {
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4477 debug_d3dprimitivetype(PrimitiveType),
4478 StartVertex, PrimitiveCount);
4480 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4481 if(This->stateBlock->streamIsUP) {
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4483 This->stateBlock->streamIsUP = FALSE;
4486 if(This->stateBlock->loadBaseVertexIndex != 0) {
4487 This->stateBlock->loadBaseVertexIndex = 0;
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4490 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4491 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4492 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4493 return WINED3D_OK;
4496 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4497 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4498 WINED3DPRIMITIVETYPE PrimitiveType,
4499 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502 UINT idxStride = 2;
4503 IWineD3DIndexBuffer *pIB;
4504 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4505 GLuint vbo;
4507 pIB = This->stateBlock->pIndexData;
4508 if (!pIB) {
4509 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4510 * without an index buffer set. (The first time at least...)
4511 * D3D8 simply dies, but I doubt it can do much harm to return
4512 * D3DERR_INVALIDCALL there as well. */
4513 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4514 return WINED3DERR_INVALIDCALL;
4517 if(This->stateBlock->streamIsUP) {
4518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4519 This->stateBlock->streamIsUP = FALSE;
4521 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4523 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4524 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4525 minIndex, NumVertices, startIndex, primCount);
4527 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4528 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4529 idxStride = 2;
4530 } else {
4531 idxStride = 4;
4534 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4535 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4539 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4540 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4542 return WINED3D_OK;
4545 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4546 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4547 UINT VertexStreamZeroStride) {
4548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4550 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4551 debug_d3dprimitivetype(PrimitiveType),
4552 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4554 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4555 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4556 This->stateBlock->streamOffset[0] = 0;
4557 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4558 This->stateBlock->streamIsUP = TRUE;
4559 This->stateBlock->loadBaseVertexIndex = 0;
4561 /* TODO: Only mark dirty if drawing from a different UP address */
4562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4564 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4565 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4567 /* MSDN specifies stream zero settings must be set to NULL */
4568 This->stateBlock->streamStride[0] = 0;
4569 This->stateBlock->streamSource[0] = NULL;
4571 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4572 * the new stream sources or use UP drawing again
4574 return WINED3D_OK;
4577 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4578 UINT MinVertexIndex, UINT NumVertices,
4579 UINT PrimitiveCount, CONST void* pIndexData,
4580 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4581 UINT VertexStreamZeroStride) {
4582 int idxStride;
4583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4586 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4587 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4588 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4590 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4591 idxStride = 2;
4592 } else {
4593 idxStride = 4;
4596 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4597 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4598 This->stateBlock->streamIsUP = TRUE;
4599 This->stateBlock->streamOffset[0] = 0;
4600 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4602 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4603 This->stateBlock->baseVertexIndex = 0;
4604 This->stateBlock->loadBaseVertexIndex = 0;
4605 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4609 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4611 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4612 This->stateBlock->streamSource[0] = NULL;
4613 This->stateBlock->streamStride[0] = 0;
4614 This->stateBlock->pIndexData = NULL;
4615 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4616 * SetStreamSource to specify a vertex buffer
4619 return WINED3D_OK;
4622 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4625 /* Mark the state dirty until we have nicer tracking
4626 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4627 * that value.
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4631 This->stateBlock->baseVertexIndex = 0;
4632 This->up_strided = DrawPrimStrideData;
4633 This->stateBlock->streamIsUP = TRUE;
4634 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4635 This->up_strided = NULL;
4636 return WINED3D_OK;
4638 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4639 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 HRESULT hr = WINED3D_OK;
4642 WINED3DRESOURCETYPE sourceType;
4643 WINED3DRESOURCETYPE destinationType;
4644 int i ,levels;
4646 /* TODO: think about moving the code into IWineD3DBaseTexture */
4648 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4650 /* verify that the source and destination textures aren't NULL */
4651 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4652 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4653 This, pSourceTexture, pDestinationTexture);
4654 hr = WINED3DERR_INVALIDCALL;
4657 if (pSourceTexture == pDestinationTexture) {
4658 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4659 This, pSourceTexture, pDestinationTexture);
4660 hr = WINED3DERR_INVALIDCALL;
4662 /* Verify that the source and destination textures are the same type */
4663 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4664 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4666 if (sourceType != destinationType) {
4667 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4668 This);
4669 hr = WINED3DERR_INVALIDCALL;
4672 /* check that both textures have the identical numbers of levels */
4673 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4674 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4675 hr = WINED3DERR_INVALIDCALL;
4678 if (WINED3D_OK == hr) {
4680 /* Make sure that the destination texture is loaded */
4681 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4683 /* Update every surface level of the texture */
4684 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4686 switch (sourceType) {
4687 case WINED3DRTYPE_TEXTURE:
4689 IWineD3DSurface *srcSurface;
4690 IWineD3DSurface *destSurface;
4692 for (i = 0 ; i < levels ; ++i) {
4693 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4694 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4695 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4696 IWineD3DSurface_Release(srcSurface);
4697 IWineD3DSurface_Release(destSurface);
4698 if (WINED3D_OK != hr) {
4699 WARN("(%p) : Call to update surface failed\n", This);
4700 return hr;
4704 break;
4705 case WINED3DRTYPE_CUBETEXTURE:
4707 IWineD3DSurface *srcSurface;
4708 IWineD3DSurface *destSurface;
4709 WINED3DCUBEMAP_FACES faceType;
4711 for (i = 0 ; i < levels ; ++i) {
4712 /* Update each cube face */
4713 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4714 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4715 if (WINED3D_OK != hr) {
4716 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4717 } else {
4718 TRACE("Got srcSurface %p\n", srcSurface);
4720 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4721 if (WINED3D_OK != hr) {
4722 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4723 } else {
4724 TRACE("Got desrSurface %p\n", destSurface);
4726 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4727 IWineD3DSurface_Release(srcSurface);
4728 IWineD3DSurface_Release(destSurface);
4729 if (WINED3D_OK != hr) {
4730 WARN("(%p) : Call to update surface failed\n", This);
4731 return hr;
4736 break;
4737 #if 0 /* TODO: Add support for volume textures */
4738 case WINED3DRTYPE_VOLUMETEXTURE:
4740 IWineD3DVolume srcVolume = NULL;
4741 IWineD3DSurface destVolume = NULL;
4743 for (i = 0 ; i < levels ; ++i) {
4744 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4745 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4746 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4747 IWineD3DVolume_Release(srcSurface);
4748 IWineD3DVolume_Release(destSurface);
4749 if (WINED3D_OK != hr) {
4750 WARN("(%p) : Call to update volume failed\n", This);
4751 return hr;
4755 break;
4756 #endif
4757 default:
4758 FIXME("(%p) : Unsupported source and destination type\n", This);
4759 hr = WINED3DERR_INVALIDCALL;
4763 return hr;
4766 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4767 IWineD3DSwapChain *swapChain;
4768 HRESULT hr;
4769 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4770 if(hr == WINED3D_OK) {
4771 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4772 IWineD3DSwapChain_Release(swapChain);
4774 return hr;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 /* return a sensible default */
4780 *pNumPasses = 1;
4781 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4782 FIXME("(%p) : stub\n", This);
4783 return WINED3D_OK;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 int j;
4789 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4790 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4791 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4792 return WINED3DERR_INVALIDCALL;
4794 for (j = 0; j < 256; ++j) {
4795 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4796 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4797 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4798 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4800 TRACE("(%p) : returning\n", This);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 int j;
4807 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4808 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4809 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4810 return WINED3DERR_INVALIDCALL;
4812 for (j = 0; j < 256; ++j) {
4813 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4814 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4815 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4816 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4818 TRACE("(%p) : returning\n", This);
4819 return WINED3D_OK;
4822 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4824 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4825 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4826 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4827 return WINED3DERR_INVALIDCALL;
4829 /*TODO: stateblocks */
4830 This->currentPalette = PaletteNumber;
4831 TRACE("(%p) : returning\n", This);
4832 return WINED3D_OK;
4835 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4837 if (PaletteNumber == NULL) {
4838 WARN("(%p) : returning Invalid Call\n", This);
4839 return WINED3DERR_INVALIDCALL;
4841 /*TODO: stateblocks */
4842 *PaletteNumber = This->currentPalette;
4843 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4849 static BOOL showFixmes = TRUE;
4850 if (showFixmes) {
4851 FIXME("(%p) : stub\n", This);
4852 showFixmes = FALSE;
4855 This->softwareVertexProcessing = bSoftware;
4856 return WINED3D_OK;
4860 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 static BOOL showFixmes = TRUE;
4863 if (showFixmes) {
4864 FIXME("(%p) : stub\n", This);
4865 showFixmes = FALSE;
4867 return This->softwareVertexProcessing;
4871 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 IWineD3DSwapChain *swapChain;
4874 HRESULT hr;
4876 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4878 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4879 if(hr == WINED3D_OK){
4880 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4881 IWineD3DSwapChain_Release(swapChain);
4882 }else{
4883 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4885 return hr;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 static BOOL showfixmes = TRUE;
4892 if(nSegments != 0.0f) {
4893 if( showfixmes) {
4894 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4895 showfixmes = FALSE;
4898 return WINED3D_OK;
4901 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 static BOOL showfixmes = TRUE;
4904 if( showfixmes) {
4905 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4906 showfixmes = FALSE;
4908 return 0.0f;
4911 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4913 /** TODO: remove casts to IWineD3DSurfaceImpl
4914 * NOTE: move code to surface to accomplish this
4915 ****************************************/
4916 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4917 int srcWidth, srcHeight;
4918 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4919 WINED3DFORMAT destFormat, srcFormat;
4920 UINT destSize;
4921 int srcLeft, destLeft, destTop;
4922 WINED3DPOOL srcPool, destPool;
4923 int offset = 0;
4924 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4925 glDescriptor *glDescription = NULL;
4927 WINED3DSURFACE_DESC winedesc;
4929 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4930 memset(&winedesc, 0, sizeof(winedesc));
4931 winedesc.Width = &srcSurfaceWidth;
4932 winedesc.Height = &srcSurfaceHeight;
4933 winedesc.Pool = &srcPool;
4934 winedesc.Format = &srcFormat;
4936 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4938 winedesc.Width = &destSurfaceWidth;
4939 winedesc.Height = &destSurfaceHeight;
4940 winedesc.Pool = &destPool;
4941 winedesc.Format = &destFormat;
4942 winedesc.Size = &destSize;
4944 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4946 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4947 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4948 return WINED3DERR_INVALIDCALL;
4951 if (destFormat == WINED3DFMT_UNKNOWN) {
4952 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4953 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4955 /* Get the update surface description */
4956 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4959 ENTER_GL();
4961 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4963 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4964 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4965 checkGLcall("glActiveTextureARB");
4968 /* Make sure the surface is loaded and up to date */
4969 IWineD3DSurface_PreLoad(pDestinationSurface);
4971 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4973 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4974 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4975 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4976 srcLeft = pSourceRect ? pSourceRect->left : 0;
4977 destLeft = pDestPoint ? pDestPoint->x : 0;
4978 destTop = pDestPoint ? pDestPoint->y : 0;
4981 /* This function doesn't support compressed textures
4982 the pitch is just bytesPerPixel * width */
4983 if(srcWidth != srcSurfaceWidth || srcLeft ){
4984 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4985 offset += srcLeft * pSrcSurface->bytesPerPixel;
4986 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4988 /* TODO DXT formats */
4990 if(pSourceRect != NULL && pSourceRect->top != 0){
4991 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4993 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4994 ,This
4995 ,glDescription->level
4996 ,destLeft
4997 ,destTop
4998 ,srcWidth
4999 ,srcHeight
5000 ,glDescription->glFormat
5001 ,glDescription->glType
5002 ,IWineD3DSurface_GetData(pSourceSurface)
5005 /* Sanity check */
5006 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5008 /* need to lock the surface to get the data */
5009 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5012 /* TODO: Cube and volume support */
5013 if(rowoffset != 0){
5014 /* not a whole row so we have to do it a line at a time */
5015 int j;
5017 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5018 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5020 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5022 glTexSubImage2D(glDescription->target
5023 ,glDescription->level
5024 ,destLeft
5026 ,srcWidth
5028 ,glDescription->glFormat
5029 ,glDescription->glType
5030 ,data /* could be quicker using */
5032 data += rowoffset;
5035 } else { /* Full width, so just write out the whole texture */
5037 if (WINED3DFMT_DXT1 == destFormat ||
5038 WINED3DFMT_DXT2 == destFormat ||
5039 WINED3DFMT_DXT3 == destFormat ||
5040 WINED3DFMT_DXT4 == destFormat ||
5041 WINED3DFMT_DXT5 == destFormat) {
5042 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5043 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5044 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5045 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5046 } if (destFormat != srcFormat) {
5047 FIXME("Updating mixed format compressed texture is not curretly support\n");
5048 } else {
5049 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5050 glDescription->level,
5051 glDescription->glFormatInternal,
5052 srcWidth,
5053 srcHeight,
5055 destSize,
5056 IWineD3DSurface_GetData(pSourceSurface));
5058 } else {
5059 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5063 } else {
5064 glTexSubImage2D(glDescription->target
5065 ,glDescription->level
5066 ,destLeft
5067 ,destTop
5068 ,srcWidth
5069 ,srcHeight
5070 ,glDescription->glFormat
5071 ,glDescription->glType
5072 ,IWineD3DSurface_GetData(pSourceSurface)
5076 checkGLcall("glTexSubImage2D");
5078 LEAVE_GL();
5080 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5081 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5084 return WINED3D_OK;
5087 /* Implementation details at http://developer.nvidia.com/attach/6494
5089 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5090 hmm.. no longer supported use
5091 OpenGL evaluators or tessellate surfaces within your application.
5094 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5095 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5098 FIXME("(%p) : Stub\n", This);
5099 return WINED3D_OK;
5103 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5104 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5107 FIXME("(%p) : Stub\n", This);
5108 return WINED3D_OK;
5111 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5113 TRACE("(%p) Handle(%d)\n", This, Handle);
5114 FIXME("(%p) : Stub\n", This);
5115 return WINED3D_OK;
5118 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5119 HRESULT hr;
5120 IWineD3DSwapChain *swapchain;
5122 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5123 if (SUCCEEDED(hr)) {
5124 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5125 return swapchain;
5128 return NULL;
5131 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5134 if (!*fbo) {
5135 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5136 checkGLcall("glGenFramebuffersEXT()");
5138 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5139 checkGLcall("glBindFramebuffer()");
5142 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5143 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5144 IWineD3DBaseTextureImpl *texture_impl;
5145 GLenum texttarget, target;
5146 GLint old_binding;
5148 texttarget = surface_impl->glDescription.target;
5149 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5150 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5152 IWineD3DSurface_PreLoad(surface);
5154 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5155 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5156 glBindTexture(target, old_binding);
5158 /* Update base texture states array */
5159 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5160 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5161 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5162 if (texture_impl->baseTexture.bindCount) {
5163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5166 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5169 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5171 checkGLcall("attach_surface_fbo");
5174 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5176 IWineD3DSwapChain *swapchain;
5178 swapchain = get_swapchain(surface);
5179 if (swapchain) {
5180 GLenum buffer;
5182 TRACE("Surface %p is onscreen\n", surface);
5184 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5185 buffer = surface_get_gl_buffer(surface, swapchain);
5186 glDrawBuffer(buffer);
5187 checkGLcall("glDrawBuffer()");
5188 } else {
5189 TRACE("Surface %p is offscreen\n", surface);
5190 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5191 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5194 if (rect) {
5195 glEnable(GL_SCISSOR_TEST);
5196 if(!swapchain) {
5197 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5198 } else {
5199 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5200 rect->x2 - rect->x1, rect->y2 - rect->y1);
5202 checkGLcall("glScissor");
5203 } else {
5204 glDisable(GL_SCISSOR_TEST);
5206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5208 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5211 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5212 glClear(GL_COLOR_BUFFER_BIT);
5213 checkGLcall("glClear");
5215 if (This->render_offscreen) {
5216 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5217 } else {
5218 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5219 checkGLcall("glBindFramebuffer()");
5222 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5223 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5224 glDrawBuffer(GL_BACK);
5225 checkGLcall("glDrawBuffer()");
5229 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5231 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5232 WINEDDBLTFX BltFx;
5233 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5235 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5236 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5237 return WINED3DERR_INVALIDCALL;
5240 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5241 color_fill_fbo(iface, pSurface, pRect, color);
5242 return WINED3D_OK;
5243 } else {
5244 /* Just forward this to the DirectDraw blitting engine */
5245 memset(&BltFx, 0, sizeof(BltFx));
5246 BltFx.dwSize = sizeof(BltFx);
5247 BltFx.u5.dwFillColor = color;
5248 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5252 /* rendertarget and deptth stencil functions */
5253 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5256 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5257 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5258 return WINED3DERR_INVALIDCALL;
5261 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5262 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5263 /* Note inc ref on returned surface */
5264 if(*ppRenderTarget != NULL)
5265 IWineD3DSurface_AddRef(*ppRenderTarget);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5272 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5273 IWineD3DSwapChainImpl *Swapchain;
5274 HRESULT hr;
5276 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5278 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5279 if(hr != WINED3D_OK) {
5280 ERR("Can't get the swapchain\n");
5281 return hr;
5284 /* Make sure to release the swapchain */
5285 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5287 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5288 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5289 return WINED3DERR_INVALIDCALL;
5291 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5292 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5293 return WINED3DERR_INVALIDCALL;
5296 if(Swapchain->frontBuffer != Front) {
5297 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5299 if(Swapchain->frontBuffer)
5300 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5301 Swapchain->frontBuffer = Front;
5303 if(Swapchain->frontBuffer) {
5304 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5308 if(Back && !Swapchain->backBuffer) {
5309 /* We need memory for the back buffer array - only one back buffer this way */
5310 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5311 if(!Swapchain->backBuffer) {
5312 ERR("Out of memory\n");
5313 return E_OUTOFMEMORY;
5317 if(Swapchain->backBuffer[0] != Back) {
5318 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5320 /* What to do about the context here in the case of multithreading? Not sure.
5321 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5323 ENTER_GL();
5324 if(!Swapchain->backBuffer[0]) {
5325 /* GL was told to draw to the front buffer at creation,
5326 * undo that
5328 glDrawBuffer(GL_BACK);
5329 checkGLcall("glDrawBuffer(GL_BACK)");
5330 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5331 Swapchain->presentParms.BackBufferCount = 1;
5332 } else if (!Back) {
5333 /* That makes problems - disable for now */
5334 /* glDrawBuffer(GL_FRONT); */
5335 checkGLcall("glDrawBuffer(GL_FRONT)");
5336 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5337 Swapchain->presentParms.BackBufferCount = 0;
5339 LEAVE_GL();
5341 if(Swapchain->backBuffer[0])
5342 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5343 Swapchain->backBuffer[0] = Back;
5345 if(Swapchain->backBuffer[0]) {
5346 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5347 } else {
5348 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5353 return WINED3D_OK;
5356 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5358 *ppZStencilSurface = This->depthStencilBuffer;
5359 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5361 if(*ppZStencilSurface != NULL) {
5362 /* Note inc ref on returned surface */
5363 IWineD3DSurface_AddRef(*ppZStencilSurface);
5365 return WINED3D_OK;
5368 /* TODO: Handle stencil attachments */
5369 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5371 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5373 TRACE("Set depth stencil to %p\n", depth_stencil);
5375 if (depth_stencil_impl) {
5376 if (depth_stencil_impl->current_renderbuffer) {
5377 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5378 checkGLcall("glFramebufferRenderbufferEXT()");
5379 } else {
5380 IWineD3DBaseTextureImpl *texture_impl;
5381 GLenum texttarget, target;
5382 GLint old_binding = 0;
5384 texttarget = depth_stencil_impl->glDescription.target;
5385 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5386 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5388 IWineD3DSurface_PreLoad(depth_stencil);
5390 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5391 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5392 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5393 glBindTexture(target, old_binding);
5395 /* Update base texture states array */
5396 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5397 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5398 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5399 if (texture_impl->baseTexture.bindCount) {
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5403 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5406 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5407 checkGLcall("glFramebufferTexture2DEXT()");
5409 } else {
5410 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5411 checkGLcall("glFramebufferTexture2DEXT()");
5415 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5417 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5419 TRACE("Set render target %u to %p\n", idx, render_target);
5421 if (rtimpl) {
5422 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5423 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5424 } else {
5425 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5426 checkGLcall("glFramebufferTexture2DEXT()");
5428 This->draw_buffers[idx] = GL_NONE;
5432 static void check_fbo_status(IWineD3DDevice *iface) {
5433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5434 GLenum status;
5436 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5437 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5438 TRACE("FBO complete\n");
5439 } else {
5440 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5442 /* Dump the FBO attachments */
5443 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5444 IWineD3DSurfaceImpl *attachment;
5445 int i;
5447 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5448 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5449 if (attachment) {
5450 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5451 attachment->pow2Width, attachment->pow2Height);
5454 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5455 if (attachment) {
5456 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5457 attachment->pow2Width, attachment->pow2Height);
5463 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5465 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5466 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5468 if (!ds_impl) return FALSE;
5470 if (ds_impl->current_renderbuffer) {
5471 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5472 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5475 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5476 rt_impl->pow2Height != ds_impl->pow2Height);
5479 void apply_fbo_state(IWineD3DDevice *iface) {
5480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5481 unsigned int i;
5483 if (This->render_offscreen) {
5484 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5486 /* Apply render targets */
5487 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5488 IWineD3DSurface *render_target = This->render_targets[i];
5489 if (This->fbo_color_attachments[i] != render_target) {
5490 set_render_target_fbo(iface, i, render_target);
5491 This->fbo_color_attachments[i] = render_target;
5495 /* Apply depth targets */
5496 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5497 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5498 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5500 if (This->stencilBufferTarget) {
5501 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5503 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5504 This->fbo_depth_attachment = This->stencilBufferTarget;
5507 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5508 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5509 checkGLcall("glDrawBuffers()");
5510 } else {
5511 glDrawBuffer(This->draw_buffers[0]);
5512 checkGLcall("glDrawBuffer()");
5514 } else {
5515 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5518 check_fbo_status(iface);
5521 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5522 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5524 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5525 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5526 GLenum gl_filter;
5528 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5529 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5530 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5531 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5533 switch (filter) {
5534 case WINED3DTEXF_LINEAR:
5535 gl_filter = GL_LINEAR;
5536 break;
5538 default:
5539 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5540 case WINED3DTEXF_NONE:
5541 case WINED3DTEXF_POINT:
5542 gl_filter = GL_NEAREST;
5543 break;
5546 /* Attach src surface to src fbo */
5547 src_swapchain = get_swapchain(src_surface);
5548 ENTER_GL();
5549 if (src_swapchain) {
5550 GLenum buffer;
5552 TRACE("Source surface %p is onscreen\n", src_surface);
5553 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5555 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5556 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5557 glReadBuffer(buffer);
5558 checkGLcall("glReadBuffer()");
5560 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5561 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5562 } else {
5563 TRACE("Source surface %p is offscreen\n", src_surface);
5564 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5565 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5566 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5567 checkGLcall("glReadBuffer()");
5570 /* Attach dst surface to dst fbo */
5571 dst_swapchain = get_swapchain(dst_surface);
5572 if (dst_swapchain) {
5573 GLenum buffer;
5575 TRACE("Destination surface %p is onscreen\n", dst_surface);
5576 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5578 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5579 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5580 glDrawBuffer(buffer);
5581 checkGLcall("glDrawBuffer()");
5583 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5584 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5585 } else {
5586 TRACE("Destination surface %p is offscreen\n", dst_surface);
5588 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5589 if(!src_swapchain) {
5590 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5593 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5594 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5595 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5596 checkGLcall("glDrawBuffer()");
5598 glDisable(GL_SCISSOR_TEST);
5599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5601 if (flip) {
5602 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5603 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5604 checkGLcall("glBlitFramebuffer()");
5605 } else {
5606 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5607 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5608 checkGLcall("glBlitFramebuffer()");
5611 if (This->render_offscreen) {
5612 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5613 } else {
5614 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5615 checkGLcall("glBindFramebuffer()");
5618 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5619 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5620 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5621 glDrawBuffer(GL_BACK);
5622 checkGLcall("glDrawBuffer()");
5624 LEAVE_GL();
5627 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 WINED3DVIEWPORT viewport;
5631 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5633 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5634 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5635 return WINED3DERR_INVALIDCALL;
5638 /* MSDN says that null disables the render target
5639 but a device must always be associated with a render target
5640 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5642 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5643 for more details
5645 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5646 FIXME("Trying to set render target 0 to NULL\n");
5647 return WINED3DERR_INVALIDCALL;
5649 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5650 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5651 return WINED3DERR_INVALIDCALL;
5654 /* If we are trying to set what we already have, don't bother */
5655 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5656 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5657 return WINED3D_OK;
5659 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5660 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5661 This->render_targets[RenderTargetIndex] = pRenderTarget;
5663 /* Render target 0 is special */
5664 if(RenderTargetIndex == 0) {
5665 /* Finally, reset the viewport as the MSDN states. */
5666 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5667 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5668 viewport.X = 0;
5669 viewport.Y = 0;
5670 viewport.MaxZ = 1.0f;
5671 viewport.MinZ = 0.0f;
5672 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5673 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5674 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5678 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5679 * ctx properly.
5680 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5681 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5683 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5685 return WINED3D_OK;
5688 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 HRESULT hr = WINED3D_OK;
5691 IWineD3DSurface *tmp;
5693 TRACE("(%p) Swapping z-buffer\n",This);
5695 if (pNewZStencil == This->stencilBufferTarget) {
5696 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5697 } else {
5698 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5699 * depending on the renter target implementation being used.
5700 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5701 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5702 * stencil buffer and incure an extra memory overhead
5703 ******************************************************/
5705 tmp = This->stencilBufferTarget;
5706 This->stencilBufferTarget = pNewZStencil;
5707 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5708 /* should we be calling the parent or the wined3d surface? */
5709 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5710 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5711 hr = WINED3D_OK;
5713 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5714 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5721 return hr;
5724 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5725 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5727 /* TODO: the use of Impl is deprecated. */
5728 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5729 WINED3DLOCKED_RECT lockedRect;
5731 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5733 /* some basic validation checks */
5734 if(This->cursorTexture) {
5735 ENTER_GL();
5736 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5737 glDeleteTextures(1, &This->cursorTexture);
5738 LEAVE_GL();
5739 This->cursorTexture = 0;
5742 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5743 This->haveHardwareCursor = TRUE;
5744 else
5745 This->haveHardwareCursor = FALSE;
5747 if(pCursorBitmap) {
5748 WINED3DLOCKED_RECT rect;
5750 /* MSDN: Cursor must be A8R8G8B8 */
5751 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5752 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5753 return WINED3DERR_INVALIDCALL;
5756 /* MSDN: Cursor must be smaller than the display mode */
5757 if(pSur->currentDesc.Width > This->ddraw_width ||
5758 pSur->currentDesc.Height > This->ddraw_height) {
5759 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5760 return WINED3DERR_INVALIDCALL;
5763 if (!This->haveHardwareCursor) {
5764 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5766 /* Do not store the surface's pointer because the application may
5767 * release it after setting the cursor image. Windows doesn't
5768 * addref the set surface, so we can't do this either without
5769 * creating circular refcount dependencies. Copy out the gl texture
5770 * instead.
5772 This->cursorWidth = pSur->currentDesc.Width;
5773 This->cursorHeight = pSur->currentDesc.Height;
5774 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5776 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5777 char *mem, *bits = (char *)rect.pBits;
5778 GLint intfmt = tableEntry->glInternal;
5779 GLint format = tableEntry->glFormat;
5780 GLint type = tableEntry->glType;
5781 INT height = This->cursorHeight;
5782 INT width = This->cursorWidth;
5783 INT bpp = tableEntry->bpp;
5784 INT i;
5786 /* Reformat the texture memory (pitch and width can be
5787 * different) */
5788 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5789 for(i = 0; i < height; i++)
5790 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5791 IWineD3DSurface_UnlockRect(pCursorBitmap);
5792 ENTER_GL();
5794 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5795 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5796 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5799 /* Make sure that a proper texture unit is selected */
5800 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5801 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5802 checkGLcall("glActiveTextureARB");
5804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5805 /* Create a new cursor texture */
5806 glGenTextures(1, &This->cursorTexture);
5807 checkGLcall("glGenTextures");
5808 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5809 checkGLcall("glBindTexture");
5810 /* Copy the bitmap memory into the cursor texture */
5811 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5812 HeapFree(GetProcessHeap(), 0, mem);
5813 checkGLcall("glTexImage2D");
5815 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5816 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5817 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5820 LEAVE_GL();
5822 else
5824 FIXME("A cursor texture was not returned.\n");
5825 This->cursorTexture = 0;
5828 else
5830 /* Draw a hardware cursor */
5831 ICONINFO cursorInfo;
5832 HCURSOR cursor;
5833 /* Create and clear maskBits because it is not needed for
5834 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5835 * chunks. */
5836 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5837 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5838 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5839 WINED3DLOCK_NO_DIRTY_UPDATE |
5840 WINED3DLOCK_READONLY
5842 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5843 pSur->currentDesc.Height);
5845 cursorInfo.fIcon = FALSE;
5846 cursorInfo.xHotspot = XHotSpot;
5847 cursorInfo.yHotspot = YHotSpot;
5848 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5849 pSur->currentDesc.Height, 1,
5850 1, &maskBits);
5851 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5852 pSur->currentDesc.Height, 1,
5853 32, lockedRect.pBits);
5854 IWineD3DSurface_UnlockRect(pCursorBitmap);
5855 /* Create our cursor and clean up. */
5856 cursor = CreateIconIndirect(&cursorInfo);
5857 SetCursor(cursor);
5858 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5859 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5860 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5861 This->hardwareCursor = cursor;
5862 HeapFree(GetProcessHeap(), 0, maskBits);
5866 This->xHotSpot = XHotSpot;
5867 This->yHotSpot = YHotSpot;
5868 return WINED3D_OK;
5871 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5873 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5875 This->xScreenSpace = XScreenSpace;
5876 This->yScreenSpace = YScreenSpace;
5878 return;
5882 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5884 BOOL oldVisible = This->bCursorVisible;
5885 POINT pt;
5887 TRACE("(%p) : visible(%d)\n", This, bShow);
5890 * When ShowCursor is first called it should make the cursor appear at the OS's last
5891 * known cursor position. Because of this, some applications just repetitively call
5892 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5894 GetCursorPos(&pt);
5895 This->xScreenSpace = pt.x;
5896 This->yScreenSpace = pt.y;
5898 if (This->haveHardwareCursor) {
5899 This->bCursorVisible = bShow;
5900 if (bShow)
5901 SetCursor(This->hardwareCursor);
5902 else
5903 SetCursor(NULL);
5905 else
5907 if (This->cursorTexture)
5908 This->bCursorVisible = bShow;
5911 return oldVisible;
5914 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5916 TRACE("(%p) : state (%u)\n", This, This->state);
5917 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5918 switch (This->state) {
5919 case WINED3D_OK:
5920 return WINED3D_OK;
5921 case WINED3DERR_DEVICELOST:
5923 ResourceList *resourceList = This->resources;
5924 while (NULL != resourceList) {
5925 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5926 return WINED3DERR_DEVICENOTRESET;
5927 resourceList = resourceList->next;
5929 return WINED3DERR_DEVICELOST;
5931 case WINED3DERR_DRIVERINTERNALERROR:
5932 return WINED3DERR_DRIVERINTERNALERROR;
5935 /* Unknown state */
5936 return WINED3DERR_DRIVERINTERNALERROR;
5940 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5942 /** FIXME: Resource tracking needs to be done,
5943 * The closes we can do to this is set the priorities of all managed textures low
5944 * and then reset them.
5945 ***********************************************************/
5946 FIXME("(%p) : stub\n", This);
5947 return WINED3D_OK;
5950 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5951 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5953 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5954 if(surface->Flags & SFLAG_DIBSECTION) {
5955 /* Release the DC */
5956 SelectObject(surface->hDC, surface->dib.holdbitmap);
5957 DeleteDC(surface->hDC);
5958 /* Release the DIB section */
5959 DeleteObject(surface->dib.DIBsection);
5960 surface->dib.bitmap_data = NULL;
5961 surface->resource.allocatedMemory = NULL;
5962 surface->Flags &= ~SFLAG_DIBSECTION;
5964 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5965 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5966 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5967 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5968 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5969 } else {
5970 surface->pow2Width = surface->pow2Height = 1;
5971 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5972 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5974 if(surface->glDescription.textureName) {
5975 ENTER_GL();
5976 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5977 glDeleteTextures(1, &surface->glDescription.textureName);
5978 LEAVE_GL();
5979 surface->glDescription.textureName = 0;
5980 surface->Flags &= ~SFLAG_CLIENT;
5982 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5983 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5984 surface->Flags |= SFLAG_NONPOW2;
5985 } else {
5986 surface->Flags &= ~SFLAG_NONPOW2;
5988 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5989 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5992 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5994 IWineD3DSwapChainImpl *swapchain;
5995 HRESULT hr;
5996 BOOL DisplayModeChanged = FALSE;
5997 WINED3DDISPLAYMODE mode;
5998 TRACE("(%p)\n", This);
6000 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6001 if(FAILED(hr)) {
6002 ERR("Failed to get the first implicit swapchain\n");
6003 return hr;
6006 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6007 * on an existing gl context, so there's no real need for recreation.
6009 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6011 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6013 TRACE("New params:\n");
6014 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6015 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6016 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6017 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6018 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6019 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6020 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6021 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6022 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6023 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6024 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6025 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6026 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6028 /* No special treatment of these parameters. Just store them */
6029 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6030 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6031 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6032 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6034 /* What to do about these? */
6035 if(pPresentationParameters->BackBufferCount != 0 &&
6036 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6037 ERR("Cannot change the back buffer count yet\n");
6039 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6040 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6041 ERR("Cannot change the back buffer format yet\n");
6043 if(pPresentationParameters->hDeviceWindow != NULL &&
6044 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6045 ERR("Cannot change the device window yet\n");
6047 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6048 ERR("What do do about a changed auto depth stencil parameter?\n");
6051 if(pPresentationParameters->Windowed) {
6052 mode.Width = swapchain->orig_width;
6053 mode.Height = swapchain->orig_height;
6054 mode.RefreshRate = 0;
6055 mode.Format = swapchain->presentParms.BackBufferFormat;
6056 } else {
6057 mode.Width = pPresentationParameters->BackBufferWidth;
6058 mode.Height = pPresentationParameters->BackBufferHeight;
6059 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6060 mode.Format = swapchain->presentParms.BackBufferFormat;
6062 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6063 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6064 pPresentationParameters->BackBufferWidth,
6065 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6068 /* Should Width == 800 && Height == 0 set 800x600? */
6069 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6070 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6071 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6073 WINED3DVIEWPORT vp;
6074 int i;
6076 vp.X = 0;
6077 vp.Y = 0;
6078 vp.Width = pPresentationParameters->BackBufferWidth;
6079 vp.Height = pPresentationParameters->BackBufferHeight;
6080 vp.MinZ = 0;
6081 vp.MaxZ = 1;
6083 if(!pPresentationParameters->Windowed) {
6084 DisplayModeChanged = TRUE;
6086 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6087 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6089 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6090 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6091 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6094 /* Now set the new viewport */
6095 IWineD3DDevice_SetViewport(iface, &vp);
6098 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6099 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6100 DisplayModeChanged) {
6102 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6103 if(!pPresentationParameters->Windowed) {
6104 IWineD3DDevice_SetFullscreen(iface, TRUE);
6107 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6109 /* Switching out of fullscreen mode? First set the original res, then change the window */
6110 if(pPresentationParameters->Windowed) {
6111 IWineD3DDevice_SetFullscreen(iface, FALSE);
6113 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6116 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6117 return WINED3D_OK;
6120 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6122 /** FIXME: always true at the moment **/
6123 if(!bEnableDialogs) {
6124 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6126 return WINED3D_OK;
6130 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6132 TRACE("(%p) : pParameters %p\n", This, pParameters);
6134 *pParameters = This->createParms;
6135 return WINED3D_OK;
6138 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6139 IWineD3DSwapChain *swapchain;
6140 HRESULT hrc = WINED3D_OK;
6142 TRACE("Relaying to swapchain\n");
6144 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6145 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6146 IWineD3DSwapChain_Release(swapchain);
6148 return;
6151 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6152 IWineD3DSwapChain *swapchain;
6153 HRESULT hrc = WINED3D_OK;
6155 TRACE("Relaying to swapchain\n");
6157 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6158 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6159 IWineD3DSwapChain_Release(swapchain);
6161 return;
6165 /** ********************************************************
6166 * Notification functions
6167 ** ********************************************************/
6168 /** This function must be called in the release of a resource when ref == 0,
6169 * the contents of resource must still be correct,
6170 * any handels to other resource held by the caller must be closed
6171 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6172 *****************************************************/
6173 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6175 ResourceList* resourceList;
6177 TRACE("(%p) : resource %p\n", This, resource);
6178 /* add a new texture to the frot of the linked list */
6179 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6180 resourceList->resource = resource;
6182 /* Get the old head */
6183 resourceList->next = This->resources;
6185 This->resources = resourceList;
6186 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6188 return;
6191 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6193 ResourceList* resourceList = NULL;
6194 ResourceList* previousResourceList = NULL;
6196 TRACE("(%p) : resource %p\n", This, resource);
6198 resourceList = This->resources;
6200 while (resourceList != NULL) {
6201 if(resourceList->resource == resource) break;
6202 previousResourceList = resourceList;
6203 resourceList = resourceList->next;
6206 if (resourceList == NULL) {
6207 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6208 return;
6209 } else {
6210 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6212 /* make sure we don't leave a hole in the list */
6213 if (previousResourceList != NULL) {
6214 previousResourceList->next = resourceList->next;
6215 } else {
6216 This->resources = resourceList->next;
6219 return;
6223 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6225 int counter;
6227 TRACE("(%p) : resource %p\n", This, resource);
6228 switch(IWineD3DResource_GetType(resource)){
6229 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6230 case WINED3DRTYPE_SURFACE: {
6231 unsigned int i;
6233 /* Cleanup any FBO attachments */
6234 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6235 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6236 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6237 set_render_target_fbo(iface, i, NULL);
6238 This->fbo_color_attachments[i] = NULL;
6241 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6242 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6243 set_depth_stencil_fbo(iface, NULL);
6244 This->fbo_depth_attachment = NULL;
6247 break;
6250 case WINED3DRTYPE_TEXTURE:
6251 case WINED3DRTYPE_CUBETEXTURE:
6252 case WINED3DRTYPE_VOLUMETEXTURE:
6253 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6254 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6255 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6256 This->stateBlock->textures[counter] = NULL;
6258 if (This->updateStateBlock != This->stateBlock ){
6259 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6260 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6261 This->updateStateBlock->textures[counter] = NULL;
6265 break;
6266 case WINED3DRTYPE_VOLUME:
6267 /* TODO: nothing really? */
6268 break;
6269 case WINED3DRTYPE_VERTEXBUFFER:
6270 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6272 int streamNumber;
6273 TRACE("Cleaning up stream pointers\n");
6275 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6276 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6277 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6279 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6280 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6281 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6282 This->updateStateBlock->streamSource[streamNumber] = 0;
6283 /* Set changed flag? */
6286 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) */
6287 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6288 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6289 This->stateBlock->streamSource[streamNumber] = 0;
6292 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6293 else { /* This shouldn't happen */
6294 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6296 #endif
6300 break;
6301 case WINED3DRTYPE_INDEXBUFFER:
6302 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6303 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6304 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6305 This->updateStateBlock->pIndexData = NULL;
6308 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6309 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6310 This->stateBlock->pIndexData = NULL;
6314 break;
6315 default:
6316 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6317 break;
6321 /* Remove the resoruce from the resourceStore */
6322 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6324 TRACE("Resource released\n");
6328 /**********************************************************
6329 * IWineD3DDevice VTbl follows
6330 **********************************************************/
6332 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6334 /*** IUnknown methods ***/
6335 IWineD3DDeviceImpl_QueryInterface,
6336 IWineD3DDeviceImpl_AddRef,
6337 IWineD3DDeviceImpl_Release,
6338 /*** IWineD3DDevice methods ***/
6339 IWineD3DDeviceImpl_GetParent,
6340 /*** Creation methods**/
6341 IWineD3DDeviceImpl_CreateVertexBuffer,
6342 IWineD3DDeviceImpl_CreateIndexBuffer,
6343 IWineD3DDeviceImpl_CreateStateBlock,
6344 IWineD3DDeviceImpl_CreateSurface,
6345 IWineD3DDeviceImpl_CreateTexture,
6346 IWineD3DDeviceImpl_CreateVolumeTexture,
6347 IWineD3DDeviceImpl_CreateVolume,
6348 IWineD3DDeviceImpl_CreateCubeTexture,
6349 IWineD3DDeviceImpl_CreateQuery,
6350 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6351 IWineD3DDeviceImpl_CreateVertexDeclaration,
6352 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6353 IWineD3DDeviceImpl_CreateVertexShader,
6354 IWineD3DDeviceImpl_CreatePixelShader,
6355 IWineD3DDeviceImpl_CreatePalette,
6356 /*** Odd functions **/
6357 IWineD3DDeviceImpl_Init3D,
6358 IWineD3DDeviceImpl_Uninit3D,
6359 IWineD3DDeviceImpl_SetFullscreen,
6360 IWineD3DDeviceImpl_SetMultithreaded,
6361 IWineD3DDeviceImpl_EvictManagedResources,
6362 IWineD3DDeviceImpl_GetAvailableTextureMem,
6363 IWineD3DDeviceImpl_GetBackBuffer,
6364 IWineD3DDeviceImpl_GetCreationParameters,
6365 IWineD3DDeviceImpl_GetDeviceCaps,
6366 IWineD3DDeviceImpl_GetDirect3D,
6367 IWineD3DDeviceImpl_GetDisplayMode,
6368 IWineD3DDeviceImpl_SetDisplayMode,
6369 IWineD3DDeviceImpl_GetHWND,
6370 IWineD3DDeviceImpl_SetHWND,
6371 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6372 IWineD3DDeviceImpl_GetRasterStatus,
6373 IWineD3DDeviceImpl_GetSwapChain,
6374 IWineD3DDeviceImpl_Reset,
6375 IWineD3DDeviceImpl_SetDialogBoxMode,
6376 IWineD3DDeviceImpl_SetCursorProperties,
6377 IWineD3DDeviceImpl_SetCursorPosition,
6378 IWineD3DDeviceImpl_ShowCursor,
6379 IWineD3DDeviceImpl_TestCooperativeLevel,
6380 /*** Getters and setters **/
6381 IWineD3DDeviceImpl_SetClipPlane,
6382 IWineD3DDeviceImpl_GetClipPlane,
6383 IWineD3DDeviceImpl_SetClipStatus,
6384 IWineD3DDeviceImpl_GetClipStatus,
6385 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6386 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6387 IWineD3DDeviceImpl_SetDepthStencilSurface,
6388 IWineD3DDeviceImpl_GetDepthStencilSurface,
6389 IWineD3DDeviceImpl_SetFVF,
6390 IWineD3DDeviceImpl_GetFVF,
6391 IWineD3DDeviceImpl_SetGammaRamp,
6392 IWineD3DDeviceImpl_GetGammaRamp,
6393 IWineD3DDeviceImpl_SetIndices,
6394 IWineD3DDeviceImpl_GetIndices,
6395 IWineD3DDeviceImpl_SetBaseVertexIndex,
6396 IWineD3DDeviceImpl_GetBaseVertexIndex,
6397 IWineD3DDeviceImpl_SetLight,
6398 IWineD3DDeviceImpl_GetLight,
6399 IWineD3DDeviceImpl_SetLightEnable,
6400 IWineD3DDeviceImpl_GetLightEnable,
6401 IWineD3DDeviceImpl_SetMaterial,
6402 IWineD3DDeviceImpl_GetMaterial,
6403 IWineD3DDeviceImpl_SetNPatchMode,
6404 IWineD3DDeviceImpl_GetNPatchMode,
6405 IWineD3DDeviceImpl_SetPaletteEntries,
6406 IWineD3DDeviceImpl_GetPaletteEntries,
6407 IWineD3DDeviceImpl_SetPixelShader,
6408 IWineD3DDeviceImpl_GetPixelShader,
6409 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6410 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6411 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6412 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6413 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6414 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6415 IWineD3DDeviceImpl_SetRenderState,
6416 IWineD3DDeviceImpl_GetRenderState,
6417 IWineD3DDeviceImpl_SetRenderTarget,
6418 IWineD3DDeviceImpl_GetRenderTarget,
6419 IWineD3DDeviceImpl_SetFrontBackBuffers,
6420 IWineD3DDeviceImpl_SetSamplerState,
6421 IWineD3DDeviceImpl_GetSamplerState,
6422 IWineD3DDeviceImpl_SetScissorRect,
6423 IWineD3DDeviceImpl_GetScissorRect,
6424 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6425 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6426 IWineD3DDeviceImpl_SetStreamSource,
6427 IWineD3DDeviceImpl_GetStreamSource,
6428 IWineD3DDeviceImpl_SetStreamSourceFreq,
6429 IWineD3DDeviceImpl_GetStreamSourceFreq,
6430 IWineD3DDeviceImpl_SetTexture,
6431 IWineD3DDeviceImpl_GetTexture,
6432 IWineD3DDeviceImpl_SetTextureStageState,
6433 IWineD3DDeviceImpl_GetTextureStageState,
6434 IWineD3DDeviceImpl_SetTransform,
6435 IWineD3DDeviceImpl_GetTransform,
6436 IWineD3DDeviceImpl_SetVertexDeclaration,
6437 IWineD3DDeviceImpl_GetVertexDeclaration,
6438 IWineD3DDeviceImpl_SetVertexShader,
6439 IWineD3DDeviceImpl_GetVertexShader,
6440 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6441 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6442 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6443 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6444 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6445 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6446 IWineD3DDeviceImpl_SetViewport,
6447 IWineD3DDeviceImpl_GetViewport,
6448 IWineD3DDeviceImpl_MultiplyTransform,
6449 IWineD3DDeviceImpl_ValidateDevice,
6450 IWineD3DDeviceImpl_ProcessVertices,
6451 /*** State block ***/
6452 IWineD3DDeviceImpl_BeginStateBlock,
6453 IWineD3DDeviceImpl_EndStateBlock,
6454 /*** Scene management ***/
6455 IWineD3DDeviceImpl_BeginScene,
6456 IWineD3DDeviceImpl_EndScene,
6457 IWineD3DDeviceImpl_Present,
6458 IWineD3DDeviceImpl_Clear,
6459 /*** Drawing ***/
6460 IWineD3DDeviceImpl_DrawPrimitive,
6461 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6462 IWineD3DDeviceImpl_DrawPrimitiveUP,
6463 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6464 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6465 IWineD3DDeviceImpl_DrawRectPatch,
6466 IWineD3DDeviceImpl_DrawTriPatch,
6467 IWineD3DDeviceImpl_DeletePatch,
6468 IWineD3DDeviceImpl_ColorFill,
6469 IWineD3DDeviceImpl_UpdateTexture,
6470 IWineD3DDeviceImpl_UpdateSurface,
6471 IWineD3DDeviceImpl_GetFrontBufferData,
6472 /*** object tracking ***/
6473 IWineD3DDeviceImpl_ResourceReleased
6477 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6478 WINED3DRS_ALPHABLENDENABLE ,
6479 WINED3DRS_ALPHAFUNC ,
6480 WINED3DRS_ALPHAREF ,
6481 WINED3DRS_ALPHATESTENABLE ,
6482 WINED3DRS_BLENDOP ,
6483 WINED3DRS_COLORWRITEENABLE ,
6484 WINED3DRS_DESTBLEND ,
6485 WINED3DRS_DITHERENABLE ,
6486 WINED3DRS_FILLMODE ,
6487 WINED3DRS_FOGDENSITY ,
6488 WINED3DRS_FOGEND ,
6489 WINED3DRS_FOGSTART ,
6490 WINED3DRS_LASTPIXEL ,
6491 WINED3DRS_SHADEMODE ,
6492 WINED3DRS_SRCBLEND ,
6493 WINED3DRS_STENCILENABLE ,
6494 WINED3DRS_STENCILFAIL ,
6495 WINED3DRS_STENCILFUNC ,
6496 WINED3DRS_STENCILMASK ,
6497 WINED3DRS_STENCILPASS ,
6498 WINED3DRS_STENCILREF ,
6499 WINED3DRS_STENCILWRITEMASK ,
6500 WINED3DRS_STENCILZFAIL ,
6501 WINED3DRS_TEXTUREFACTOR ,
6502 WINED3DRS_WRAP0 ,
6503 WINED3DRS_WRAP1 ,
6504 WINED3DRS_WRAP2 ,
6505 WINED3DRS_WRAP3 ,
6506 WINED3DRS_WRAP4 ,
6507 WINED3DRS_WRAP5 ,
6508 WINED3DRS_WRAP6 ,
6509 WINED3DRS_WRAP7 ,
6510 WINED3DRS_ZENABLE ,
6511 WINED3DRS_ZFUNC ,
6512 WINED3DRS_ZWRITEENABLE
6515 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6516 WINED3DTSS_ADDRESSW ,
6517 WINED3DTSS_ALPHAARG0 ,
6518 WINED3DTSS_ALPHAARG1 ,
6519 WINED3DTSS_ALPHAARG2 ,
6520 WINED3DTSS_ALPHAOP ,
6521 WINED3DTSS_BUMPENVLOFFSET ,
6522 WINED3DTSS_BUMPENVLSCALE ,
6523 WINED3DTSS_BUMPENVMAT00 ,
6524 WINED3DTSS_BUMPENVMAT01 ,
6525 WINED3DTSS_BUMPENVMAT10 ,
6526 WINED3DTSS_BUMPENVMAT11 ,
6527 WINED3DTSS_COLORARG0 ,
6528 WINED3DTSS_COLORARG1 ,
6529 WINED3DTSS_COLORARG2 ,
6530 WINED3DTSS_COLOROP ,
6531 WINED3DTSS_RESULTARG ,
6532 WINED3DTSS_TEXCOORDINDEX ,
6533 WINED3DTSS_TEXTURETRANSFORMFLAGS
6536 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6537 WINED3DSAMP_ADDRESSU ,
6538 WINED3DSAMP_ADDRESSV ,
6539 WINED3DSAMP_ADDRESSW ,
6540 WINED3DSAMP_BORDERCOLOR ,
6541 WINED3DSAMP_MAGFILTER ,
6542 WINED3DSAMP_MINFILTER ,
6543 WINED3DSAMP_MIPFILTER ,
6544 WINED3DSAMP_MIPMAPLODBIAS ,
6545 WINED3DSAMP_MAXMIPLEVEL ,
6546 WINED3DSAMP_MAXANISOTROPY ,
6547 WINED3DSAMP_SRGBTEXTURE ,
6548 WINED3DSAMP_ELEMENTINDEX
6551 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6552 WINED3DRS_AMBIENT ,
6553 WINED3DRS_AMBIENTMATERIALSOURCE ,
6554 WINED3DRS_CLIPPING ,
6555 WINED3DRS_CLIPPLANEENABLE ,
6556 WINED3DRS_COLORVERTEX ,
6557 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6558 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6559 WINED3DRS_FOGDENSITY ,
6560 WINED3DRS_FOGEND ,
6561 WINED3DRS_FOGSTART ,
6562 WINED3DRS_FOGTABLEMODE ,
6563 WINED3DRS_FOGVERTEXMODE ,
6564 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6565 WINED3DRS_LIGHTING ,
6566 WINED3DRS_LOCALVIEWER ,
6567 WINED3DRS_MULTISAMPLEANTIALIAS ,
6568 WINED3DRS_MULTISAMPLEMASK ,
6569 WINED3DRS_NORMALIZENORMALS ,
6570 WINED3DRS_PATCHEDGESTYLE ,
6571 WINED3DRS_POINTSCALE_A ,
6572 WINED3DRS_POINTSCALE_B ,
6573 WINED3DRS_POINTSCALE_C ,
6574 WINED3DRS_POINTSCALEENABLE ,
6575 WINED3DRS_POINTSIZE ,
6576 WINED3DRS_POINTSIZE_MAX ,
6577 WINED3DRS_POINTSIZE_MIN ,
6578 WINED3DRS_POINTSPRITEENABLE ,
6579 WINED3DRS_RANGEFOGENABLE ,
6580 WINED3DRS_SPECULARMATERIALSOURCE ,
6581 WINED3DRS_TWEENFACTOR ,
6582 WINED3DRS_VERTEXBLEND
6585 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6586 WINED3DTSS_TEXCOORDINDEX ,
6587 WINED3DTSS_TEXTURETRANSFORMFLAGS
6590 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6591 WINED3DSAMP_DMAPOFFSET
6594 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6595 DWORD rep = StateTable[state].representative;
6596 DWORD idx;
6597 BYTE shift;
6598 UINT i;
6599 WineD3DContext *context;
6601 if(!rep) return;
6602 for(i = 0; i < This->numContexts; i++) {
6603 context = This->contexts[i];
6604 if(isStateDirty(context, rep)) continue;
6606 context->dirtyArray[context->numDirtyEntries++] = rep;
6607 idx = rep >> 5;
6608 shift = rep & 0x1f;
6609 context->isStateDirty[idx] |= (1 << shift);