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 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
73 /* allocate one pbuffer per surface */
74 BOOL pbuffer_per_surface = FALSE;
76 /* static function declarations */
77 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
79 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
82 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
84 #define D3DCREATEOBJECTINSTANCE(object, type) { \
85 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
86 D3DMEMCHECK(object, pp##type); \
87 object->lpVtbl = &IWineD3D##type##_Vtbl; \
88 object->wineD3DDevice = This; \
89 object->parent = parent; \
91 *pp##type = (IWineD3D##type *) object; \
94 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
95 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
96 D3DMEMCHECK(object, pp##type); \
97 object->lpVtbl = &IWineD3D##type##_Vtbl; \
98 object->parent = parent; \
100 object->baseShader.device = (IWineD3DDevice*) This; \
101 list_init(&object->baseShader.linked_programs); \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * IUnknown parts follows
153 **********************************************************/
155 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
159 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
160 if (IsEqualGUID(riid, &IID_IUnknown)
161 || IsEqualGUID(riid, &IID_IWineD3DBase)
162 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
163 IUnknown_AddRef(iface);
168 return E_NOINTERFACE;
171 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
173 ULONG refCount = InterlockedIncrement(&This->ref);
175 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
179 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
181 ULONG refCount = InterlockedDecrement(&This->ref);
183 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
187 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
190 HeapFree(GetProcessHeap(), 0, This->render_targets);
192 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
194 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
196 /* TODO: Clean up all the surfaces and textures! */
197 /* NOTE: You must release the parent if the object was created via a callback
198 ** ***************************/
200 /* Release the update stateblock */
201 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
202 if(This->updateStateBlock != This->stateBlock)
203 FIXME("(%p) Something's still holding the Update stateblock\n",This);
205 This->updateStateBlock = NULL;
206 { /* because were not doing proper internal refcounts releasing the primary state block
207 causes recursion with the extra checks in ResourceReleased, to avoid this we have
208 to set this->stateBlock = NULL; first */
209 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
210 This->stateBlock = NULL;
212 /* Release the stateblock */
213 if(IWineD3DStateBlock_Release(stateBlock) > 0){
214 FIXME("(%p) Something's still holding the Update stateblock\n",This);
218 if (This->resources != NULL ) {
219 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
220 dumpResources(This->resources);
223 if(This->contexts) ERR("Context array not freed!\n");
225 IWineD3D_Release(This->wineD3D);
226 This->wineD3D = NULL;
227 HeapFree(GetProcessHeap(), 0, This);
228 TRACE("Freed device %p\n", This);
234 /**********************************************************
235 * IWineD3DDevice implementation follows
236 **********************************************************/
237 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
239 *pParent = This->parent;
240 IUnknown_AddRef(This->parent);
244 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
245 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
246 GLenum error, glUsage;
247 DWORD vboUsage = object->resource.usage;
248 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
249 WARN("Creating a vbo failed once, not trying again\n");
253 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
256 /* Make sure that the gl error is cleared. Do not use checkGLcall
257 * here because checkGLcall just prints a fixme and continues. However,
258 * if an error during VBO creation occurs we can fall back to non-vbo operation
259 * with full functionality(but performance loss)
261 while(glGetError() != GL_NO_ERROR);
263 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
264 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
265 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
266 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
267 * to check if the rhw and color values are in the correct format.
270 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
271 error = glGetError();
272 if(object->vbo == 0 || error != GL_NO_ERROR) {
273 WARN("Failed to create a VBO with error %d\n", error);
277 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
278 error = glGetError();
279 if(error != GL_NO_ERROR) {
280 WARN("Failed to bind the VBO, error %d\n", error);
284 /* Don't use static, because dx apps tend to update the buffer
285 * quite often even if they specify 0 usage. Because we always keep the local copy
286 * we never read from the vbo and can create a write only opengl buffer.
288 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
289 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
290 case WINED3DUSAGE_DYNAMIC:
291 TRACE("Gl usage = GL_STREAM_DRAW\n");
292 glUsage = GL_STREAM_DRAW_ARB;
294 case WINED3DUSAGE_WRITEONLY:
296 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
297 glUsage = GL_DYNAMIC_DRAW_ARB;
301 /* Reserve memory for the buffer. The amount of data won't change
302 * so we are safe with calling glBufferData once with a NULL ptr and
303 * calling glBufferSubData on updates
305 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
306 error = glGetError();
307 if(error != GL_NO_ERROR) {
308 WARN("glBufferDataARB failed with error %d\n", error);
316 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
317 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
318 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
320 object->Flags |= VBFLAG_VBOCREATEFAIL;
325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
326 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
329 IWineD3DVertexBufferImpl *object;
330 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
331 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
335 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
336 *ppVertexBuffer = NULL;
337 return WINED3DERR_INVALIDCALL;
340 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
342 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
343 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
345 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
346 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
350 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
351 * drawStridedFast (half-life 2).
353 * Basically converting the vertices in the buffer is quite expensive, and observations
354 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
355 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
357 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
358 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
359 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
360 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
362 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
363 * more. In this call we can convert dx7 buffers too.
365 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
366 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
367 (dxVersion > 7 || !conv) ) {
373 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
374 GLenum error, glUsage;
375 TRACE("Creating VBO for Index Buffer %p\n", object);
377 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
378 * restored on the next draw
380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
385 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
386 error = glGetError();
387 if(error != GL_NO_ERROR || object->vbo == 0) {
388 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
392 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
393 error = glGetError();
394 if(error != GL_NO_ERROR) {
395 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
399 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
400 * copy no readback will be needed
402 glUsage = GL_STATIC_DRAW;
403 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
404 error = glGetError();
405 if(error != GL_NO_ERROR) {
406 ERR("Failed to initialize the index buffer\n");
410 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
414 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
415 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
420 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
421 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
422 HANDLE *sharedHandle, IUnknown *parent) {
423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
424 IWineD3DIndexBufferImpl *object;
425 TRACE("(%p) Creating index buffer\n", This);
427 /* Allocate the storage for the device */
428 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
430 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
431 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
434 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
435 CreateIndexBufferVBO(This, object);
438 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
439 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
440 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
445 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
448 IWineD3DStateBlockImpl *object;
452 D3DCREATEOBJECTINSTANCE(object, StateBlock)
453 object->blockType = Type;
455 for(i = 0; i < LIGHTMAP_SIZE; i++) {
456 list_init(&object->lightMap[i]);
459 /* Special case - Used during initialization to produce a placeholder stateblock
460 so other functions called can update a state block */
461 if (Type == WINED3DSBT_INIT) {
462 /* Don't bother increasing the reference count otherwise a device will never
463 be freed due to circular dependencies */
467 temp_result = allocate_shader_constants(object);
468 if (WINED3D_OK != temp_result)
471 /* Otherwise, might as well set the whole state block to the appropriate values */
472 if (This->stateBlock != NULL)
473 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
475 memset(object->streamFreq, 1, sizeof(object->streamFreq));
477 /* Reset the ref and type after kludging it */
478 object->wineD3DDevice = This;
480 object->blockType = Type;
482 TRACE("Updating changed flags appropriate for type %d\n", Type);
484 if (Type == WINED3DSBT_ALL) {
486 TRACE("ALL => Pretend everything has changed\n");
487 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
489 /* Lights are not part of the changed / set structure */
490 for(j = 0; j < LIGHTMAP_SIZE; j++) {
492 LIST_FOR_EACH(e, &object->lightMap[j]) {
493 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
494 light->changed = TRUE;
495 light->enabledChanged = TRUE;
498 } else if (Type == WINED3DSBT_PIXELSTATE) {
500 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
501 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
503 object->changed.pixelShader = TRUE;
505 /* Pixel Shader Constants */
506 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
507 object->changed.pixelShaderConstantsF[i] = TRUE;
508 for (i = 0; i < MAX_CONST_B; ++i)
509 object->changed.pixelShaderConstantsB[i] = TRUE;
510 for (i = 0; i < MAX_CONST_I; ++i)
511 object->changed.pixelShaderConstantsI[i] = TRUE;
513 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
514 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
516 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
517 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
518 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
521 for (j = 0 ; j < 16; j++) {
522 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
524 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
528 } else if (Type == WINED3DSBT_VERTEXSTATE) {
530 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
531 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
533 object->changed.vertexShader = TRUE;
535 /* Vertex Shader Constants */
536 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
537 object->changed.vertexShaderConstantsF[i] = TRUE;
538 for (i = 0; i < MAX_CONST_B; ++i)
539 object->changed.vertexShaderConstantsB[i] = TRUE;
540 for (i = 0; i < MAX_CONST_I; ++i)
541 object->changed.vertexShaderConstantsI[i] = TRUE;
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
544 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
546 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
547 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
548 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
551 for (j = 0 ; j < 16; j++){
552 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
553 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 FIXME("Unrecognized state block type %d\n", Type);
569 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
574 /* ************************************
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 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.
583 ******************************** */
585 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) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int pow2Width, pow2Height;
589 unsigned int Size = 1;
590 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
591 TRACE("(%p) Create surface\n",This);
593 /** FIXME: Check ranges on the inputs are valid
596 * [in] Quality level. The valid range is between zero and one less than the level
597 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
598 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
599 * values of paired render targets, depth stencil surfaces, and the MultiSample type
601 *******************************/
606 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
608 * If this flag is set, the contents of the depth stencil buffer will be
609 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
610 * with a different depth surface.
612 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
613 ***************************/
615 if(MultisampleQuality < 0) {
616 FIXME("Invalid multisample level %d\n", MultisampleQuality);
617 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
620 if(MultisampleQuality > 0) {
621 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
622 MultisampleQuality=0;
625 /** FIXME: Check that the format is supported
627 *******************************/
629 /* Non-power2 support */
630 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
634 /* Find the nearest pow2 match */
635 pow2Width = pow2Height = 1;
636 while (pow2Width < Width) pow2Width <<= 1;
637 while (pow2Height < Height) pow2Height <<= 1;
640 if (pow2Width > Width || pow2Height > Height) {
641 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
642 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
643 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
644 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
645 This, Width, Height);
646 return WINED3DERR_NOTAVAILABLE;
650 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
651 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
653 *********************************/
654 if (WINED3DFMT_UNKNOWN == Format) {
656 } else if (Format == WINED3DFMT_DXT1) {
657 /* DXT1 is half byte per pixel */
658 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
660 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
661 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
662 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
664 /* The pitch is a multiple of 4 bytes */
665 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
669 /** Create and initialise the surface resource **/
670 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
671 /* "Standalone" surface */
672 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
674 object->currentDesc.Width = Width;
675 object->currentDesc.Height = Height;
676 object->currentDesc.MultiSampleType = MultiSample;
677 object->currentDesc.MultiSampleQuality = MultisampleQuality;
679 /* Setup some glformat defaults */
680 object->glDescription.glFormat = tableEntry->glFormat;
681 object->glDescription.glFormatInternal = tableEntry->glInternal;
682 object->glDescription.glType = tableEntry->glType;
684 object->glDescription.textureName = 0;
685 object->glDescription.level = Level;
686 object->glDescription.target = GL_TEXTURE_2D;
689 object->pow2Width = pow2Width;
690 object->pow2Height = pow2Height;
693 object->Flags = 0; /* We start without flags set */
694 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
695 object->Flags |= Discard ? SFLAG_DISCARD : 0;
696 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
697 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
700 if (WINED3DFMT_UNKNOWN != Format) {
701 object->bytesPerPixel = tableEntry->bpp;
703 object->bytesPerPixel = 0;
706 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
708 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
710 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
711 * this function is too deep to need to care about things like this.
712 * Levels need to be checked too, and possibly Type since they all affect what can be done.
713 * ****************************************/
715 case WINED3DPOOL_SCRATCH:
717 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
718 "which are mutually exclusive, setting lockable to TRUE\n");
721 case WINED3DPOOL_SYSTEMMEM:
722 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
723 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
724 case WINED3DPOOL_MANAGED:
725 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
726 "Usage of DYNAMIC which are mutually exclusive, not doing "
727 "anything just telling you.\n");
729 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
730 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
731 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
732 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
735 FIXME("(%p) Unknown pool %d\n", This, Pool);
739 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
740 FIXME("Trying to create a render target that isn't in the default pool\n");
743 /* mark the texture as dirty so that it gets loaded first time around*/
744 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
745 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
746 This, Width, Height, Format, debug_d3dformat(Format),
747 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
749 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
750 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
751 This->ddraw_primary = (IWineD3DSurface *) object;
753 /* Look at the implementation and set the correct Vtable */
756 /* Nothing to do, it's set already */
760 object->lpVtbl = &IWineGDISurface_Vtbl;
764 /* To be sure to catch this */
765 ERR("Unknown requested surface implementation %d!\n", Impl);
766 IWineD3DSurface_Release((IWineD3DSurface *) object);
767 return WINED3DERR_INVALIDCALL;
770 /* Call the private setup routine */
771 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
775 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
776 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
777 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
778 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
781 IWineD3DTextureImpl *object;
786 unsigned int pow2Width;
787 unsigned int pow2Height;
790 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
791 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
792 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
794 /* TODO: It should only be possible to create textures for formats
795 that are reported as supported */
796 if (WINED3DFMT_UNKNOWN >= Format) {
797 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
798 return WINED3DERR_INVALIDCALL;
801 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
802 D3DINITIALIZEBASETEXTURE(object->baseTexture);
803 object->width = Width;
804 object->height = Height;
806 /** Non-power2 support **/
807 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
811 /* Find the nearest pow2 match */
812 pow2Width = pow2Height = 1;
813 while (pow2Width < Width) pow2Width <<= 1;
814 while (pow2Height < Height) pow2Height <<= 1;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords */
819 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
820 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
821 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
823 /* Calculate levels for mip mapping */
825 TRACE("calculating levels %d\n", object->baseTexture.levels);
826 object->baseTexture.levels++;
829 while (tmpW > 1 || tmpH > 1) {
830 tmpW = max(1, tmpW >> 1);
831 tmpH = max(1, tmpH >> 1);
832 object->baseTexture.levels++;
834 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
837 /* Generate all the surfaces */
840 for (i = 0; i < object->baseTexture.levels; i++)
842 /* use the callback to create the texture surface */
843 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
844 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
845 FIXME("Failed to create surface %p\n", object);
847 object->surfaces[i] = NULL;
848 IWineD3DTexture_Release((IWineD3DTexture *)object);
854 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
855 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
856 /* calculate the next mipmap level */
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
861 TRACE("(%p) : Created texture %p\n", This, object);
865 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
866 UINT Width, UINT Height, UINT Depth,
867 UINT Levels, DWORD Usage,
868 WINED3DFORMAT Format, WINED3DPOOL Pool,
869 IWineD3DVolumeTexture **ppVolumeTexture,
870 HANDLE *pSharedHandle, IUnknown *parent,
871 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
874 IWineD3DVolumeTextureImpl *object;
880 /* TODO: It should only be possible to create textures for formats
881 that are reported as supported */
882 if (WINED3DFMT_UNKNOWN >= Format) {
883 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
884 return WINED3DERR_INVALIDCALL;
887 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
888 D3DINITIALIZEBASETEXTURE(object->baseTexture);
890 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
891 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
893 object->width = Width;
894 object->height = Height;
895 object->depth = Depth;
897 /* Calculate levels for mip mapping */
899 object->baseTexture.levels++;
903 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
904 tmpW = max(1, tmpW >> 1);
905 tmpH = max(1, tmpH >> 1);
906 tmpD = max(1, tmpD >> 1);
907 object->baseTexture.levels++;
909 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
912 /* Generate all the surfaces */
917 for (i = 0; i < object->baseTexture.levels; i++)
920 /* Create the volume */
921 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
922 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
925 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
926 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
927 *ppVolumeTexture = NULL;
931 /* Set its container to this object */
932 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
934 /* calcualte the next mipmap level */
935 tmpW = max(1, tmpW >> 1);
936 tmpH = max(1, tmpH >> 1);
937 tmpD = max(1, tmpD >> 1);
940 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
941 TRACE("(%p) : Created volume texture %p\n", This, object);
945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
946 UINT Width, UINT Height, UINT Depth,
948 WINED3DFORMAT Format, WINED3DPOOL Pool,
949 IWineD3DVolume** ppVolume,
950 HANDLE* pSharedHandle, IUnknown *parent) {
952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
953 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
954 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
956 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
958 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
959 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
961 object->currentDesc.Width = Width;
962 object->currentDesc.Height = Height;
963 object->currentDesc.Depth = Depth;
964 object->bytesPerPixel = formatDesc->bpp;
966 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
967 object->lockable = TRUE;
968 object->locked = FALSE;
969 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
970 object->dirty = TRUE;
972 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
975 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
976 UINT Levels, DWORD Usage,
977 WINED3DFORMAT Format, WINED3DPOOL Pool,
978 IWineD3DCubeTexture **ppCubeTexture,
979 HANDLE *pSharedHandle, IUnknown *parent,
980 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
987 unsigned int pow2EdgeLength = EdgeLength;
989 /* TODO: It should only be possible to create textures for formats
990 that are reported as supported */
991 if (WINED3DFMT_UNKNOWN >= Format) {
992 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
993 return WINED3DERR_INVALIDCALL;
996 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
997 D3DINITIALIZEBASETEXTURE(object->baseTexture);
999 TRACE("(%p) Create Cube Texture\n", This);
1001 /** Non-power2 support **/
1003 /* Find the nearest pow2 match */
1005 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1007 object->edgeLength = EdgeLength;
1008 /* TODO: support for native non-power 2 */
1009 /* Precalculated scaling for 'faked' non power of two texture coords */
1010 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1012 /* Calculate levels for mip mapping */
1014 object->baseTexture.levels++;
1017 tmpW = max(1, tmpW >> 1);
1018 object->baseTexture.levels++;
1020 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1023 /* Generate all the surfaces */
1025 for (i = 0; i < object->baseTexture.levels; i++) {
1027 /* Create the 6 faces */
1028 for (j = 0; j < 6; j++) {
1030 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1031 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1033 if(hr!= WINED3D_OK) {
1037 for (l = 0; l < j; l++) {
1038 IWineD3DSurface_Release(object->surfaces[j][i]);
1040 for (k = 0; k < i; k++) {
1041 for (l = 0; l < 6; l++) {
1042 IWineD3DSurface_Release(object->surfaces[l][j]);
1046 FIXME("(%p) Failed to create surface\n",object);
1047 HeapFree(GetProcessHeap(),0,object);
1048 *ppCubeTexture = NULL;
1051 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1052 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1054 tmpW = max(1, tmpW >> 1);
1057 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1058 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1065 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1067 /* Just a check to see if we support this type of query */
1069 case WINED3DQUERYTYPE_OCCLUSION:
1070 TRACE("(%p) occlusion query\n", This);
1071 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1074 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1077 case WINED3DQUERYTYPE_EVENT:
1078 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1079 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1081 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1085 case WINED3DQUERYTYPE_VCACHE:
1086 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1087 case WINED3DQUERYTYPE_VERTEXSTATS:
1088 case WINED3DQUERYTYPE_TIMESTAMP:
1089 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1090 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1091 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1092 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1093 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1094 case WINED3DQUERYTYPE_PIXELTIMINGS:
1095 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1096 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1098 FIXME("(%p) Unhandled query type %d\n", This, Type);
1100 if(NULL == ppQuery || hr != WINED3D_OK) {
1104 D3DCREATEOBJECTINSTANCE(object, Query)
1105 object->type = Type;
1106 /* allocated the 'extended' data based on the type of query requested */
1108 case WINED3DQUERYTYPE_OCCLUSION:
1109 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1110 TRACE("(%p) Allocating data for an occlusion query\n", This);
1111 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1112 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1115 case WINED3DQUERYTYPE_VCACHE:
1116 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1117 case WINED3DQUERYTYPE_VERTEXSTATS:
1118 case WINED3DQUERYTYPE_EVENT:
1119 case WINED3DQUERYTYPE_TIMESTAMP:
1120 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1121 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1122 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1123 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1124 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1125 case WINED3DQUERYTYPE_PIXELTIMINGS:
1126 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1127 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1129 object->extendedData = 0;
1130 FIXME("(%p) Unhandled query type %d\n",This , Type);
1132 TRACE("(%p) : Created Query %p\n", This, object);
1136 /*****************************************************************************
1137 * IWineD3DDeviceImpl_SetupFullscreenWindow
1139 * Helper function that modifies a HWND's Style and ExStyle for proper
1143 * iface: Pointer to the IWineD3DDevice interface
1144 * window: Window to setup
1146 *****************************************************************************/
1147 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1150 LONG style, exStyle;
1151 /* Don't do anything if an original style is stored.
1152 * That shouldn't happen
1154 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1155 if (This->style || This->exStyle) {
1156 ERR("(%p): Want to change the window parameters of HWND %p, but "
1157 "another style is stored for restoration afterwards\n", This, window);
1160 /* Get the parameters and save them */
1161 style = GetWindowLongW(window, GWL_STYLE);
1162 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1163 This->style = style;
1164 This->exStyle = exStyle;
1166 /* Filter out window decorations */
1167 style &= ~WS_CAPTION;
1168 style &= ~WS_THICKFRAME;
1169 exStyle &= ~WS_EX_WINDOWEDGE;
1170 exStyle &= ~WS_EX_CLIENTEDGE;
1172 /* Make sure the window is managed, otherwise we won't get keyboard input */
1173 style |= WS_POPUP | WS_SYSMENU;
1175 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1176 This->style, This->exStyle, style, exStyle);
1178 SetWindowLongW(window, GWL_STYLE, style);
1179 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1181 /* Inform the window about the update. */
1182 SetWindowPos(window, HWND_TOP, 0, 0,
1183 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1184 ShowWindow(window, SW_NORMAL);
1187 /*****************************************************************************
1188 * IWineD3DDeviceImpl_RestoreWindow
1190 * Helper function that restores a windows' properties when taking it out
1191 * of fullscreen mode
1194 * iface: Pointer to the IWineD3DDevice interface
1195 * window: Window to setup
1197 *****************************************************************************/
1198 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1201 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1202 * switch, do nothing
1204 if (!This->style && !This->exStyle) return;
1206 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1207 This, window, This->style, This->exStyle);
1209 SetWindowLongW(window, GWL_STYLE, This->style);
1210 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1212 /* Delete the old values */
1216 /* Inform the window about the update */
1217 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1218 0, 0, 0, 0, /* Pos, Size, ignored */
1219 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1222 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1223 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1225 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1226 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1230 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1231 HRESULT hr = WINED3D_OK;
1232 IUnknown *bufferParent;
1235 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1237 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1238 * does a device hold a reference to a swap chain giving them a lifetime of the device
1239 * or does the swap chain notify the device of its destruction.
1240 *******************************/
1242 /* Check the params */
1243 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1244 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1245 return WINED3DERR_INVALIDCALL;
1246 } else if (pPresentationParameters->BackBufferCount > 1) {
1247 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");
1250 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1252 /*********************
1253 * Lookup the window Handle and the relating X window handle
1254 ********************/
1256 /* Setup hwnd we are using, plus which display this equates to */
1257 object->win_handle = pPresentationParameters->hDeviceWindow;
1258 if (!object->win_handle) {
1259 object->win_handle = This->createParms.hFocusWindow;
1262 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1263 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1264 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1265 return WINED3DERR_NOTAVAILABLE;
1267 hDc = GetDC(object->win_handle);
1268 display = get_display(hDc);
1269 ReleaseDC(object->win_handle, hDc);
1270 TRACE("Using a display of %p %p\n", display, hDc);
1272 if (NULL == display || NULL == hDc) {
1273 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1274 return WINED3DERR_NOTAVAILABLE;
1277 if (object->win == 0) {
1278 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1279 return WINED3DERR_NOTAVAILABLE;
1282 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1283 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1284 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1286 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1287 * then the corresponding dimension of the client area of the hDeviceWindow
1288 * (or the focus window, if hDeviceWindow is NULL) is taken.
1289 **********************/
1291 if (pPresentationParameters->Windowed &&
1292 ((pPresentationParameters->BackBufferWidth == 0) ||
1293 (pPresentationParameters->BackBufferHeight == 0))) {
1296 GetClientRect(object->win_handle, &Rect);
1298 if (pPresentationParameters->BackBufferWidth == 0) {
1299 pPresentationParameters->BackBufferWidth = Rect.right;
1300 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1302 if (pPresentationParameters->BackBufferHeight == 0) {
1303 pPresentationParameters->BackBufferHeight = Rect.bottom;
1304 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1308 /* Put the correct figures in the presentation parameters */
1309 TRACE("Copying across presentation parameters\n");
1310 object->presentParms = *pPresentationParameters;
1312 TRACE("calling rendertarget CB\n");
1313 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1315 object->presentParms.BackBufferWidth,
1316 object->presentParms.BackBufferHeight,
1317 object->presentParms.BackBufferFormat,
1318 object->presentParms.MultiSampleType,
1319 object->presentParms.MultiSampleQuality,
1320 TRUE /* Lockable */,
1321 &object->frontBuffer,
1322 NULL /* pShared (always null)*/);
1323 if (object->frontBuffer != NULL) {
1324 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1326 ERR("Failed to create the front buffer\n");
1331 * Create an opengl context for the display visual
1332 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1333 * use different properties after that point in time. FIXME: How to handle when requested format
1334 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1335 * it chooses is identical to the one already being used!
1336 **********************************/
1338 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1340 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1343 if (!object->context) {
1344 ERR("Failed to create a new context\n");
1345 hr = WINED3DERR_NOTAVAILABLE;
1348 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1349 object->win_handle, object->context->glCtx, object->win);
1352 /*********************
1353 * Windowed / Fullscreen
1354 *******************/
1357 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1358 * so we should really check to see if there is a fullscreen swapchain already
1359 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1360 **************************************/
1362 if (!pPresentationParameters->Windowed) {
1369 /* Get info on the current display setup */
1371 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1374 /* Change the display settings */
1375 memset(&devmode, 0, sizeof(DEVMODEW));
1376 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1377 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1378 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1379 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1380 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1381 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1383 /* For GetDisplayMode */
1384 This->ddraw_width = devmode.dmPelsWidth;
1385 This->ddraw_height = devmode.dmPelsHeight;
1386 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1388 IWineD3DDevice_SetFullscreen(iface, TRUE);
1390 /* And finally clip mouse to our screen */
1391 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1392 ClipCursor(&clip_rc);
1395 /*********************
1396 * Create the back, front and stencil buffers
1397 *******************/
1398 if(object->presentParms.BackBufferCount > 0) {
1401 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1402 if(!object->backBuffer) {
1403 ERR("Out of memory\n");
1408 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1409 TRACE("calling rendertarget CB\n");
1410 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1412 object->presentParms.BackBufferWidth,
1413 object->presentParms.BackBufferHeight,
1414 object->presentParms.BackBufferFormat,
1415 object->presentParms.MultiSampleType,
1416 object->presentParms.MultiSampleQuality,
1417 TRUE /* Lockable */,
1418 &object->backBuffer[i],
1419 NULL /* pShared (always null)*/);
1420 if(hr == WINED3D_OK && object->backBuffer[i]) {
1421 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1423 ERR("Cannot create new back buffer\n");
1427 glDrawBuffer(GL_BACK);
1428 checkGLcall("glDrawBuffer(GL_BACK)");
1432 object->backBuffer = NULL;
1434 /* Single buffering - draw to front buffer */
1436 glDrawBuffer(GL_FRONT);
1437 checkGLcall("glDrawBuffer(GL_FRONT)");
1441 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1442 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1443 TRACE("Creating depth stencil buffer\n");
1444 if (This->depthStencilBuffer == NULL ) {
1445 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1447 object->presentParms.BackBufferWidth,
1448 object->presentParms.BackBufferHeight,
1449 object->presentParms.AutoDepthStencilFormat,
1450 object->presentParms.MultiSampleType,
1451 object->presentParms.MultiSampleQuality,
1452 FALSE /* FIXME: Discard */,
1453 &This->depthStencilBuffer,
1454 NULL /* pShared (always null)*/ );
1455 if (This->depthStencilBuffer != NULL)
1456 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1459 /** TODO: A check on width, height and multisample types
1460 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1461 ****************************/
1462 object->wantsDepthStencilBuffer = TRUE;
1464 object->wantsDepthStencilBuffer = FALSE;
1467 TRACE("Created swapchain %p\n", object);
1468 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1472 if (object->backBuffer) {
1474 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1475 if(object->backBuffer[i]) {
1476 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1477 IUnknown_Release(bufferParent); /* once for the get parent */
1478 if (IUnknown_Release(bufferParent) > 0) {
1479 FIXME("(%p) Something's still holding the back buffer\n",This);
1483 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1484 object->backBuffer = NULL;
1486 if(object->context) {
1487 DestroyContext(This, object->context);
1489 if(object->frontBuffer) {
1490 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1491 IUnknown_Release(bufferParent); /* once for the get parent */
1492 if (IUnknown_Release(bufferParent) > 0) {
1493 FIXME("(%p) Something's still holding the front buffer\n",This);
1496 if(object) HeapFree(GetProcessHeap(), 0, object);
1500 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1501 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1503 TRACE("(%p)\n", This);
1505 return This->NumberOfSwapChains;
1508 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1510 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1512 if(iSwapChain < This->NumberOfSwapChains) {
1513 *pSwapChain = This->swapchains[iSwapChain];
1514 IWineD3DSwapChain_AddRef(*pSwapChain);
1515 TRACE("(%p) returning %p\n", This, *pSwapChain);
1518 TRACE("Swapchain out of range\n");
1520 return WINED3DERR_INVALIDCALL;
1525 * Vertex Declaration
1527 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1528 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1530 IWineD3DVertexDeclarationImpl *object = NULL;
1531 HRESULT hr = WINED3D_OK;
1533 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1534 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1536 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1539 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1544 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1545 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1548 HRESULT hr = WINED3D_OK;
1549 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1550 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1552 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1554 if (vertex_declaration) {
1555 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1558 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1560 if (WINED3D_OK != hr) {
1561 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1562 IWineD3DVertexShader_Release(*ppVertexShader);
1563 return WINED3DERR_INVALIDCALL;
1569 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1571 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1572 HRESULT hr = WINED3D_OK;
1574 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1575 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1576 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1577 if (WINED3D_OK == hr) {
1578 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1580 WARN("(%p) : Failed to create pixel shader\n", This);
1586 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1588 IWineD3DPaletteImpl *object;
1590 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1592 /* Create the new object */
1593 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1595 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1596 return E_OUTOFMEMORY;
1599 object->lpVtbl = &IWineD3DPalette_Vtbl;
1601 object->Flags = Flags;
1602 object->parent = Parent;
1603 object->wineD3DDevice = This;
1604 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1606 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1609 HeapFree( GetProcessHeap(), 0, object);
1610 return E_OUTOFMEMORY;
1613 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1615 IWineD3DPalette_Release((IWineD3DPalette *) object);
1619 *Palette = (IWineD3DPalette *) object;
1624 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1626 IWineD3DSwapChainImpl *swapchain;
1629 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1630 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1632 /* TODO: Test if OpenGL is compiled in and loaded */
1634 /* Initialize the texture unit mapping to a 1:1 mapping */
1635 for(state = 0; state < MAX_SAMPLERS; state++) {
1636 This->texUnitMap[state] = state;
1638 This->oneToOneTexUnitMap = TRUE;
1640 /* Setup the implicit swapchain */
1641 TRACE("Creating implicit swapchain\n");
1642 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1643 WARN("Failed to create implicit swapchain\n");
1644 return WINED3DERR_INVALIDCALL;
1647 This->NumberOfSwapChains = 1;
1648 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1649 if(!This->swapchains) {
1650 ERR("Out of memory!\n");
1651 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1652 return E_OUTOFMEMORY;
1654 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1656 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1658 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1659 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1660 This->render_targets[0] = swapchain->backBuffer[0];
1661 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1664 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1665 This->render_targets[0] = swapchain->frontBuffer;
1666 This->lastActiveRenderTarget = swapchain->frontBuffer;
1668 IWineD3DSurface_AddRef(This->render_targets[0]);
1669 This->activeContext = swapchain->context;
1671 /* Depth Stencil support */
1672 This->stencilBufferTarget = This->depthStencilBuffer;
1673 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1674 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1676 if (NULL != This->stencilBufferTarget) {
1677 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1680 /* Set up some starting GL setup */
1683 * Initialize openGL extension related variables
1684 * with Default values
1687 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1688 /* Setup all the devices defaults */
1689 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1691 IWineD3DImpl_CheckGraphicsMemory();
1694 { /* Set a default viewport */
1698 vp.Width = pPresentationParameters->BackBufferWidth;
1699 vp.Height = pPresentationParameters->BackBufferHeight;
1702 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1705 /* Initialize the current view state */
1706 This->view_ident = 1;
1707 This->contexts[0]->last_was_rhw = 0;
1708 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1709 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1710 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1713 /* Clear the screen */
1714 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1716 This->d3d_initialized = TRUE;
1720 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1724 TRACE("(%p)\n", This);
1726 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1728 /* Delete the pbuffer context if there is any */
1729 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1731 /* Delete the mouse cursor texture */
1732 if(This->cursorTexture) {
1734 glDeleteTextures(1, &This->cursorTexture);
1736 This->cursorTexture = 0;
1739 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1740 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1743 /* Release the buffers (with sanity checks)*/
1744 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1745 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1746 if(This->depthStencilBuffer != This->stencilBufferTarget)
1747 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1749 This->stencilBufferTarget = NULL;
1751 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1752 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1753 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1755 TRACE("Setting rendertarget to NULL\n");
1756 This->render_targets[0] = NULL;
1758 if (This->depthStencilBuffer) {
1759 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1760 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1762 This->depthStencilBuffer = NULL;
1765 for(i=0; i < This->NumberOfSwapChains; i++) {
1766 TRACE("Releasing the implicit swapchain %d\n", i);
1767 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1768 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1772 HeapFree(GetProcessHeap(), 0, This->swapchains);
1773 This->swapchains = NULL;
1774 This->NumberOfSwapChains = 0;
1776 This->d3d_initialized = FALSE;
1780 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1782 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1784 /* Setup the window for fullscreen mode */
1785 if(fullscreen && !This->ddraw_fullscreen) {
1786 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1787 } else if(!fullscreen && This->ddraw_fullscreen) {
1788 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1791 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1792 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1793 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1796 This->ddraw_fullscreen = fullscreen;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1803 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1806 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1808 /* Resize the screen even without a window:
1809 * The app could have unset it with SetCooperativeLevel, but not called
1810 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1811 * but we don't have any hwnd
1814 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1815 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1816 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1817 devmode.dmPelsWidth = pMode->Width;
1818 devmode.dmPelsHeight = pMode->Height;
1820 devmode.dmDisplayFrequency = pMode->RefreshRate;
1821 if (pMode->RefreshRate != 0) {
1822 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1825 /* Only change the mode if necessary */
1826 if( (This->ddraw_width == pMode->Width) &&
1827 (This->ddraw_height == pMode->Height) &&
1828 (This->ddraw_format == pMode->Format) &&
1829 (pMode->RefreshRate == 0) ) {
1833 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1834 if (ret != DISP_CHANGE_SUCCESSFUL) {
1835 if(devmode.dmDisplayFrequency != 0) {
1836 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1837 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1838 devmode.dmDisplayFrequency = 0;
1839 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1841 if(ret != DISP_CHANGE_SUCCESSFUL) {
1842 return DDERR_INVALIDMODE;
1846 /* Store the new values */
1847 This->ddraw_width = pMode->Width;
1848 This->ddraw_height = pMode->Height;
1849 This->ddraw_format = pMode->Format;
1851 /* Only do this with a window of course */
1852 if(This->ddraw_window)
1853 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1855 /* And finally clip mouse to our screen */
1856 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1857 ClipCursor(&clip_rc);
1862 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1864 *ppD3D= This->wineD3D;
1865 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1866 IWineD3D_AddRef(*ppD3D);
1870 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1871 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1872 * into the video ram as possible and seeing how many fit
1873 * you can also get the correct initial value from nvidia and ATI's driver via X
1874 * texture memory is video memory + AGP memory
1875 *******************/
1876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1877 static BOOL showfixmes = TRUE;
1879 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1880 (wined3d_settings.emulated_textureram/(1024*1024)),
1881 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1884 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1885 (wined3d_settings.emulated_textureram/(1024*1024)),
1886 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1887 /* return simulated texture memory left */
1888 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1896 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1899 /* Update the current state block */
1900 This->updateStateBlock->changed.fvf = TRUE;
1901 This->updateStateBlock->set.fvf = TRUE;
1903 if(This->updateStateBlock->fvf == fvf) {
1904 TRACE("Application is setting the old fvf over, nothing to do\n");
1908 This->updateStateBlock->fvf = fvf;
1909 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1915 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1917 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1918 *pfvf = This->stateBlock->fvf;
1923 * Get / Set Stream Source
1925 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 IWineD3DVertexBuffer *oldSrc;
1929 if (StreamNumber >= MAX_STREAMS) {
1930 WARN("Stream out of range %d\n", StreamNumber);
1931 return WINED3DERR_INVALIDCALL;
1934 oldSrc = This->stateBlock->streamSource[StreamNumber];
1935 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1937 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1938 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1940 if(oldSrc == pStreamData &&
1941 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1942 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1943 TRACE("Application is setting the old values over, nothing to do\n");
1947 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1949 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1950 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1953 /* Handle recording of state blocks */
1954 if (This->isRecordingState) {
1955 TRACE("Recording... not performing anything\n");
1959 /* Need to do a getParent and pass the reffs up */
1960 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1961 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1962 so for now, just count internally */
1963 if (pStreamData != NULL) {
1964 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
1965 InterlockedIncrement(&vbImpl->bindCount);
1967 if (oldSrc != NULL) {
1968 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
1971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1976 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
1977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1979 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
1980 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
1982 if (StreamNumber >= MAX_STREAMS) {
1983 WARN("Stream out of range %d\n", StreamNumber);
1984 return WINED3DERR_INVALIDCALL;
1986 *pStream = This->stateBlock->streamSource[StreamNumber];
1987 *pStride = This->stateBlock->streamStride[StreamNumber];
1989 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1992 if (*pStream != NULL) {
1993 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1998 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2000 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2001 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2003 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2004 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2006 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2007 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2008 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2010 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2011 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2018 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2021 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2022 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2024 TRACE("(%p) : returning %d\n", This, *Divider);
2030 * Get / Set & Multiply Transform
2032 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2035 /* Most of this routine, comments included copied from ddraw tree initially: */
2036 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2038 /* Handle recording of state blocks */
2039 if (This->isRecordingState) {
2040 TRACE("Recording... not performing anything\n");
2041 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2042 This->updateStateBlock->set.transform[d3dts] = TRUE;
2043 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2048 * If the new matrix is the same as the current one,
2049 * we cut off any further processing. this seems to be a reasonable
2050 * optimization because as was noticed, some apps (warcraft3 for example)
2051 * tend towards setting the same matrix repeatedly for some reason.
2053 * From here on we assume that the new matrix is different, wherever it matters.
2055 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2056 TRACE("The app is setting the same matrix over again\n");
2059 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2063 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2064 where ViewMat = Camera space, WorldMat = world space.
2066 In OpenGL, camera and world space is combined into GL_MODELVIEW
2067 matrix. The Projection matrix stay projection matrix.
2070 /* Capture the times we can just ignore the change for now */
2071 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2072 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2073 /* Handled by the state manager */
2076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2080 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2082 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2083 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2087 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2088 WINED3DMATRIX *mat = NULL;
2091 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2092 * below means it will be recorded in a state block change, but it
2093 * works regardless where it is recorded.
2094 * If this is found to be wrong, change to StateBlock.
2096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2097 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2099 if (State < HIGHEST_TRANSFORMSTATE)
2101 mat = &This->updateStateBlock->transforms[State];
2103 FIXME("Unhandled transform state!!\n");
2106 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2108 /* Apply change via set transform - will reapply to eg. lights this way */
2109 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2115 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2116 you can reference any indexes you want as long as that number max are enabled at any
2117 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2118 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2119 but when recording, just build a chain pretty much of commands to be replayed. */
2121 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2123 PLIGHTINFOEL *object = NULL;
2124 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2128 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2130 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2134 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2135 return WINED3DERR_INVALIDCALL;
2138 switch(pLight->Type) {
2139 case WINED3DLIGHT_POINT:
2140 case WINED3DLIGHT_SPOT:
2141 case WINED3DLIGHT_PARALLELPOINT:
2142 case WINED3DLIGHT_GLSPOT:
2143 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2146 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2147 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2148 return WINED3DERR_INVALIDCALL;
2152 case WINED3DLIGHT_DIRECTIONAL:
2153 /* Ignores attenuation */
2157 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2158 return WINED3DERR_INVALIDCALL;
2161 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2162 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2163 if(object->OriginalIndex == Index) break;
2168 TRACE("Adding new light\n");
2169 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2171 ERR("Out of memory error when allocating a light\n");
2172 return E_OUTOFMEMORY;
2174 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2175 object->glIndex = -1;
2176 object->OriginalIndex = Index;
2177 object->changed = TRUE;
2180 /* Initialize the object */
2181 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,
2182 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2183 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2184 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2185 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2186 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2187 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2189 /* Save away the information */
2190 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2192 switch (pLight->Type) {
2193 case WINED3DLIGHT_POINT:
2195 object->lightPosn[0] = pLight->Position.x;
2196 object->lightPosn[1] = pLight->Position.y;
2197 object->lightPosn[2] = pLight->Position.z;
2198 object->lightPosn[3] = 1.0f;
2199 object->cutoff = 180.0f;
2203 case WINED3DLIGHT_DIRECTIONAL:
2205 object->lightPosn[0] = -pLight->Direction.x;
2206 object->lightPosn[1] = -pLight->Direction.y;
2207 object->lightPosn[2] = -pLight->Direction.z;
2208 object->lightPosn[3] = 0.0;
2209 object->exponent = 0.0f;
2210 object->cutoff = 180.0f;
2213 case WINED3DLIGHT_SPOT:
2215 object->lightPosn[0] = pLight->Position.x;
2216 object->lightPosn[1] = pLight->Position.y;
2217 object->lightPosn[2] = pLight->Position.z;
2218 object->lightPosn[3] = 1.0;
2221 object->lightDirn[0] = pLight->Direction.x;
2222 object->lightDirn[1] = pLight->Direction.y;
2223 object->lightDirn[2] = pLight->Direction.z;
2224 object->lightDirn[3] = 1.0;
2227 * opengl-ish and d3d-ish spot lights use too different models for the
2228 * light "intensity" as a function of the angle towards the main light direction,
2229 * so we only can approximate very roughly.
2230 * however spot lights are rather rarely used in games (if ever used at all).
2231 * furthermore if still used, probably nobody pays attention to such details.
2233 if (pLight->Falloff == 0) {
2236 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2238 if (rho < 0.0001) rho = 0.0001f;
2239 object->exponent = -0.3/log(cos(rho/2));
2240 if (object->exponent > 128.0) {
2241 object->exponent = 128.0;
2243 object->cutoff = pLight->Phi*90/M_PI;
2249 FIXME("Unrecognized light type %d\n", pLight->Type);
2252 /* Update the live definitions if the light is currently assigned a glIndex */
2253 if (object->glIndex != -1 && !This->isRecordingState) {
2254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2259 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2260 PLIGHTINFOEL *lightInfo = NULL;
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2262 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2264 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2266 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2267 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2268 if(lightInfo->OriginalIndex == Index) break;
2272 if (lightInfo == NULL) {
2273 TRACE("Light information requested but light not defined\n");
2274 return WINED3DERR_INVALIDCALL;
2277 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2282 * Get / Set Light Enable
2283 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2285 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2286 PLIGHTINFOEL *lightInfo = NULL;
2287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2288 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2290 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2292 /* Tests show true = 128...not clear why */
2293 Enable = Enable? 128: 0;
2295 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2296 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2297 if(lightInfo->OriginalIndex == Index) break;
2300 TRACE("Found light: %p\n", lightInfo);
2302 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2303 if (lightInfo == NULL) {
2305 TRACE("Light enabled requested but light not defined, so defining one!\n");
2306 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2308 /* Search for it again! Should be fairly quick as near head of list */
2309 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2310 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2311 if(lightInfo->OriginalIndex == Index) break;
2314 if (lightInfo == NULL) {
2315 FIXME("Adding default lights has failed dismally\n");
2316 return WINED3DERR_INVALIDCALL;
2320 lightInfo->enabledChanged = TRUE;
2322 if(lightInfo->glIndex != -1) {
2323 if(!This->isRecordingState) {
2324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2327 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2328 lightInfo->glIndex = -1;
2330 TRACE("Light already disabled, nothing to do\n");
2333 if (lightInfo->glIndex != -1) {
2335 TRACE("Nothing to do as light was enabled\n");
2338 /* Find a free gl light */
2339 for(i = 0; i < This->maxConcurrentLights; i++) {
2340 if(This->stateBlock->activeLights[i] == NULL) {
2341 This->stateBlock->activeLights[i] = lightInfo;
2342 lightInfo->glIndex = i;
2346 if(lightInfo->glIndex == -1) {
2347 ERR("Too many concurrently active lights\n");
2348 return WINED3DERR_INVALIDCALL;
2351 /* i == lightInfo->glIndex */
2352 if(!This->isRecordingState) {
2353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2361 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2363 PLIGHTINFOEL *lightInfo = NULL;
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2366 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2367 TRACE("(%p) : for idx(%d)\n", This, Index);
2369 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2370 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2371 if(lightInfo->OriginalIndex == Index) break;
2375 if (lightInfo == NULL) {
2376 TRACE("Light enabled state requested but light not defined\n");
2377 return WINED3DERR_INVALIDCALL;
2379 /* true is 128 according to SetLightEnable */
2380 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2385 * Get / Set Clip Planes
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2389 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2391 /* Validate Index */
2392 if (Index >= GL_LIMITS(clipplanes)) {
2393 TRACE("Application has requested clipplane this device doesn't support\n");
2394 return WINED3DERR_INVALIDCALL;
2397 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2398 This->updateStateBlock->set.clipplane[Index] = TRUE;
2399 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2400 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2401 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2402 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2404 /* Handle recording of state blocks */
2405 if (This->isRecordingState) {
2406 TRACE("Recording... not performing anything\n");
2414 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2415 glMatrixMode(GL_MODELVIEW);
2417 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2419 TRACE("Clipplane [%f,%f,%f,%f]\n",
2420 This->updateStateBlock->clipplane[Index][0],
2421 This->updateStateBlock->clipplane[Index][1],
2422 This->updateStateBlock->clipplane[Index][2],
2423 This->updateStateBlock->clipplane[Index][3]);
2424 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2425 checkGLcall("glClipPlane");
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2435 TRACE("(%p) : for idx %d\n", This, Index);
2437 /* Validate Index */
2438 if (Index >= GL_LIMITS(clipplanes)) {
2439 TRACE("Application has requested clipplane this device doesn't support\n");
2440 return WINED3DERR_INVALIDCALL;
2443 pPlane[0] = This->stateBlock->clipplane[Index][0];
2444 pPlane[1] = This->stateBlock->clipplane[Index][1];
2445 pPlane[2] = This->stateBlock->clipplane[Index][2];
2446 pPlane[3] = This->stateBlock->clipplane[Index][3];
2451 * Get / Set Clip Plane Status
2452 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2454 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2456 FIXME("(%p) : stub\n", This);
2457 if (NULL == pClipStatus) {
2458 return WINED3DERR_INVALIDCALL;
2460 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2461 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2465 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2467 FIXME("(%p) : stub\n", This);
2468 if (NULL == pClipStatus) {
2469 return WINED3DERR_INVALIDCALL;
2471 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2472 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2477 * Get / Set Material
2479 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 This->updateStateBlock->changed.material = TRUE;
2483 This->updateStateBlock->set.material = TRUE;
2484 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2486 /* Handle recording of state blocks */
2487 if (This->isRecordingState) {
2488 TRACE("Recording... not performing anything\n");
2493 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2494 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2495 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2496 pMaterial->Ambient.b, pMaterial->Ambient.a);
2497 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2498 pMaterial->Specular.b, pMaterial->Specular.a);
2499 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2500 pMaterial->Emissive.b, pMaterial->Emissive.a);
2501 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2503 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2504 checkGLcall("glMaterialfv(GL_AMBIENT)");
2505 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2506 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2508 /* Only change material color if specular is enabled, otherwise it is set to black */
2509 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2510 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2511 checkGLcall("glMaterialfv(GL_SPECULAR");
2513 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2514 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2515 checkGLcall("glMaterialfv(GL_SPECULAR");
2517 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2518 checkGLcall("glMaterialfv(GL_EMISSION)");
2519 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2520 checkGLcall("glMaterialf(GL_SHININESS");
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2529 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2530 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2531 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2532 pMaterial->Ambient.b, pMaterial->Ambient.a);
2533 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2534 pMaterial->Specular.b, pMaterial->Specular.a);
2535 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2536 pMaterial->Emissive.b, pMaterial->Emissive.a);
2537 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2545 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2546 UINT BaseVertexIndex) {
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 IWineD3DIndexBuffer *oldIdxs;
2549 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2551 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2552 oldIdxs = This->updateStateBlock->pIndexData;
2554 This->updateStateBlock->changed.indices = TRUE;
2555 This->updateStateBlock->set.indices = TRUE;
2556 This->updateStateBlock->pIndexData = pIndexData;
2557 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2559 /* Handle recording of state blocks */
2560 if (This->isRecordingState) {
2561 TRACE("Recording... not performing anything\n");
2565 /* The base vertex index affects the stream sources, while
2566 * The index buffer is a seperate index buffer state
2568 if(BaseVertexIndex != oldBaseIndex) {
2569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2571 if(oldIdxs != pIndexData) {
2572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2577 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 *ppIndexData = This->stateBlock->pIndexData;
2582 /* up ref count on ppindexdata */
2584 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2585 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2586 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2588 TRACE("(%p) No index data set\n", This);
2590 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2595 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2596 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 TRACE("(%p)->(%d)\n", This, BaseIndex);
2600 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2601 TRACE("Application is setting the old value over, nothing to do\n");
2605 This->updateStateBlock->baseVertexIndex = BaseIndex;
2607 if (This->isRecordingState) {
2608 TRACE("Recording... not performing anything\n");
2611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2616 * Get / Set Viewports
2618 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p)\n", This);
2622 This->updateStateBlock->changed.viewport = TRUE;
2623 This->updateStateBlock->set.viewport = TRUE;
2624 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2626 /* Handle recording of state blocks */
2627 if (This->isRecordingState) {
2628 TRACE("Recording... not performing anything\n");
2632 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2633 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2640 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 TRACE("(%p)\n", This);
2643 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2648 * Get / Set Render States
2649 * TODO: Verify against dx9 definitions
2651 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2654 DWORD oldValue = This->stateBlock->renderState[State];
2656 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2658 This->updateStateBlock->changed.renderState[State] = TRUE;
2659 This->updateStateBlock->set.renderState[State] = TRUE;
2660 This->updateStateBlock->renderState[State] = Value;
2662 /* Handle recording of state blocks */
2663 if (This->isRecordingState) {
2664 TRACE("Recording... not performing anything\n");
2668 /* Compared here and not before the assignment to allow proper stateblock recording */
2669 if(Value == oldValue) {
2670 TRACE("Application is setting the old value over, nothing to do\n");
2672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2678 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2681 *pValue = This->stateBlock->renderState[State];
2686 * Get / Set Sampler States
2687 * TODO: Verify against dx9 definitions
2690 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2692 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2695 * SetSampler is designed to allow for more than the standard up to 8 textures
2696 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2697 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2699 * http://developer.nvidia.com/object/General_FAQ.html#t6
2701 * There are two new settings for GForce
2703 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2704 * and the texture one:
2705 * GL_MAX_TEXTURE_COORDS_ARB.
2706 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2709 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2710 debug_d3dsamplerstate(Type), Type, Value);
2711 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2712 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2713 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2715 /* Handle recording of state blocks */
2716 if (This->isRecordingState) {
2717 TRACE("Recording... not performing anything\n");
2721 if(oldValue == Value) {
2722 TRACE("Application is setting the old value over, nothing to do\n");
2726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2731 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2733 *Value = This->stateBlock->samplerState[Sampler][Type];
2734 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 This->updateStateBlock->set.scissorRect = TRUE;
2743 This->updateStateBlock->changed.scissorRect = TRUE;
2744 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2745 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2748 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2750 if(This->isRecordingState) {
2751 TRACE("Recording... not performing anything\n");
2755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2760 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2763 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2764 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2768 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2770 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2772 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2774 This->updateStateBlock->vertexDecl = pDecl;
2775 This->updateStateBlock->changed.vertexDecl = TRUE;
2776 This->updateStateBlock->set.vertexDecl = TRUE;
2778 if (This->isRecordingState) {
2779 TRACE("Recording... not performing anything\n");
2781 } else if(pDecl == oldDecl) {
2782 /* Checked after the assignment to allow proper stateblock recording */
2783 TRACE("Application is setting the old declaration over, nothing to do\n");
2787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2791 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2794 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2796 *ppDecl = This->stateBlock->vertexDecl;
2797 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2801 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2805 This->updateStateBlock->vertexShader = pShader;
2806 This->updateStateBlock->changed.vertexShader = TRUE;
2807 This->updateStateBlock->set.vertexShader = TRUE;
2809 if (This->isRecordingState) {
2810 TRACE("Recording... not performing anything\n");
2812 } else if(oldShader == pShader) {
2813 /* Checked here to allow proper stateblock recording */
2814 TRACE("App is setting the old shader over, nothing to do\n");
2818 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2825 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 if (NULL == ppShader) {
2829 return WINED3DERR_INVALIDCALL;
2831 *ppShader = This->stateBlock->vertexShader;
2832 if( NULL != *ppShader)
2833 IWineD3DVertexShader_AddRef(*ppShader);
2835 TRACE("(%p) : returning %p\n", This, *ppShader);
2839 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2840 IWineD3DDevice *iface,
2842 CONST BOOL *srcData,
2845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2846 int i, cnt = min(count, MAX_CONST_B - start);
2848 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2849 iface, srcData, start, count);
2851 if (srcData == NULL || cnt < 0)
2852 return WINED3DERR_INVALIDCALL;
2854 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2855 for (i = 0; i < cnt; i++)
2856 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2858 for (i = start; i < cnt + start; ++i) {
2859 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2860 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2868 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2869 IWineD3DDevice *iface,
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 int cnt = min(count, MAX_CONST_B - start);
2877 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2878 iface, dstData, start, count);
2880 if (dstData == NULL || cnt < 0)
2881 return WINED3DERR_INVALIDCALL;
2883 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2887 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2888 IWineD3DDevice *iface,
2893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2894 int i, cnt = min(count, MAX_CONST_I - start);
2896 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2897 iface, srcData, start, count);
2899 if (srcData == NULL || cnt < 0)
2900 return WINED3DERR_INVALIDCALL;
2902 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2903 for (i = 0; i < cnt; i++)
2904 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2905 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2907 for (i = start; i < cnt + start; ++i) {
2908 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2909 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2918 IWineD3DDevice *iface,
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 int cnt = min(count, MAX_CONST_I - start);
2926 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2927 iface, dstData, start, count);
2929 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2930 return WINED3DERR_INVALIDCALL;
2932 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2936 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2937 IWineD3DDevice *iface,
2939 CONST float *srcData,
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2946 iface, srcData, start, count);
2948 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2949 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
2950 return WINED3DERR_INVALIDCALL;
2952 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2954 for (i = 0; i < count; i++)
2955 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2956 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2959 for (i = start; i < count + start; ++i) {
2960 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2961 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
2962 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
2963 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
2964 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
2966 ptr->idx[ptr->count++] = i;
2967 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
2969 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2978 IWineD3DDevice *iface,
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2986 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2987 iface, dstData, start, count);
2989 if (dstData == NULL || cnt < 0)
2990 return WINED3DERR_INVALIDCALL;
2992 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2996 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2998 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
2999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3003 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3005 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3006 * it is never called.
3009 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3010 * that would be really messy and require shader recompilation
3011 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3012 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3013 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3014 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3016 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3017 if(This->oneToOneTexUnitMap) {
3018 TRACE("Not touching 1:1 map\n");
3021 TRACE("Restoring 1:1 texture unit mapping\n");
3022 /* Restore a 1:1 mapping */
3023 for(i = 0; i < MAX_SAMPLERS; i++) {
3024 if(This->texUnitMap[i] != i) {
3025 This->texUnitMap[i] = i;
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3027 markTextureStagesDirty(This, i);
3030 This->oneToOneTexUnitMap = TRUE;
3033 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3034 * First, see if we can succeed at all
3037 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3038 if(This->stateBlock->textures[i] == NULL) tex++;
3041 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3042 FIXME("Too many bound textures to support the combiner settings\n");
3046 /* Now work out the mapping */
3048 This->oneToOneTexUnitMap = FALSE;
3049 WARN("Non 1:1 mapping UNTESTED!\n");
3050 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3051 /* Skip NULL textures */
3052 if (!This->stateBlock->textures[i]) {
3053 /* Map to -1, so the check below doesn't fail if a non-NULL
3054 * texture is set on this stage */
3055 TRACE("Mapping texture stage %d to -1\n", i);
3056 This->texUnitMap[i] = -1;
3061 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3062 if(This->texUnitMap[i] != tex) {
3063 This->texUnitMap[i] = tex;
3064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3065 markTextureStagesDirty(This, i);
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3075 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3076 This->updateStateBlock->pixelShader = pShader;
3077 This->updateStateBlock->changed.pixelShader = TRUE;
3078 This->updateStateBlock->set.pixelShader = TRUE;
3080 /* Handle recording of state blocks */
3081 if (This->isRecordingState) {
3082 TRACE("Recording... not performing anything\n");
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3090 if(pShader == oldShader) {
3091 TRACE("App is setting the old pixel shader over, nothing to do\n");
3095 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3098 /* Rebuild the texture unit mapping if nvrc's are supported */
3099 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3100 IWineD3DDeviceImpl_FindTexUnitMap(This);
3106 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 if (NULL == ppShader) {
3110 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3111 return WINED3DERR_INVALIDCALL;
3114 *ppShader = This->stateBlock->pixelShader;
3115 if (NULL != *ppShader) {
3116 IWineD3DPixelShader_AddRef(*ppShader);
3118 TRACE("(%p) : returning %p\n", This, *ppShader);
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3123 IWineD3DDevice *iface,
3125 CONST BOOL *srcData,
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 int i, cnt = min(count, MAX_CONST_B - start);
3131 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3132 iface, srcData, start, count);
3134 if (srcData == NULL || cnt < 0)
3135 return WINED3DERR_INVALIDCALL;
3137 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3138 for (i = 0; i < cnt; i++)
3139 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3141 for (i = start; i < cnt + start; ++i) {
3142 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3143 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3151 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3152 IWineD3DDevice *iface,
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 int cnt = min(count, MAX_CONST_B - start);
3160 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3161 iface, dstData, start, count);
3163 if (dstData == NULL || cnt < 0)
3164 return WINED3DERR_INVALIDCALL;
3166 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3171 IWineD3DDevice *iface,
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 int i, cnt = min(count, MAX_CONST_I - start);
3179 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3180 iface, srcData, start, count);
3182 if (srcData == NULL || cnt < 0)
3183 return WINED3DERR_INVALIDCALL;
3185 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3186 for (i = 0; i < cnt; i++)
3187 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3188 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3190 for (i = start; i < cnt + start; ++i) {
3191 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3192 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3200 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3201 IWineD3DDevice *iface,
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207 int cnt = min(count, MAX_CONST_I - start);
3209 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3210 iface, dstData, start, count);
3212 if (dstData == NULL || cnt < 0)
3213 return WINED3DERR_INVALIDCALL;
3215 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3219 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3220 IWineD3DDevice *iface,
3222 CONST float *srcData,
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3229 iface, srcData, start, count);
3231 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3232 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3233 return WINED3DERR_INVALIDCALL;
3235 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3237 for (i = 0; i < count; i++)
3238 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3239 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3242 for (i = start; i < count + start; ++i) {
3243 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3244 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3245 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3246 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3247 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3249 ptr->idx[ptr->count++] = i;
3250 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3252 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3261 IWineD3DDevice *iface,
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3269 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3270 iface, dstData, start, count);
3272 if (dstData == NULL || cnt < 0)
3273 return WINED3DERR_INVALIDCALL;
3275 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3279 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3281 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3282 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3284 DWORD DestFVF = dest->fvf;
3286 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3290 if (SrcFVF & WINED3DFVF_NORMAL) {
3291 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3294 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3295 ERR("Source has no position mask\n");
3296 return WINED3DERR_INVALIDCALL;
3299 /* We might access VBOs from this code, so hold the lock */
3302 if (dest->resource.allocatedMemory == NULL) {
3303 /* This may happen if we do direct locking into a vbo. Unlikely,
3304 * but theoretically possible(ddraw processvertices test)
3306 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3307 if(!dest->resource.allocatedMemory) {
3309 ERR("Out of memory\n");
3310 return E_OUTOFMEMORY;
3314 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3315 checkGLcall("glBindBufferARB");
3316 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3318 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3320 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3321 checkGLcall("glUnmapBufferARB");
3325 /* Get a pointer into the destination vbo(create one if none exists) and
3326 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3328 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3333 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3334 if(!dest_conv_addr) {
3335 ERR("Out of memory\n");
3336 /* Continue without storing converted vertices */
3338 dest_conv = dest_conv_addr;
3342 * a) WINED3DRS_CLIPPING is enabled
3343 * b) WINED3DVOP_CLIP is passed
3345 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3346 static BOOL warned = FALSE;
3348 * The clipping code is not quite correct. Some things need
3349 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3350 * so disable clipping for now.
3351 * (The graphics in Half-Life are broken, and my processvertices
3352 * test crashes with IDirect3DDevice3)
3358 FIXME("Clipping is broken and disabled for now\n");
3360 } else doClip = FALSE;
3361 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3363 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3366 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3367 WINED3DTS_PROJECTION,
3369 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3370 WINED3DTS_WORLDMATRIX(0),
3373 TRACE("View mat:\n");
3374 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);
3375 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);
3376 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);
3377 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);
3379 TRACE("Proj mat:\n");
3380 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);
3381 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);
3382 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);
3383 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);
3385 TRACE("World mat:\n");
3386 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);
3387 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);
3388 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);
3389 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);
3391 /* Get the viewport */
3392 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3393 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3394 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3396 multiply_matrix(&mat,&view_mat,&world_mat);
3397 multiply_matrix(&mat,&proj_mat,&mat);
3399 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3401 for (i = 0; i < dwCount; i+= 1) {
3402 unsigned int tex_index;
3404 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3405 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3406 /* The position first */
3408 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3410 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3412 /* Multiplication with world, view and projection matrix */
3413 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);
3414 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);
3415 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);
3416 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);
3418 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3420 /* WARNING: The following things are taken from d3d7 and were not yet checked
3421 * against d3d8 or d3d9!
3424 /* Clipping conditions: From
3425 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3427 * A vertex is clipped if it does not match the following requirements
3431 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3433 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3434 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3439 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3440 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3443 /* "Normal" viewport transformation (not clipped)
3444 * 1) The values are divided by rhw
3445 * 2) The y axis is negative, so multiply it with -1
3446 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3447 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3448 * 4) Multiply x with Width/2 and add Width/2
3449 * 5) The same for the height
3450 * 6) Add the viewpoint X and Y to the 2D coordinates and
3451 * The minimum Z value to z
3452 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3454 * Well, basically it's simply a linear transformation into viewport
3466 z *= vp.MaxZ - vp.MinZ;
3468 x += vp.Width / 2 + vp.X;
3469 y += vp.Height / 2 + vp.Y;
3474 /* That vertex got clipped
3475 * Contrary to OpenGL it is not dropped completely, it just
3476 * undergoes a different calculation.
3478 TRACE("Vertex got clipped\n");
3485 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3486 * outside of the main vertex buffer memory. That needs some more
3491 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3494 ( (float *) dest_ptr)[0] = x;
3495 ( (float *) dest_ptr)[1] = y;
3496 ( (float *) dest_ptr)[2] = z;
3497 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3499 dest_ptr += 3 * sizeof(float);
3501 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3502 dest_ptr += sizeof(float);
3507 ( (float *) dest_conv)[0] = x * w;
3508 ( (float *) dest_conv)[1] = y * w;
3509 ( (float *) dest_conv)[2] = z * w;
3510 ( (float *) dest_conv)[3] = w;
3512 dest_conv += 3 * sizeof(float);
3514 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3515 dest_conv += sizeof(float);
3519 if (DestFVF & WINED3DFVF_PSIZE) {
3520 dest_ptr += sizeof(DWORD);
3521 if(dest_conv) dest_conv += sizeof(DWORD);
3523 if (DestFVF & WINED3DFVF_NORMAL) {
3525 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3526 /* AFAIK this should go into the lighting information */
3527 FIXME("Didn't expect the destination to have a normal\n");
3528 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3530 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3534 if (DestFVF & WINED3DFVF_DIFFUSE) {
3536 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3538 static BOOL warned = FALSE;
3541 ERR("No diffuse color in source, but destination has one\n");
3545 *( (DWORD *) dest_ptr) = 0xffffffff;
3546 dest_ptr += sizeof(DWORD);
3549 *( (DWORD *) dest_conv) = 0xffffffff;
3550 dest_conv += sizeof(DWORD);
3554 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3556 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3557 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3558 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3559 dest_conv += sizeof(DWORD);
3564 if (DestFVF & WINED3DFVF_SPECULAR) {
3565 /* What's the color value in the feedback buffer? */
3567 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3569 static BOOL warned = FALSE;
3572 ERR("No specular color in source, but destination has one\n");
3576 *( (DWORD *) dest_ptr) = 0xFF000000;
3577 dest_ptr += sizeof(DWORD);
3580 *( (DWORD *) dest_conv) = 0xFF000000;
3581 dest_conv += sizeof(DWORD);
3585 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3587 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3588 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3589 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3590 dest_conv += sizeof(DWORD);
3595 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3597 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3598 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3600 ERR("No source texture, but destination requests one\n");
3601 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3602 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3605 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3607 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3614 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3615 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3616 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3617 dwCount * get_flexible_vertex_size(DestFVF),
3619 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3620 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3627 #undef copy_and_next
3629 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3631 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3632 WineDirect3DVertexStridedData strided;
3633 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3636 WARN("NULL source vertex buffer\n");
3637 return WINED3DERR_INVALIDCALL;
3639 /* We don't need the source vbo because this buffer is only used as
3640 * a source for ProcessVertices. Avoid wasting resources by converting the
3641 * buffer and loading the VBO
3644 TRACE("Releasing the source vbo, it won't be needed\n");
3646 if(!SrcImpl->resource.allocatedMemory) {
3647 /* Rescue the data from the buffer */
3649 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3650 if(!SrcImpl->resource.allocatedMemory) {
3651 ERR("Out of memory\n");
3652 return E_OUTOFMEMORY;
3656 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3657 checkGLcall("glBindBufferARB");
3659 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3661 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3664 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3665 checkGLcall("glUnmapBufferARB");
3670 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3671 checkGLcall("glBindBufferARB");
3672 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3673 checkGLcall("glDeleteBuffersARB");
3679 memset(&strided, 0, sizeof(strided));
3680 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3682 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3686 * Get / Set Texture Stage States
3687 * TODO: Verify against dx9 definitions
3689 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3693 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3695 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3697 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3698 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3699 This->updateStateBlock->textureState[Stage][Type] = Value;
3701 if (This->isRecordingState) {
3702 TRACE("Recording... not performing anything\n");
3706 /* Checked after the assignments to allow proper stateblock recording */
3707 if(oldValue == Value) {
3708 TRACE("App is setting the old value over, nothing to do\n");
3712 if(Stage > This->stateBlock->lowest_disabled_stage &&
3713 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3714 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3715 * Changes in other states are important on disabled stages too
3720 if(Type == WINED3DTSS_COLOROP) {
3723 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3724 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3725 * they have to be disabled
3727 * The current stage is dirtified below.
3729 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3730 TRACE("Additionally dirtifying stage %d\n", i);
3731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3733 This->stateBlock->lowest_disabled_stage = Stage;
3734 TRACE("New lowest disabled: %d\n", Stage);
3735 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3736 /* Previously disabled stage enabled. Stages above it may need enabling
3737 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3738 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3740 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3743 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3744 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3747 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3750 This->stateBlock->lowest_disabled_stage = i;
3751 TRACE("New lowest disabled: %d\n", i);
3753 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3754 /* TODO: Built a stage -> texture unit mapping for register combiners */
3758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3760 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3761 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3762 * will call FindTexUnitMap too.
3764 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3765 IWineD3DDeviceImpl_FindTexUnitMap(This);
3770 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3772 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3773 *pValue = This->updateStateBlock->textureState[Stage][Type];
3780 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3783 IWineD3DBaseTexture *oldTexture;
3785 oldTexture = This->updateStateBlock->textures[Stage];
3786 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3788 #if 0 /* TODO: check so vertex textures */
3789 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3790 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3795 if(pTexture != NULL) {
3796 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3798 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3799 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3800 return WINED3DERR_INVALIDCALL;
3802 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3805 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3806 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3808 This->updateStateBlock->set.textures[Stage] = TRUE;
3809 This->updateStateBlock->changed.textures[Stage] = TRUE;
3810 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3811 This->updateStateBlock->textures[Stage] = pTexture;
3813 /* Handle recording of state blocks */
3814 if (This->isRecordingState) {
3815 TRACE("Recording... not performing anything\n");
3819 if(oldTexture == pTexture) {
3820 TRACE("App is setting the same texture again, nothing to do\n");
3824 /** NOTE: MSDN says that setTexture increases the reference count,
3825 * and the the application nust set the texture back to null (or have a leaky application),
3826 * This means we should pass the refcount up to the parent
3827 *******************************/
3828 if (NULL != This->updateStateBlock->textures[Stage]) {
3829 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3830 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3832 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3833 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3834 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3835 * so the COLOROP and ALPHAOP have to be dirtified.
3837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3840 if(bindCount == 1) {
3841 new->baseTexture.sampler = Stage;
3843 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3847 if (NULL != oldTexture) {
3848 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3849 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3851 IWineD3DBaseTexture_Release(oldTexture);
3852 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3857 if(bindCount && old->baseTexture.sampler == Stage) {
3859 /* Have to do a search for the other sampler(s) where the texture is bound to
3860 * Shouldn't happen as long as apps bind a texture only to one stage
3862 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3863 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3864 if(This->updateStateBlock->textures[i] == oldTexture) {
3865 old->baseTexture.sampler = i;
3872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3874 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3875 * pixel shader is used
3877 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3878 IWineD3DDeviceImpl_FindTexUnitMap(This);
3884 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3886 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3888 *ppTexture=This->stateBlock->textures[Stage];
3890 IWineD3DBaseTexture_AddRef(*ppTexture);
3898 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3899 IWineD3DSurface **ppBackBuffer) {
3900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3901 IWineD3DSwapChain *swapChain;
3904 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3906 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3907 if (hr == WINED3D_OK) {
3908 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3909 IWineD3DSwapChain_Release(swapChain);
3911 *ppBackBuffer = NULL;
3916 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3918 WARN("(%p) : stub, calling idirect3d for now\n", This);
3919 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3922 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 IWineD3DSwapChain *swapChain;
3927 if(iSwapChain > 0) {
3928 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3929 if (hr == WINED3D_OK) {
3930 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3931 IWineD3DSwapChain_Release(swapChain);
3933 FIXME("(%p) Error getting display mode\n", This);
3936 /* Don't read the real display mode,
3937 but return the stored mode instead. X11 can't change the color
3938 depth, and some apps are pretty angry if they SetDisplayMode from
3939 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3941 Also don't relay to the swapchain because with ddraw it's possible
3942 that there isn't a swapchain at all */
3943 pMode->Width = This->ddraw_width;
3944 pMode->Height = This->ddraw_height;
3945 pMode->Format = This->ddraw_format;
3946 pMode->RefreshRate = 0;
3953 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3955 TRACE("(%p)->(%p)\n", This, hWnd);
3957 if(This->ddraw_fullscreen) {
3958 if(This->ddraw_window && This->ddraw_window != hWnd) {
3959 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
3961 if(hWnd && This->ddraw_window != hWnd) {
3962 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
3966 This->ddraw_window = hWnd;
3970 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 TRACE("(%p)->(%p)\n", This, hWnd);
3974 *hWnd = This->ddraw_window;
3979 * Stateblock related functions
3982 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
3983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3984 IWineD3DStateBlockImpl *object;
3985 HRESULT temp_result;
3988 TRACE("(%p)\n", This);
3990 if (This->isRecordingState) {
3991 return WINED3DERR_INVALIDCALL;
3994 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
3995 if (NULL == object ) {
3996 FIXME("(%p)Error allocating memory for stateblock\n", This);
3997 return E_OUTOFMEMORY;
3999 TRACE("(%p) created object %p\n", This, object);
4000 object->wineD3DDevice= This;
4001 /** FIXME: object->parent = parent; **/
4002 object->parent = NULL;
4003 object->blockType = WINED3DSBT_ALL;
4005 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4007 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4008 list_init(&object->lightMap[i]);
4011 temp_result = allocate_shader_constants(object);
4012 if (WINED3D_OK != temp_result)
4015 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4016 This->updateStateBlock = object;
4017 This->isRecordingState = TRUE;
4019 TRACE("(%p) recording stateblock %p\n",This , object);
4023 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4026 if (!This->isRecordingState) {
4027 FIXME("(%p) not recording! returning error\n", This);
4028 *ppStateBlock = NULL;
4029 return WINED3DERR_INVALIDCALL;
4032 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4033 This->isRecordingState = FALSE;
4034 This->updateStateBlock = This->stateBlock;
4035 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4036 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4037 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4042 * Scene related functions
4044 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4045 /* At the moment we have no need for any functionality at the beginning
4047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4048 TRACE("(%p)\n", This);
4051 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4052 return WINED3DERR_INVALIDCALL;
4054 This->inScene = TRUE;
4058 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4060 TRACE("(%p)\n", This);
4062 if(!This->inScene) {
4063 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4064 return WINED3DERR_INVALIDCALL;
4068 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4070 checkGLcall("glFlush");
4073 This->inScene = FALSE;
4077 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4078 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4079 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4081 IWineD3DSwapChain *swapChain = NULL;
4083 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4085 TRACE("(%p) Presenting the frame\n", This);
4087 for(i = 0 ; i < swapchains ; i ++) {
4089 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4090 TRACE("presentinng chain %d, %p\n", i, swapChain);
4091 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4092 IWineD3DSwapChain_Release(swapChain);
4098 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4099 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4102 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4103 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4104 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4105 GLbitfield glMask = 0;
4107 CONST WINED3DRECT* curRect;
4109 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4110 Count, pRects, Flags, Z, Stencil);
4115 glEnable(GL_SCISSOR_TEST);
4116 checkGLcall("glEnable GL_SCISSOR_TEST");
4117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4119 glDisable(GL_SCISSOR_TEST);
4120 checkGLcall("glEnable GL_SCISSOR_TEST");
4122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4124 if (Count > 0 && pRects) {
4130 /* Only set the values up once, as they are not changing */
4131 if (Flags & WINED3DCLEAR_STENCIL) {
4132 glClearStencil(Stencil);
4133 checkGLcall("glClearStencil");
4134 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4135 glStencilMask(0xFFFFFFFF);
4138 if (Flags & WINED3DCLEAR_ZBUFFER) {
4139 glDepthMask(GL_TRUE);
4141 checkGLcall("glClearDepth");
4142 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4146 if (Flags & WINED3DCLEAR_TARGET) {
4147 TRACE("Clearing screen with glClear to color %x\n", Color);
4148 glClearColor(D3DCOLOR_R(Color),
4152 checkGLcall("glClearColor");
4154 /* Clear ALL colors! */
4155 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4156 glMask = glMask | GL_COLOR_BUFFER_BIT;
4161 checkGLcall("glClear");
4163 /* Now process each rect in turn */
4164 for (i = 0; i < Count; i++) {
4165 /* Note gl uses lower left, width/height */
4166 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4167 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4168 curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2),
4169 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4171 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4172 * The rectangle is not cleared, no error is returned, but further rectanlges are
4173 * still cleared if they are valid
4175 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4176 TRACE("Rectangle with negative dimensions, ignoring\n");
4180 glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2,
4181 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4182 checkGLcall("glScissor");
4185 checkGLcall("glClear");
4189 /* Restore the old values (why..?) */
4190 if (Flags & WINED3DCLEAR_STENCIL) {
4191 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4193 if (Flags & WINED3DCLEAR_TARGET) {
4194 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4195 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4196 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4197 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4198 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4203 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4204 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4206 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
4213 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4214 UINT PrimitiveCount) {
4216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4217 This->stateBlock->streamIsUP = FALSE;
4219 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4220 debug_d3dprimitivetype(PrimitiveType),
4221 StartVertex, PrimitiveCount);
4223 if(This->stateBlock->loadBaseVertexIndex != 0) {
4224 This->stateBlock->loadBaseVertexIndex = 0;
4225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4227 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4228 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4229 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4233 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4234 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4235 WINED3DPRIMITIVETYPE PrimitiveType,
4236 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4240 IWineD3DIndexBuffer *pIB;
4241 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4244 pIB = This->stateBlock->pIndexData;
4245 This->stateBlock->streamIsUP = FALSE;
4246 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4248 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4249 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4250 minIndex, NumVertices, startIndex, primCount);
4252 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4253 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4259 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4260 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4264 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4265 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4271 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4272 UINT VertexStreamZeroStride) {
4273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4275 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4276 debug_d3dprimitivetype(PrimitiveType),
4277 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4279 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4280 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4281 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4282 This->stateBlock->streamIsUP = TRUE;
4283 This->stateBlock->loadBaseVertexIndex = 0;
4285 /* TODO: Only mark dirty if drawing from a different UP address */
4286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4288 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4289 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4291 /* MSDN specifies stream zero settings must be set to NULL */
4292 This->stateBlock->streamStride[0] = 0;
4293 This->stateBlock->streamSource[0] = NULL;
4295 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4296 * the new stream sources or use UP drawing again
4301 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4302 UINT MinVertexIndex, UINT NumVertices,
4303 UINT PrimitiveCount, CONST void* pIndexData,
4304 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4305 UINT VertexStreamZeroStride) {
4307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4309 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4310 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4311 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4312 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4314 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4320 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4321 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4322 This->stateBlock->streamIsUP = TRUE;
4323 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4325 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4326 This->stateBlock->baseVertexIndex = 0;
4327 This->stateBlock->loadBaseVertexIndex = 0;
4328 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4332 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4334 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4335 This->stateBlock->streamSource[0] = NULL;
4336 This->stateBlock->streamStride[0] = 0;
4337 This->stateBlock->pIndexData = NULL;
4338 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4339 * SetStreamSource to specify a vertex buffer
4345 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4348 /* Mark the state dirty until we have nicer tracking
4349 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4354 This->stateBlock->baseVertexIndex = 0;
4355 This->up_strided = DrawPrimStrideData;
4356 This->stateBlock->streamIsUP = TRUE;
4357 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4358 This->up_strided = NULL;
4361 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4362 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4364 HRESULT hr = WINED3D_OK;
4365 WINED3DRESOURCETYPE sourceType;
4366 WINED3DRESOURCETYPE destinationType;
4369 /* TODO: think about moving the code into IWineD3DBaseTexture */
4371 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4373 /* verify that the source and destination textures aren't NULL */
4374 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4375 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4376 This, pSourceTexture, pDestinationTexture);
4377 hr = WINED3DERR_INVALIDCALL;
4380 if (pSourceTexture == pDestinationTexture) {
4381 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4382 This, pSourceTexture, pDestinationTexture);
4383 hr = WINED3DERR_INVALIDCALL;
4385 /* Verify that the source and destination textures are the same type */
4386 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4387 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4389 if (sourceType != destinationType) {
4390 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4392 hr = WINED3DERR_INVALIDCALL;
4395 /* check that both textures have the identical numbers of levels */
4396 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4397 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4398 hr = WINED3DERR_INVALIDCALL;
4401 if (WINED3D_OK == hr) {
4403 /* Make sure that the destination texture is loaded */
4404 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4406 /* Update every surface level of the texture */
4407 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4409 switch (sourceType) {
4410 case WINED3DRTYPE_TEXTURE:
4412 IWineD3DSurface *srcSurface;
4413 IWineD3DSurface *destSurface;
4415 for (i = 0 ; i < levels ; ++i) {
4416 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4417 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4418 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4419 IWineD3DSurface_Release(srcSurface);
4420 IWineD3DSurface_Release(destSurface);
4421 if (WINED3D_OK != hr) {
4422 WARN("(%p) : Call to update surface failed\n", This);
4428 case WINED3DRTYPE_CUBETEXTURE:
4430 IWineD3DSurface *srcSurface;
4431 IWineD3DSurface *destSurface;
4432 WINED3DCUBEMAP_FACES faceType;
4434 for (i = 0 ; i < levels ; ++i) {
4435 /* Update each cube face */
4436 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4437 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4438 if (WINED3D_OK != hr) {
4439 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4441 TRACE("Got srcSurface %p\n", srcSurface);
4443 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4444 if (WINED3D_OK != hr) {
4445 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4447 TRACE("Got desrSurface %p\n", destSurface);
4449 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4450 IWineD3DSurface_Release(srcSurface);
4451 IWineD3DSurface_Release(destSurface);
4452 if (WINED3D_OK != hr) {
4453 WARN("(%p) : Call to update surface failed\n", This);
4460 #if 0 /* TODO: Add support for volume textures */
4461 case WINED3DRTYPE_VOLUMETEXTURE:
4463 IWineD3DVolume srcVolume = NULL;
4464 IWineD3DSurface destVolume = NULL;
4466 for (i = 0 ; i < levels ; ++i) {
4467 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4468 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4469 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4470 IWineD3DVolume_Release(srcSurface);
4471 IWineD3DVolume_Release(destSurface);
4472 if (WINED3D_OK != hr) {
4473 WARN("(%p) : Call to update volume failed\n", This);
4481 FIXME("(%p) : Unsupported source and destination type\n", This);
4482 hr = WINED3DERR_INVALIDCALL;
4489 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4490 IWineD3DSwapChain *swapChain;
4492 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4493 if(hr == WINED3D_OK) {
4494 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4495 IWineD3DSwapChain_Release(swapChain);
4500 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502 /* return a sensible default */
4504 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4505 FIXME("(%p) : stub\n", This);
4509 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4512 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4513 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4514 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4515 return WINED3DERR_INVALIDCALL;
4517 for (j = 0; j < 256; ++j) {
4518 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4519 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4520 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4521 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4523 TRACE("(%p) : returning\n", This);
4527 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4531 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4532 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4533 return WINED3DERR_INVALIDCALL;
4535 for (j = 0; j < 256; ++j) {
4536 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4537 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4538 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4539 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4541 TRACE("(%p) : returning\n", This);
4545 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4547 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4548 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4549 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4550 return WINED3DERR_INVALIDCALL;
4552 /*TODO: stateblocks */
4553 This->currentPalette = PaletteNumber;
4554 TRACE("(%p) : returning\n", This);
4558 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 if (PaletteNumber == NULL) {
4561 WARN("(%p) : returning Invalid Call\n", This);
4562 return WINED3DERR_INVALIDCALL;
4564 /*TODO: stateblocks */
4565 *PaletteNumber = This->currentPalette;
4566 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4570 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 static BOOL showFixmes = TRUE;
4574 FIXME("(%p) : stub\n", This);
4578 This->softwareVertexProcessing = bSoftware;
4583 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 static BOOL showFixmes = TRUE;
4587 FIXME("(%p) : stub\n", This);
4590 return This->softwareVertexProcessing;
4594 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4596 IWineD3DSwapChain *swapChain;
4599 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4601 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4602 if(hr == WINED3D_OK){
4603 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4604 IWineD3DSwapChain_Release(swapChain);
4606 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4612 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 static BOOL showfixmes = TRUE;
4615 if(nSegments != 0.0f) {
4617 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4624 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 static BOOL showfixmes = TRUE;
4628 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4634 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4636 /** TODO: remove casts to IWineD3DSurfaceImpl
4637 * NOTE: move code to surface to accomplish this
4638 ****************************************/
4639 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4640 int srcWidth, srcHeight;
4641 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4642 WINED3DFORMAT destFormat, srcFormat;
4644 int srcLeft, destLeft, destTop;
4645 WINED3DPOOL srcPool, destPool;
4647 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4648 glDescriptor *glDescription = NULL;
4650 WINED3DSURFACE_DESC winedesc;
4652 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4653 memset(&winedesc, 0, sizeof(winedesc));
4654 winedesc.Width = &srcSurfaceWidth;
4655 winedesc.Height = &srcSurfaceHeight;
4656 winedesc.Pool = &srcPool;
4657 winedesc.Format = &srcFormat;
4659 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4661 winedesc.Width = &destSurfaceWidth;
4662 winedesc.Height = &destSurfaceHeight;
4663 winedesc.Pool = &destPool;
4664 winedesc.Format = &destFormat;
4665 winedesc.Size = &destSize;
4667 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4669 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4670 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4671 return WINED3DERR_INVALIDCALL;
4674 if (destFormat == WINED3DFMT_UNKNOWN) {
4675 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4676 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4678 /* Get the update surface description */
4679 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4683 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4684 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4685 checkGLcall("glActiveTextureARB");
4688 /* Make sure the surface is loaded and up to date */
4689 IWineD3DSurface_PreLoad(pDestinationSurface);
4691 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4693 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4694 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4695 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4696 srcLeft = pSourceRect ? pSourceRect->left : 0;
4697 destLeft = pDestPoint ? pDestPoint->x : 0;
4698 destTop = pDestPoint ? pDestPoint->y : 0;
4701 /* This function doesn't support compressed textures
4702 the pitch is just bytesPerPixel * width */
4703 if(srcWidth != srcSurfaceWidth || srcLeft ){
4704 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4705 offset += srcLeft * pSrcSurface->bytesPerPixel;
4706 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4708 /* TODO DXT formats */
4710 if(pSourceRect != NULL && pSourceRect->top != 0){
4711 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4713 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4715 ,glDescription->level
4720 ,glDescription->glFormat
4721 ,glDescription->glType
4722 ,IWineD3DSurface_GetData(pSourceSurface)
4726 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4728 /* need to lock the surface to get the data */
4729 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4732 /* TODO: Cube and volume support */
4734 /* not a whole row so we have to do it a line at a time */
4737 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4738 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4740 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4742 glTexSubImage2D(glDescription->target
4743 ,glDescription->level
4748 ,glDescription->glFormat
4749 ,glDescription->glType
4750 ,data /* could be quicker using */
4755 } else { /* Full width, so just write out the whole texture */
4757 if (WINED3DFMT_DXT1 == destFormat ||
4758 WINED3DFMT_DXT2 == destFormat ||
4759 WINED3DFMT_DXT3 == destFormat ||
4760 WINED3DFMT_DXT4 == destFormat ||
4761 WINED3DFMT_DXT5 == destFormat) {
4762 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4763 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4764 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4765 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4766 } if (destFormat != srcFormat) {
4767 FIXME("Updating mixed format compressed texture is not curretly support\n");
4769 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4770 glDescription->level,
4771 glDescription->glFormatInternal,
4776 IWineD3DSurface_GetData(pSourceSurface));
4779 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4784 glTexSubImage2D(glDescription->target
4785 ,glDescription->level
4790 ,glDescription->glFormat
4791 ,glDescription->glType
4792 ,IWineD3DSurface_GetData(pSourceSurface)
4796 checkGLcall("glTexSubImage2D");
4800 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4806 /* Implementation details at http://developer.nvidia.com/attach/6494
4808 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4809 hmm.. no longer supported use
4810 OpenGL evaluators or tessellate surfaces within your application.
4813 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4814 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4817 FIXME("(%p) : Stub\n", This);
4822 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4823 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4826 FIXME("(%p) : Stub\n", This);
4830 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4832 TRACE("(%p) Handle(%d)\n", This, Handle);
4833 FIXME("(%p) : Stub\n", This);
4837 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4839 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4841 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4843 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4844 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4845 return WINED3DERR_INVALIDCALL;
4848 /* Just forward this to the DirectDraw blitting engine */
4849 memset(&BltFx, 0, sizeof(BltFx));
4850 BltFx.dwSize = sizeof(BltFx);
4851 BltFx.u5.dwFillColor = color;
4852 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4855 /* rendertarget and deptth stencil functions */
4856 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4860 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4861 return WINED3DERR_INVALIDCALL;
4864 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4865 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4866 /* Note inc ref on returned surface */
4867 if(*ppRenderTarget != NULL)
4868 IWineD3DSurface_AddRef(*ppRenderTarget);
4872 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4874 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4875 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4876 IWineD3DSwapChainImpl *Swapchain;
4879 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4881 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4882 if(hr != WINED3D_OK) {
4883 ERR("Can't get the swapchain\n");
4887 /* Make sure to release the swapchain */
4888 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4890 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4891 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4892 return WINED3DERR_INVALIDCALL;
4894 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4895 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4896 return WINED3DERR_INVALIDCALL;
4899 if(Swapchain->frontBuffer != Front) {
4900 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4902 if(Swapchain->frontBuffer)
4903 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4904 Swapchain->frontBuffer = Front;
4906 if(Swapchain->frontBuffer) {
4907 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4911 if(Back && !Swapchain->backBuffer) {
4912 /* We need memory for the back buffer array - only one back buffer this way */
4913 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4914 if(!Swapchain->backBuffer) {
4915 ERR("Out of memory\n");
4916 return E_OUTOFMEMORY;
4920 if(Swapchain->backBuffer[0] != Back) {
4921 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4923 if(!Swapchain->backBuffer[0]) {
4924 /* GL was told to draw to the front buffer at creation,
4927 glDrawBuffer(GL_BACK);
4928 checkGLcall("glDrawBuffer(GL_BACK)");
4929 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4930 Swapchain->presentParms.BackBufferCount = 1;
4932 /* That makes problems - disable for now */
4933 /* glDrawBuffer(GL_FRONT); */
4934 checkGLcall("glDrawBuffer(GL_FRONT)");
4935 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4936 Swapchain->presentParms.BackBufferCount = 0;
4940 if(Swapchain->backBuffer[0])
4941 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4942 Swapchain->backBuffer[0] = Back;
4944 if(Swapchain->backBuffer[0]) {
4945 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4947 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
4955 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4957 *ppZStencilSurface = This->depthStencilBuffer;
4958 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
4960 if(*ppZStencilSurface != NULL) {
4961 /* Note inc ref on returned surface */
4962 IWineD3DSurface_AddRef(*ppZStencilSurface);
4967 static void bind_fbo(IWineD3DDevice *iface) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4971 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
4972 checkGLcall("glGenFramebuffersEXT()");
4974 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
4975 checkGLcall("glBindFramebuffer()");
4978 /* TODO: Handle stencil attachments */
4979 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
4980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4981 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
4983 This->depth_copy_state = WINED3D_DCS_NO_COPY;
4987 if (depth_stencil_impl) {
4988 GLenum texttarget, target;
4989 GLint old_binding = 0;
4991 IWineD3DSurface_PreLoad(depth_stencil);
4992 texttarget = depth_stencil_impl->glDescription.target;
4993 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
4995 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
4996 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
4997 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4998 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4999 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5000 glBindTexture(target, old_binding);
5002 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5003 checkGLcall("glFramebufferTexture2DEXT()");
5005 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5006 checkGLcall("glFramebufferTexture2DEXT()");
5009 if (!This->render_offscreen) {
5010 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5011 checkGLcall("glBindFramebuffer()");
5015 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5017 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5019 if (idx >= GL_LIMITS(buffers)) {
5020 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5026 GLenum texttarget, target;
5027 GLint old_binding = 0;
5029 IWineD3DSurface_PreLoad(render_target);
5030 texttarget = rtimpl->glDescription.target;
5031 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5033 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5034 glBindTexture(target, rtimpl->glDescription.textureName);
5035 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5036 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5037 glBindTexture(target, old_binding);
5039 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5040 checkGLcall("glFramebufferTexture2DEXT()");
5042 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5044 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5045 checkGLcall("glFramebufferTexture2DEXT()");
5047 This->draw_buffers[idx] = GL_NONE;
5050 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5051 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5052 checkGLcall("glDrawBuffers()");
5055 if (!This->render_offscreen) {
5056 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5057 checkGLcall("glBindFramebuffer()");
5061 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 WINED3DVIEWPORT viewport;
5065 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5067 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5068 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5069 return WINED3DERR_INVALIDCALL;
5072 /* MSDN says that null disables the render target
5073 but a device must always be associated with a render target
5074 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5076 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5079 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5080 FIXME("Trying to set render target 0 to NULL\n");
5081 return WINED3DERR_INVALIDCALL;
5083 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5084 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);
5085 return WINED3DERR_INVALIDCALL;
5088 /* If we are trying to set what we already have, don't bother */
5089 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5090 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5093 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5094 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5095 This->render_targets[RenderTargetIndex] = pRenderTarget;
5097 /* Render target 0 is special */
5098 if(RenderTargetIndex == 0) {
5099 /* Finally, reset the viewport as the MSDN states. */
5100 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5101 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5104 viewport.MaxZ = 1.0f;
5105 viewport.MinZ = 0.0f;
5106 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5108 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5110 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5111 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5113 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5115 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5116 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5121 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5123 HRESULT hr = WINED3D_OK;
5124 IWineD3DSurface *tmp;
5126 TRACE("(%p) Swapping z-buffer\n",This);
5128 if (pNewZStencil == This->stencilBufferTarget) {
5129 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5131 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5132 * depending on the renter target implementation being used.
5133 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5134 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5135 * stencil buffer and incure an extra memory overhead
5136 ******************************************************/
5139 tmp = This->stencilBufferTarget;
5140 This->stencilBufferTarget = pNewZStencil;
5141 /* should we be calling the parent or the wined3d surface? */
5142 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5143 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5145 /** TODO: glEnable/glDisable on depth/stencil depending on
5146 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5147 **********************************************************/
5148 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5149 set_depth_stencil_fbo(iface, pNewZStencil);
5156 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5157 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5159 /* TODO: the use of Impl is deprecated. */
5160 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5162 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5164 /* some basic validation checks */
5165 if(This->cursorTexture) {
5167 glDeleteTextures(1, &This->cursorTexture);
5169 This->cursorTexture = 0;
5173 /* MSDN: Cursor must be A8R8G8B8 */
5174 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5175 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5176 return WINED3DERR_INVALIDCALL;
5179 /* MSDN: Cursor must be smaller than the display mode */
5180 if(pSur->currentDesc.Width > This->ddraw_width ||
5181 pSur->currentDesc.Height > This->ddraw_height) {
5182 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);
5183 return WINED3DERR_INVALIDCALL;
5186 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5187 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5188 * Texture and Blitting code to draw the cursor
5190 pSur->Flags |= SFLAG_FORCELOAD;
5191 IWineD3DSurface_PreLoad(pCursorBitmap);
5192 pSur->Flags &= ~SFLAG_FORCELOAD;
5193 /* Do not store the surface's pointer because the application may release
5194 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5195 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5197 This->cursorTexture = pSur->glDescription.textureName;
5198 This->cursorWidth = pSur->currentDesc.Width;
5199 This->cursorHeight = pSur->currentDesc.Height;
5200 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5203 This->xHotSpot = XHotSpot;
5204 This->yHotSpot = YHotSpot;
5208 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5210 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5212 This->xScreenSpace = XScreenSpace;
5213 This->yScreenSpace = YScreenSpace;
5219 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5221 BOOL oldVisible = This->bCursorVisible;
5222 TRACE("(%p) : visible(%d)\n", This, bShow);
5224 if(This->cursorTexture)
5225 This->bCursorVisible = bShow;
5230 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5232 TRACE("(%p) : state (%u)\n", This, This->state);
5233 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5234 switch (This->state) {
5237 case WINED3DERR_DEVICELOST:
5239 ResourceList *resourceList = This->resources;
5240 while (NULL != resourceList) {
5241 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5242 return WINED3DERR_DEVICENOTRESET;
5243 resourceList = resourceList->next;
5245 return WINED3DERR_DEVICELOST;
5247 case WINED3DERR_DRIVERINTERNALERROR:
5248 return WINED3DERR_DRIVERINTERNALERROR;
5252 return WINED3DERR_DRIVERINTERNALERROR;
5256 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5258 /** FIXME: Resource tracking needs to be done,
5259 * The closes we can do to this is set the priorities of all managed textures low
5260 * and then reset them.
5261 ***********************************************************/
5262 FIXME("(%p) : stub\n", This);
5266 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5267 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5269 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5270 if(surface->Flags & SFLAG_DIBSECTION) {
5271 /* Release the DC */
5272 SelectObject(surface->hDC, surface->dib.holdbitmap);
5273 DeleteDC(surface->hDC);
5274 /* Release the DIB section */
5275 DeleteObject(surface->dib.DIBsection);
5276 surface->dib.bitmap_data = NULL;
5277 surface->resource.allocatedMemory = NULL;
5278 surface->Flags &= ~SFLAG_DIBSECTION;
5280 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5281 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5282 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5283 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5284 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5286 surface->pow2Width = surface->pow2Height = 1;
5287 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5288 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5290 if(surface->glDescription.textureName) {
5292 glDeleteTextures(1, &surface->glDescription.textureName);
5294 surface->glDescription.textureName = 0;
5296 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5297 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5298 surface->Flags |= SFLAG_NONPOW2;
5300 surface->Flags &= ~SFLAG_NONPOW2;
5302 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5303 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5306 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5308 IWineD3DSwapChainImpl *swapchain;
5310 BOOL DisplayModeChanged = FALSE;
5311 WINED3DDISPLAYMODE mode;
5312 TRACE("(%p)\n", This);
5314 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5316 ERR("Failed to get the first implicit swapchain\n");
5320 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5321 * on an existing gl context, so there's no real need for recreation.
5323 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5325 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5327 TRACE("New params:\n");
5328 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5329 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5330 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5331 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5332 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5333 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5334 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5335 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5336 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5337 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5338 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5339 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5340 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5342 /* No special treatment of these parameters. Just store them */
5343 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5344 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5345 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5346 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5348 /* What to do about these? */
5349 if(pPresentationParameters->BackBufferCount != 0 &&
5350 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5351 ERR("Cannot change the back buffer count yet\n");
5353 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5354 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5355 ERR("Cannot change the back buffer format yet\n");
5357 if(pPresentationParameters->hDeviceWindow != NULL &&
5358 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5359 ERR("Cannot change the device window yet\n");
5361 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5362 ERR("What do do about a changed auto depth stencil parameter?\n");
5365 if(pPresentationParameters->Windowed) {
5366 mode.Width = swapchain->orig_width;
5367 mode.Height = swapchain->orig_height;
5368 mode.RefreshRate = 0;
5369 mode.Format = swapchain->presentParms.BackBufferFormat;
5371 mode.Width = pPresentationParameters->BackBufferWidth;
5372 mode.Height = pPresentationParameters->BackBufferHeight;
5373 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5374 mode.Format = swapchain->presentParms.BackBufferFormat;
5377 /* Should Width == 800 && Height == 0 set 800x600? */
5378 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5379 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5380 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5387 vp.Width = pPresentationParameters->BackBufferWidth;
5388 vp.Height = pPresentationParameters->BackBufferHeight;
5392 if(!pPresentationParameters->Windowed) {
5393 DisplayModeChanged = TRUE;
5395 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5396 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5398 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5399 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5400 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5403 /* Now set the new viewport */
5404 IWineD3DDevice_SetViewport(iface, &vp);
5407 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5408 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5409 DisplayModeChanged) {
5411 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5412 if(!pPresentationParameters->Windowed) {
5413 IWineD3DDevice_SetFullscreen(iface, TRUE);
5416 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5418 /* Switching out of fullscreen mode? First set the original res, then change the window */
5419 if(pPresentationParameters->Windowed) {
5420 IWineD3DDevice_SetFullscreen(iface, FALSE);
5422 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5425 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5429 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5431 /** FIXME: always true at the moment **/
5432 if(!bEnableDialogs) {
5433 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5439 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5441 TRACE("(%p) : pParameters %p\n", This, pParameters);
5443 *pParameters = This->createParms;
5447 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5448 IWineD3DSwapChain *swapchain;
5449 HRESULT hrc = WINED3D_OK;
5451 TRACE("Relaying to swapchain\n");
5453 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5454 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5455 IWineD3DSwapChain_Release(swapchain);
5460 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5461 IWineD3DSwapChain *swapchain;
5462 HRESULT hrc = WINED3D_OK;
5464 TRACE("Relaying to swapchain\n");
5466 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5467 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5468 IWineD3DSwapChain_Release(swapchain);
5474 /** ********************************************************
5475 * Notification functions
5476 ** ********************************************************/
5477 /** This function must be called in the release of a resource when ref == 0,
5478 * the contents of resource must still be correct,
5479 * any handels to other resource held by the caller must be closed
5480 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5481 *****************************************************/
5482 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5484 ResourceList* resourceList;
5486 TRACE("(%p) : resource %p\n", This, resource);
5488 EnterCriticalSection(&resourceStoreCriticalSection);
5490 /* add a new texture to the frot of the linked list */
5491 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5492 resourceList->resource = resource;
5494 /* Get the old head */
5495 resourceList->next = This->resources;
5497 This->resources = resourceList;
5498 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5501 LeaveCriticalSection(&resourceStoreCriticalSection);
5506 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5508 ResourceList* resourceList = NULL;
5509 ResourceList* previousResourceList = NULL;
5511 TRACE("(%p) : resource %p\n", This, resource);
5514 EnterCriticalSection(&resourceStoreCriticalSection);
5516 resourceList = This->resources;
5518 while (resourceList != NULL) {
5519 if(resourceList->resource == resource) break;
5520 previousResourceList = resourceList;
5521 resourceList = resourceList->next;
5524 if (resourceList == NULL) {
5525 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5527 LeaveCriticalSection(&resourceStoreCriticalSection);
5531 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5533 /* make sure we don't leave a hole in the list */
5534 if (previousResourceList != NULL) {
5535 previousResourceList->next = resourceList->next;
5537 This->resources = resourceList->next;
5541 LeaveCriticalSection(&resourceStoreCriticalSection);
5547 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5551 TRACE("(%p) : resource %p\n", This, resource);
5552 switch(IWineD3DResource_GetType(resource)){
5553 case WINED3DRTYPE_SURFACE:
5554 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5556 case WINED3DRTYPE_TEXTURE:
5557 case WINED3DRTYPE_CUBETEXTURE:
5558 case WINED3DRTYPE_VOLUMETEXTURE:
5559 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5560 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5561 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5562 This->stateBlock->textures[counter] = NULL;
5564 if (This->updateStateBlock != This->stateBlock ){
5565 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5566 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5567 This->updateStateBlock->textures[counter] = NULL;
5572 case WINED3DRTYPE_VOLUME:
5573 /* TODO: nothing really? */
5575 case WINED3DRTYPE_VERTEXBUFFER:
5576 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5579 TRACE("Cleaning up stream pointers\n");
5581 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5582 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5583 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5585 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5586 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5587 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5588 This->updateStateBlock->streamSource[streamNumber] = 0;
5589 /* Set changed flag? */
5592 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) */
5593 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5594 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5595 This->stateBlock->streamSource[streamNumber] = 0;
5598 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5599 else { /* This shouldn't happen */
5600 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5607 case WINED3DRTYPE_INDEXBUFFER:
5608 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5609 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5610 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5611 This->updateStateBlock->pIndexData = NULL;
5614 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5615 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5616 This->stateBlock->pIndexData = NULL;
5622 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5627 /* Remove the resoruce from the resourceStore */
5628 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5630 TRACE("Resource released\n");
5634 /**********************************************************
5635 * IWineD3DDevice VTbl follows
5636 **********************************************************/
5638 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5640 /*** IUnknown methods ***/
5641 IWineD3DDeviceImpl_QueryInterface,
5642 IWineD3DDeviceImpl_AddRef,
5643 IWineD3DDeviceImpl_Release,
5644 /*** IWineD3DDevice methods ***/
5645 IWineD3DDeviceImpl_GetParent,
5646 /*** Creation methods**/
5647 IWineD3DDeviceImpl_CreateVertexBuffer,
5648 IWineD3DDeviceImpl_CreateIndexBuffer,
5649 IWineD3DDeviceImpl_CreateStateBlock,
5650 IWineD3DDeviceImpl_CreateSurface,
5651 IWineD3DDeviceImpl_CreateTexture,
5652 IWineD3DDeviceImpl_CreateVolumeTexture,
5653 IWineD3DDeviceImpl_CreateVolume,
5654 IWineD3DDeviceImpl_CreateCubeTexture,
5655 IWineD3DDeviceImpl_CreateQuery,
5656 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5657 IWineD3DDeviceImpl_CreateVertexDeclaration,
5658 IWineD3DDeviceImpl_CreateVertexShader,
5659 IWineD3DDeviceImpl_CreatePixelShader,
5660 IWineD3DDeviceImpl_CreatePalette,
5661 /*** Odd functions **/
5662 IWineD3DDeviceImpl_Init3D,
5663 IWineD3DDeviceImpl_Uninit3D,
5664 IWineD3DDeviceImpl_SetFullscreen,
5665 IWineD3DDeviceImpl_EvictManagedResources,
5666 IWineD3DDeviceImpl_GetAvailableTextureMem,
5667 IWineD3DDeviceImpl_GetBackBuffer,
5668 IWineD3DDeviceImpl_GetCreationParameters,
5669 IWineD3DDeviceImpl_GetDeviceCaps,
5670 IWineD3DDeviceImpl_GetDirect3D,
5671 IWineD3DDeviceImpl_GetDisplayMode,
5672 IWineD3DDeviceImpl_SetDisplayMode,
5673 IWineD3DDeviceImpl_GetHWND,
5674 IWineD3DDeviceImpl_SetHWND,
5675 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5676 IWineD3DDeviceImpl_GetRasterStatus,
5677 IWineD3DDeviceImpl_GetSwapChain,
5678 IWineD3DDeviceImpl_Reset,
5679 IWineD3DDeviceImpl_SetDialogBoxMode,
5680 IWineD3DDeviceImpl_SetCursorProperties,
5681 IWineD3DDeviceImpl_SetCursorPosition,
5682 IWineD3DDeviceImpl_ShowCursor,
5683 IWineD3DDeviceImpl_TestCooperativeLevel,
5684 /*** Getters and setters **/
5685 IWineD3DDeviceImpl_SetClipPlane,
5686 IWineD3DDeviceImpl_GetClipPlane,
5687 IWineD3DDeviceImpl_SetClipStatus,
5688 IWineD3DDeviceImpl_GetClipStatus,
5689 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5690 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5691 IWineD3DDeviceImpl_SetDepthStencilSurface,
5692 IWineD3DDeviceImpl_GetDepthStencilSurface,
5693 IWineD3DDeviceImpl_SetFVF,
5694 IWineD3DDeviceImpl_GetFVF,
5695 IWineD3DDeviceImpl_SetGammaRamp,
5696 IWineD3DDeviceImpl_GetGammaRamp,
5697 IWineD3DDeviceImpl_SetIndices,
5698 IWineD3DDeviceImpl_GetIndices,
5699 IWineD3DDeviceImpl_SetBasevertexIndex,
5700 IWineD3DDeviceImpl_SetLight,
5701 IWineD3DDeviceImpl_GetLight,
5702 IWineD3DDeviceImpl_SetLightEnable,
5703 IWineD3DDeviceImpl_GetLightEnable,
5704 IWineD3DDeviceImpl_SetMaterial,
5705 IWineD3DDeviceImpl_GetMaterial,
5706 IWineD3DDeviceImpl_SetNPatchMode,
5707 IWineD3DDeviceImpl_GetNPatchMode,
5708 IWineD3DDeviceImpl_SetPaletteEntries,
5709 IWineD3DDeviceImpl_GetPaletteEntries,
5710 IWineD3DDeviceImpl_SetPixelShader,
5711 IWineD3DDeviceImpl_GetPixelShader,
5712 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5713 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5714 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5715 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5716 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5717 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5718 IWineD3DDeviceImpl_SetRenderState,
5719 IWineD3DDeviceImpl_GetRenderState,
5720 IWineD3DDeviceImpl_SetRenderTarget,
5721 IWineD3DDeviceImpl_GetRenderTarget,
5722 IWineD3DDeviceImpl_SetFrontBackBuffers,
5723 IWineD3DDeviceImpl_SetSamplerState,
5724 IWineD3DDeviceImpl_GetSamplerState,
5725 IWineD3DDeviceImpl_SetScissorRect,
5726 IWineD3DDeviceImpl_GetScissorRect,
5727 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5728 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5729 IWineD3DDeviceImpl_SetStreamSource,
5730 IWineD3DDeviceImpl_GetStreamSource,
5731 IWineD3DDeviceImpl_SetStreamSourceFreq,
5732 IWineD3DDeviceImpl_GetStreamSourceFreq,
5733 IWineD3DDeviceImpl_SetTexture,
5734 IWineD3DDeviceImpl_GetTexture,
5735 IWineD3DDeviceImpl_SetTextureStageState,
5736 IWineD3DDeviceImpl_GetTextureStageState,
5737 IWineD3DDeviceImpl_SetTransform,
5738 IWineD3DDeviceImpl_GetTransform,
5739 IWineD3DDeviceImpl_SetVertexDeclaration,
5740 IWineD3DDeviceImpl_GetVertexDeclaration,
5741 IWineD3DDeviceImpl_SetVertexShader,
5742 IWineD3DDeviceImpl_GetVertexShader,
5743 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5744 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5745 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5746 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5747 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5748 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5749 IWineD3DDeviceImpl_SetViewport,
5750 IWineD3DDeviceImpl_GetViewport,
5751 IWineD3DDeviceImpl_MultiplyTransform,
5752 IWineD3DDeviceImpl_ValidateDevice,
5753 IWineD3DDeviceImpl_ProcessVertices,
5754 /*** State block ***/
5755 IWineD3DDeviceImpl_BeginStateBlock,
5756 IWineD3DDeviceImpl_EndStateBlock,
5757 /*** Scene management ***/
5758 IWineD3DDeviceImpl_BeginScene,
5759 IWineD3DDeviceImpl_EndScene,
5760 IWineD3DDeviceImpl_Present,
5761 IWineD3DDeviceImpl_Clear,
5763 IWineD3DDeviceImpl_DrawPrimitive,
5764 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5765 IWineD3DDeviceImpl_DrawPrimitiveUP,
5766 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5767 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5768 IWineD3DDeviceImpl_DrawRectPatch,
5769 IWineD3DDeviceImpl_DrawTriPatch,
5770 IWineD3DDeviceImpl_DeletePatch,
5771 IWineD3DDeviceImpl_ColorFill,
5772 IWineD3DDeviceImpl_UpdateTexture,
5773 IWineD3DDeviceImpl_UpdateSurface,
5774 IWineD3DDeviceImpl_GetFrontBufferData,
5775 /*** object tracking ***/
5776 IWineD3DDeviceImpl_ResourceReleased
5780 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5781 WINED3DRS_ALPHABLENDENABLE ,
5782 WINED3DRS_ALPHAFUNC ,
5783 WINED3DRS_ALPHAREF ,
5784 WINED3DRS_ALPHATESTENABLE ,
5786 WINED3DRS_COLORWRITEENABLE ,
5787 WINED3DRS_DESTBLEND ,
5788 WINED3DRS_DITHERENABLE ,
5789 WINED3DRS_FILLMODE ,
5790 WINED3DRS_FOGDENSITY ,
5792 WINED3DRS_FOGSTART ,
5793 WINED3DRS_LASTPIXEL ,
5794 WINED3DRS_SHADEMODE ,
5795 WINED3DRS_SRCBLEND ,
5796 WINED3DRS_STENCILENABLE ,
5797 WINED3DRS_STENCILFAIL ,
5798 WINED3DRS_STENCILFUNC ,
5799 WINED3DRS_STENCILMASK ,
5800 WINED3DRS_STENCILPASS ,
5801 WINED3DRS_STENCILREF ,
5802 WINED3DRS_STENCILWRITEMASK ,
5803 WINED3DRS_STENCILZFAIL ,
5804 WINED3DRS_TEXTUREFACTOR ,
5815 WINED3DRS_ZWRITEENABLE
5818 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5819 WINED3DTSS_ADDRESSW ,
5820 WINED3DTSS_ALPHAARG0 ,
5821 WINED3DTSS_ALPHAARG1 ,
5822 WINED3DTSS_ALPHAARG2 ,
5823 WINED3DTSS_ALPHAOP ,
5824 WINED3DTSS_BUMPENVLOFFSET ,
5825 WINED3DTSS_BUMPENVLSCALE ,
5826 WINED3DTSS_BUMPENVMAT00 ,
5827 WINED3DTSS_BUMPENVMAT01 ,
5828 WINED3DTSS_BUMPENVMAT10 ,
5829 WINED3DTSS_BUMPENVMAT11 ,
5830 WINED3DTSS_COLORARG0 ,
5831 WINED3DTSS_COLORARG1 ,
5832 WINED3DTSS_COLORARG2 ,
5833 WINED3DTSS_COLOROP ,
5834 WINED3DTSS_RESULTARG ,
5835 WINED3DTSS_TEXCOORDINDEX ,
5836 WINED3DTSS_TEXTURETRANSFORMFLAGS
5839 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5840 WINED3DSAMP_ADDRESSU ,
5841 WINED3DSAMP_ADDRESSV ,
5842 WINED3DSAMP_ADDRESSW ,
5843 WINED3DSAMP_BORDERCOLOR ,
5844 WINED3DSAMP_MAGFILTER ,
5845 WINED3DSAMP_MINFILTER ,
5846 WINED3DSAMP_MIPFILTER ,
5847 WINED3DSAMP_MIPMAPLODBIAS ,
5848 WINED3DSAMP_MAXMIPLEVEL ,
5849 WINED3DSAMP_MAXANISOTROPY ,
5850 WINED3DSAMP_SRGBTEXTURE ,
5851 WINED3DSAMP_ELEMENTINDEX
5854 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5856 WINED3DRS_AMBIENTMATERIALSOURCE ,
5857 WINED3DRS_CLIPPING ,
5858 WINED3DRS_CLIPPLANEENABLE ,
5859 WINED3DRS_COLORVERTEX ,
5860 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5861 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5862 WINED3DRS_FOGDENSITY ,
5864 WINED3DRS_FOGSTART ,
5865 WINED3DRS_FOGTABLEMODE ,
5866 WINED3DRS_FOGVERTEXMODE ,
5867 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5868 WINED3DRS_LIGHTING ,
5869 WINED3DRS_LOCALVIEWER ,
5870 WINED3DRS_MULTISAMPLEANTIALIAS ,
5871 WINED3DRS_MULTISAMPLEMASK ,
5872 WINED3DRS_NORMALIZENORMALS ,
5873 WINED3DRS_PATCHEDGESTYLE ,
5874 WINED3DRS_POINTSCALE_A ,
5875 WINED3DRS_POINTSCALE_B ,
5876 WINED3DRS_POINTSCALE_C ,
5877 WINED3DRS_POINTSCALEENABLE ,
5878 WINED3DRS_POINTSIZE ,
5879 WINED3DRS_POINTSIZE_MAX ,
5880 WINED3DRS_POINTSIZE_MIN ,
5881 WINED3DRS_POINTSPRITEENABLE ,
5882 WINED3DRS_RANGEFOGENABLE ,
5883 WINED3DRS_SPECULARMATERIALSOURCE ,
5884 WINED3DRS_TWEENFACTOR ,
5885 WINED3DRS_VERTEXBLEND
5888 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5889 WINED3DTSS_TEXCOORDINDEX ,
5890 WINED3DTSS_TEXTURETRANSFORMFLAGS
5893 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5894 WINED3DSAMP_DMAPOFFSET
5897 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5898 DWORD rep = StateTable[state].representative;
5902 WineD3DContext *context;
5905 for(i = 0; i < This->numContexts; i++) {
5906 context = This->contexts[i];
5907 if(isStateDirty(context, rep)) continue;
5909 context->dirtyArray[context->numDirtyEntries++] = rep;
5912 context->isStateDirty[idx] |= (1 << shift);