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 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader
);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY
, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE
, /* get current drawable for a DC */
60 X11DRV_GET_FONT
, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display
*get_display( HDC hdc
)
67 enum x11drv_escape_codes escape
= X11DRV_GET_DISPLAY
;
69 if (!ExtEscape( hdc
, X11DRV_ESCAPE
, sizeof(escape
), (LPCSTR
)&escape
,
70 sizeof(display
), (LPSTR
)&display
)) display
= NULL
;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface
= FALSE
;
77 /* static function declarations */
78 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
80 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
);
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
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 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice
*iface
, GLhandleARB shaderObj
, GLhandleARB programId
) {
158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
160 if (shaderObj
!= 0 && programId
!= 0) {
161 TRACE_(d3d_shader
)("Detaching GLSL shader object %u from program %u\n", shaderObj
, programId
);
162 GL_EXTCALL(glDetachObjectARB(programId
, shaderObj
));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice
*iface
, GLhandleARB obj
) {
170 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
173 TRACE_(d3d_shader
)("Deleting GLSL shader program %u\n", obj
);
174 GL_EXTCALL(glDeleteObjectARB(obj
));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice
* iface
) {
185 struct list
*ptr
= NULL
;
186 struct glsl_shader_prog_link
*curLink
= NULL
;
187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
191 GLhandleARB objList
[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr
= list_head( &This
->glsl_shader_progs
);
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink
= LIST_ENTRY( ptr
, struct glsl_shader_prog_link
, entry
);
201 ptr
= list_next( &This
->glsl_shader_progs
, ptr
);
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink
->programId
, 2, &numAttached
, objList
));
205 TRACE_(d3d_shader
)("%i GLSL objects are currently attached to program %u\n", numAttached
, curLink
->programId
);
206 for (i
= 0; i
< numAttached
; i
++) {
207 detach_glsl_shader(iface
, objList
[i
], curLink
->programId
);
210 delete_glsl_shader_program(iface
, curLink
->programId
);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink
->vuniformF_locations
);
214 HeapFree(GetProcessHeap(), 0, curLink
->puniformF_locations
);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink
);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
227 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
229 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
230 if (IsEqualGUID(riid
, &IID_IUnknown
)
231 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
232 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
233 IUnknown_AddRef(iface
);
238 return E_NOINTERFACE
;
241 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
242 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
243 ULONG refCount
= InterlockedIncrement(&This
->ref
);
245 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
249 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
251 ULONG refCount
= InterlockedDecrement(&This
->ref
);
253 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This
->fbo
));
260 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
262 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This
->vs_selected_mode
== SHADER_GLSL
||
270 This
->ps_selected_mode
== SHADER_GLSL
)
271 delete_glsl_shader_list(iface
);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
275 if(This
->updateStateBlock
!= This
->stateBlock
)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
278 This
->updateStateBlock
= NULL
;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
283 This
->stateBlock
= NULL
;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
291 if (This
->resources
!= NULL
) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
293 dumpResources(This
->resources
);
296 if(This
->contexts
) ERR("Context array not freed!\n");
298 IWineD3D_Release(This
->wineD3D
);
299 This
->wineD3D
= NULL
;
300 HeapFree(GetProcessHeap(), 0, This
);
301 TRACE("Freed device %p\n", This
);
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
311 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
312 *pParent
= This
->parent
;
313 IUnknown_AddRef(This
->parent
);
317 static void CreateVBO(IWineD3DVertexBufferImpl
*object
) {
318 IWineD3DDeviceImpl
*This
= object
->resource
.wineD3DDevice
; /* Needed for GL_EXTCALL */
319 GLenum error
, glUsage
;
320 DWORD vboUsage
= object
->resource
.usage
;
321 if(object
->Flags
& VBFLAG_VBOCREATEFAIL
) {
322 WARN("Creating a vbo failed once, not trying again\n");
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object
, debug_d3dusage(vboUsage
));
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR
);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object
->vbo
));
344 error
= glGetError();
345 if(object
->vbo
== 0 || error
!= GL_NO_ERROR
) {
346 WARN("Failed to create a VBO with error %d\n", error
);
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, object
->vbo
));
351 error
= glGetError();
352 if(error
!= GL_NO_ERROR
) {
353 WARN("Failed to bind the VBO, error %d\n", error
);
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage
& (WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
) ) {
362 case WINED3DUSAGE_WRITEONLY
| WINED3DUSAGE_DYNAMIC
:
363 case WINED3DUSAGE_DYNAMIC
:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage
= GL_STREAM_DRAW_ARB
;
367 case WINED3DUSAGE_WRITEONLY
:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage
= GL_DYNAMIC_DRAW_ARB
;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB
, object
->resource
.size
, NULL
, glUsage
));
379 error
= glGetError();
380 if(error
!= GL_NO_ERROR
) {
381 WARN("glBufferDataARB failed with error %d\n", error
);
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object
->vbo
) GL_EXTCALL(glDeleteBuffersARB(1, &object
->vbo
));
393 object
->Flags
|= VBFLAG_VBOCREATEFAIL
;
398 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
399 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DVertexBuffer
** ppVertexBuffer
, HANDLE
*sharedHandle
,
401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
402 IWineD3DVertexBufferImpl
*object
;
403 WINED3DFORMAT Format
= WINED3DFMT_VERTEXDATA
; /* Dummy format for now */
404 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer
= NULL
;
410 return WINED3DERR_INVALIDCALL
;
413 D3DCREATERESOURCEOBJECTINSTANCE(object
, VertexBuffer
, WINED3DRTYPE_VERTEXBUFFER
, Size
)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
416 *ppVertexBuffer
= (IWineD3DVertexBuffer
*)object
;
418 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
419 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, object
->resource
.size
);
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
) && Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) &&
440 (dxVersion
> 7 || !conv
) ) {
446 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
, UINT Length
, DWORD Usage
,
447 WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DIndexBuffer
** ppIndexBuffer
,
448 HANDLE
*sharedHandle
, IUnknown
*parent
) {
449 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
450 IWineD3DIndexBufferImpl
*object
;
451 TRACE("(%p) Creating index buffer\n", This
);
453 /* Allocate the storage for the device */
454 D3DCREATERESOURCEOBJECTINSTANCE(object
,IndexBuffer
,WINED3DRTYPE_INDEXBUFFER
, Length
)
457 if (Pool
== WINED3DPOOL_DEFAULT
) { /* Allocate some system memory for now */
458 object
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,object
->resource
.size
);
461 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
, Format
,
462 debug_d3dformat(Format
), Pool
, object
, object
->resource
.allocatedMemory
);
463 *ppIndexBuffer
= (IWineD3DIndexBuffer
*) object
;
468 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
471 IWineD3DStateBlockImpl
*object
;
475 D3DCREATEOBJECTINSTANCE(object
, StateBlock
)
476 object
->blockType
= Type
;
478 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
479 list_init(&object
->lightMap
[i
]);
482 /* Special case - Used during initialization to produce a placeholder stateblock
483 so other functions called can update a state block */
484 if (Type
== WINED3DSBT_INIT
) {
485 /* Don't bother increasing the reference count otherwise a device will never
486 be freed due to circular dependencies */
490 temp_result
= allocate_shader_constants(object
);
491 if (WINED3D_OK
!= temp_result
)
494 /* Otherwise, might as well set the whole state block to the appropriate values */
495 if (This
->stateBlock
!= NULL
)
496 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
498 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
500 /* Reset the ref and type after kludging it */
501 object
->wineD3DDevice
= This
;
503 object
->blockType
= Type
;
505 TRACE("Updating changed flags appropriate for type %d\n", Type
);
507 if (Type
== WINED3DSBT_ALL
) {
509 TRACE("ALL => Pretend everything has changed\n");
510 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
512 /* Lights are not part of the changed / set structure */
513 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
515 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
516 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
517 light
->changed
= TRUE
;
518 light
->enabledChanged
= TRUE
;
521 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
523 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
524 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
526 object
->changed
.pixelShader
= TRUE
;
528 /* Pixel Shader Constants */
529 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
)
530 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
531 for (i
= 0; i
< MAX_CONST_B
; ++i
)
532 object
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
533 for (i
= 0; i
< MAX_CONST_I
; ++i
)
534 object
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
536 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
537 object
->changed
.renderState
[SavedPixelStates_R
[i
]] = TRUE
;
539 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
540 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
541 object
->changed
.textureState
[j
][SavedPixelStates_T
[i
]] = TRUE
;
544 for (j
= 0 ; j
< 16; j
++) {
545 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
547 object
->changed
.samplerState
[j
][SavedPixelStates_S
[i
]] = TRUE
;
551 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
553 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
554 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
556 object
->changed
.vertexShader
= TRUE
;
558 /* Vertex Shader Constants */
559 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
)
560 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
561 for (i
= 0; i
< MAX_CONST_B
; ++i
)
562 object
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
563 for (i
= 0; i
< MAX_CONST_I
; ++i
)
564 object
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
566 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
567 object
->changed
.renderState
[SavedVertexStates_R
[i
]] = TRUE
;
569 for (j
= 0; j
< GL_LIMITS(texture_stages
); j
++) {
570 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
571 object
->changed
.textureState
[j
][SavedVertexStates_T
[i
]] = TRUE
;
574 for (j
= 0 ; j
< 16; j
++){
575 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
576 object
->changed
.samplerState
[j
][SavedVertexStates_S
[i
]] = TRUE
;
580 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
582 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
583 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
584 light
->changed
= TRUE
;
585 light
->enabledChanged
= TRUE
;
589 FIXME("Unrecognized state block type %d\n", Type
);
592 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
597 /* ************************************
599 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
602 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
604 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.
606 ******************************** */
608 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
) {
609 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
610 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
611 unsigned int pow2Width
, pow2Height
;
612 unsigned int Size
= 1;
613 const PixelFormatDesc
*tableEntry
= getFormatDescEntry(Format
);
614 TRACE("(%p) Create surface\n",This
);
616 /** FIXME: Check ranges on the inputs are valid
619 * [in] Quality level. The valid range is between zero and one less than the level
620 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
621 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
622 * values of paired render targets, depth stencil surfaces, and the MultiSample type
624 *******************************/
629 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 * If this flag is set, the contents of the depth stencil buffer will be
632 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
633 * with a different depth surface.
635 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
636 ***************************/
638 if(MultisampleQuality
< 0) {
639 FIXME("Invalid multisample level %d\n", MultisampleQuality
);
640 return WINED3DERR_INVALIDCALL
; /* TODO: Check that this is the case! */
643 if(MultisampleQuality
> 0) {
644 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
645 MultisampleQuality
=0;
648 /** FIXME: Check that the format is supported
650 *******************************/
652 /* Non-power2 support */
653 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
657 /* Find the nearest pow2 match */
658 pow2Width
= pow2Height
= 1;
659 while (pow2Width
< Width
) pow2Width
<<= 1;
660 while (pow2Height
< Height
) pow2Height
<<= 1;
663 if (pow2Width
> Width
|| pow2Height
> Height
) {
664 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
665 if (Format
== WINED3DFMT_DXT1
|| Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
666 || Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
667 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
668 This
, Width
, Height
);
669 return WINED3DERR_NOTAVAILABLE
;
673 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
674 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
676 *********************************/
677 if (WINED3DFMT_UNKNOWN
== Format
) {
679 } else if (Format
== WINED3DFMT_DXT1
) {
680 /* DXT1 is half byte per pixel */
681 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4)) >> 1;
683 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
684 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
) {
685 Size
= ((max(Width
,4) * tableEntry
->bpp
) * max(Height
,4));
687 /* The pitch is a multiple of 4 bytes */
688 Size
= ((Width
* tableEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
692 /** Create and initialise the surface resource **/
693 D3DCREATERESOURCEOBJECTINSTANCE(object
,Surface
,WINED3DRTYPE_SURFACE
, Size
)
694 /* "Standalone" surface */
695 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
697 object
->currentDesc
.Width
= Width
;
698 object
->currentDesc
.Height
= Height
;
699 object
->currentDesc
.MultiSampleType
= MultiSample
;
700 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
702 /* Setup some glformat defaults */
703 object
->glDescription
.glFormat
= tableEntry
->glFormat
;
704 object
->glDescription
.glFormatInternal
= tableEntry
->glInternal
;
705 object
->glDescription
.glType
= tableEntry
->glType
;
707 object
->glDescription
.textureName
= 0;
708 object
->glDescription
.level
= Level
;
709 object
->glDescription
.target
= GL_TEXTURE_2D
;
712 object
->pow2Width
= pow2Width
;
713 object
->pow2Height
= pow2Height
;
716 object
->Flags
= 0; /* We start without flags set */
717 object
->Flags
|= (pow2Width
!= Width
|| pow2Height
!= Height
) ? SFLAG_NONPOW2
: 0;
718 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
719 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
720 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
723 if (WINED3DFMT_UNKNOWN
!= Format
) {
724 object
->bytesPerPixel
= tableEntry
->bpp
;
726 object
->bytesPerPixel
= 0;
729 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
731 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
733 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
734 * this function is too deep to need to care about things like this.
735 * Levels need to be checked too, and possibly Type since they all affect what can be done.
736 * ****************************************/
738 case WINED3DPOOL_SCRATCH
:
740 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
741 "which are mutually exclusive, setting lockable to TRUE\n");
744 case WINED3DPOOL_SYSTEMMEM
:
745 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
746 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
747 case WINED3DPOOL_MANAGED
:
748 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
749 "Usage of DYNAMIC which are mutually exclusive, not doing "
750 "anything just telling you.\n");
752 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
753 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
754 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
755 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
758 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
762 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
763 FIXME("Trying to create a render target that isn't in the default pool\n");
766 /* mark the texture as dirty so that it gets loaded first time around*/
767 IWineD3DSurface_AddDirtyRect(*ppSurface
, NULL
);
768 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
769 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
770 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
772 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
773 if( (Usage
& WINED3DUSAGE_RENDERTARGET
) && (!This
->ddraw_primary
) )
774 This
->ddraw_primary
= (IWineD3DSurface
*) object
;
776 /* Look at the implementation and set the correct Vtable */
779 /* Nothing to do, it's set already */
783 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
787 /* To be sure to catch this */
788 ERR("Unknown requested surface implementation %d!\n", Impl
);
789 IWineD3DSurface_Release((IWineD3DSurface
*) object
);
790 return WINED3DERR_INVALIDCALL
;
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface
*) object
);
798 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
, UINT Width
, UINT Height
, UINT Levels
,
799 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
800 IWineD3DTexture
** ppTexture
, HANDLE
* pSharedHandle
, IUnknown
*parent
,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
803 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
804 IWineD3DTextureImpl
*object
;
809 unsigned int pow2Width
;
810 unsigned int pow2Height
;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, pSharedHandle
, parent
);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN
>= Format
) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
821 return WINED3DERR_INVALIDCALL
;
824 D3DCREATERESOURCEOBJECTINSTANCE(object
, Texture
, WINED3DRTYPE_TEXTURE
, 0);
825 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
826 object
->width
= Width
;
827 object
->height
= Height
;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
834 /* Find the nearest pow2 match */
835 pow2Width
= pow2Height
= 1;
836 while (pow2Width
< Width
) pow2Width
<<= 1;
837 while (pow2Height
< Height
) pow2Height
<<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object
->pow2scalingFactorX
= (((float)Width
) / ((float)pow2Width
));
843 object
->pow2scalingFactorY
= (((float)Height
) / ((float)pow2Height
));
844 TRACE(" xf(%f) yf(%f)\n", object
->pow2scalingFactorX
, object
->pow2scalingFactorY
);
846 /* Calculate levels for mip mapping */
848 TRACE("calculating levels %d\n", object
->baseTexture
.levels
);
849 object
->baseTexture
.levels
++;
852 while (tmpW
> 1 || tmpH
> 1) {
853 tmpW
= max(1, tmpW
>> 1);
854 tmpH
= max(1, tmpH
>> 1);
855 object
->baseTexture
.levels
++;
857 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
860 /* Generate all the surfaces */
863 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
865 /* use the callback to create the texture surface */
866 hr
= D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpH
, Format
, Usage
, Pool
, i
, &object
->surfaces
[i
],NULL
);
867 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
868 FIXME("Failed to create surface %p\n", object
);
870 object
->surfaces
[i
] = NULL
;
871 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
877 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
878 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
879 /* calculate the next mipmap level */
880 tmpW
= max(1, tmpW
>> 1);
881 tmpH
= max(1, tmpH
>> 1);
884 TRACE("(%p) : Created texture %p\n", This
, object
);
888 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
889 UINT Width
, UINT Height
, UINT Depth
,
890 UINT Levels
, DWORD Usage
,
891 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
892 IWineD3DVolumeTexture
**ppVolumeTexture
,
893 HANDLE
*pSharedHandle
, IUnknown
*parent
,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume
) {
896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
897 IWineD3DVolumeTextureImpl
*object
;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN
>= Format
) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
907 return WINED3DERR_INVALIDCALL
;
910 D3DCREATERESOURCEOBJECTINSTANCE(object
, VolumeTexture
, WINED3DRTYPE_VOLUMETEXTURE
, 0);
911 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
914 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
916 object
->width
= Width
;
917 object
->height
= Height
;
918 object
->depth
= Depth
;
920 /* Calculate levels for mip mapping */
922 object
->baseTexture
.levels
++;
926 while (tmpW
> 1 || tmpH
> 1 || tmpD
> 1) {
927 tmpW
= max(1, tmpW
>> 1);
928 tmpH
= max(1, tmpH
>> 1);
929 tmpD
= max(1, tmpD
>> 1);
930 object
->baseTexture
.levels
++;
932 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
935 /* Generate all the surfaces */
940 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
943 /* Create the volume */
944 hr
= D3DCB_CreateVolume(This
->parent
, parent
, Width
, Height
, Depth
, Format
, Pool
, Usage
,
945 (IWineD3DVolume
**)&object
->volumes
[i
], pSharedHandle
);
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
950 *ppVolumeTexture
= NULL
;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
957 /* calcualte the next mipmap level */
958 tmpW
= max(1, tmpW
>> 1);
959 tmpH
= max(1, tmpH
>> 1);
960 tmpD
= max(1, tmpD
>> 1);
963 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
964 TRACE("(%p) : Created volume texture %p\n", This
, object
);
968 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
969 UINT Width
, UINT Height
, UINT Depth
,
971 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
972 IWineD3DVolume
** ppVolume
,
973 HANDLE
* pSharedHandle
, IUnknown
*parent
) {
975 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
976 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
977 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(Format
);
979 D3DCREATERESOURCEOBJECTINSTANCE(object
, Volume
, WINED3DRTYPE_VOLUME
, ((Width
* formatDesc
->bpp
) * Height
* Depth
))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
982 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
984 object
->currentDesc
.Width
= Width
;
985 object
->currentDesc
.Height
= Height
;
986 object
->currentDesc
.Depth
= Depth
;
987 object
->bytesPerPixel
= formatDesc
->bpp
;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object
->lockable
= TRUE
;
991 object
->locked
= FALSE
;
992 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
993 object
->dirty
= TRUE
;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume
*) object
, NULL
);
998 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
,
999 UINT Levels
, DWORD Usage
,
1000 WINED3DFORMAT Format
, WINED3DPOOL Pool
,
1001 IWineD3DCubeTexture
**ppCubeTexture
,
1002 HANDLE
*pSharedHandle
, IUnknown
*parent
,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface
) {
1005 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1006 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1010 unsigned int pow2EdgeLength
= EdgeLength
;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN
>= Format
) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1016 return WINED3DERR_INVALIDCALL
;
1019 D3DCREATERESOURCEOBJECTINSTANCE(object
, CubeTexture
, WINED3DRTYPE_CUBETEXTURE
, 0);
1020 D3DINITIALIZEBASETEXTURE(object
->baseTexture
);
1022 TRACE("(%p) Create Cube Texture\n", This
);
1024 /** Non-power2 support **/
1026 /* Find the nearest pow2 match */
1028 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1030 object
->edgeLength
= EdgeLength
;
1031 /* TODO: support for native non-power 2 */
1032 /* Precalculated scaling for 'faked' non power of two texture coords */
1033 object
->pow2scalingFactor
= ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1035 /* Calculate levels for mip mapping */
1037 object
->baseTexture
.levels
++;
1040 tmpW
= max(1, tmpW
>> 1);
1041 object
->baseTexture
.levels
++;
1043 TRACE("Calculated levels = %d\n", object
->baseTexture
.levels
);
1046 /* Generate all the surfaces */
1048 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1050 /* Create the 6 faces */
1051 for (j
= 0; j
< 6; j
++) {
1053 hr
=D3DCB_CreateSurface(This
->parent
, parent
, tmpW
, tmpW
, Format
, Usage
, Pool
,
1054 i
/* Level */, &object
->surfaces
[j
][i
],pSharedHandle
);
1056 if(hr
!= WINED3D_OK
) {
1060 for (l
= 0; l
< j
; l
++) {
1061 IWineD3DSurface_Release(object
->surfaces
[j
][i
]);
1063 for (k
= 0; k
< i
; k
++) {
1064 for (l
= 0; l
< 6; l
++) {
1065 IWineD3DSurface_Release(object
->surfaces
[l
][j
]);
1069 FIXME("(%p) Failed to create surface\n",object
);
1070 HeapFree(GetProcessHeap(),0,object
);
1071 *ppCubeTexture
= NULL
;
1074 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1075 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1077 tmpW
= max(1, tmpW
>> 1);
1080 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1081 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1085 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1086 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1087 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1088 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1090 /* Just a check to see if we support this type of query */
1092 case WINED3DQUERYTYPE_OCCLUSION
:
1093 TRACE("(%p) occlusion query\n", This
);
1094 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1097 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1100 case WINED3DQUERYTYPE_EVENT
:
1101 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1102 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1104 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1108 case WINED3DQUERYTYPE_VCACHE
:
1109 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1110 case WINED3DQUERYTYPE_VERTEXSTATS
:
1111 case WINED3DQUERYTYPE_TIMESTAMP
:
1112 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1113 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1114 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1115 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1116 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1117 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1118 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1119 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1121 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1123 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1127 D3DCREATEOBJECTINSTANCE(object
, Query
)
1128 object
->type
= Type
;
1129 /* allocated the 'extended' data based on the type of query requested */
1131 case WINED3DQUERYTYPE_OCCLUSION
:
1132 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1133 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1134 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1135 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1138 case WINED3DQUERYTYPE_VCACHE
:
1139 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1140 case WINED3DQUERYTYPE_VERTEXSTATS
:
1141 case WINED3DQUERYTYPE_EVENT
:
1142 case WINED3DQUERYTYPE_TIMESTAMP
:
1143 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1144 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1145 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1146 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1147 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1148 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1149 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1150 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1152 object
->extendedData
= 0;
1153 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1155 TRACE("(%p) : Created Query %p\n", This
, object
);
1159 /*****************************************************************************
1160 * IWineD3DDeviceImpl_SetupFullscreenWindow
1162 * Helper function that modifies a HWND's Style and ExStyle for proper
1166 * iface: Pointer to the IWineD3DDevice interface
1167 * window: Window to setup
1169 *****************************************************************************/
1170 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
) {
1171 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1173 LONG style
, exStyle
;
1174 /* Don't do anything if an original style is stored.
1175 * That shouldn't happen
1177 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1178 if (This
->style
|| This
->exStyle
) {
1179 ERR("(%p): Want to change the window parameters of HWND %p, but "
1180 "another style is stored for restoration afterwards\n", This
, window
);
1183 /* Get the parameters and save them */
1184 style
= GetWindowLongW(window
, GWL_STYLE
);
1185 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1186 This
->style
= style
;
1187 This
->exStyle
= exStyle
;
1189 /* Filter out window decorations */
1190 style
&= ~WS_CAPTION
;
1191 style
&= ~WS_THICKFRAME
;
1192 exStyle
&= ~WS_EX_WINDOWEDGE
;
1193 exStyle
&= ~WS_EX_CLIENTEDGE
;
1195 /* Make sure the window is managed, otherwise we won't get keyboard input */
1196 style
|= WS_POPUP
| WS_SYSMENU
;
1198 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1199 This
->style
, This
->exStyle
, style
, exStyle
);
1201 SetWindowLongW(window
, GWL_STYLE
, style
);
1202 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1204 /* Inform the window about the update. */
1205 SetWindowPos(window
, HWND_TOP
, 0, 0,
1206 This
->ddraw_width
, This
->ddraw_height
, SWP_FRAMECHANGED
);
1207 ShowWindow(window
, TRUE
);
1210 /*****************************************************************************
1211 * IWineD3DDeviceImpl_RestoreWindow
1213 * Helper function that restores a windows' properties when taking it out
1214 * of fullscreen mode
1217 * iface: Pointer to the IWineD3DDevice interface
1218 * window: Window to setup
1220 *****************************************************************************/
1221 static void WINAPI
IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1222 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1224 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1225 * switch, do nothing
1227 if (!This
->style
&& !This
->exStyle
) return;
1229 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1230 This
, window
, This
->style
, This
->exStyle
);
1232 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1233 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1235 /* Delete the old values */
1239 /* Inform the window about the update */
1240 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1241 0, 0, 0, 0, /* Pos, Size, ignored */
1242 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1245 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1246 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, IWineD3DSwapChain
** ppSwapChain
,
1248 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget
,
1249 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil
) {
1250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1253 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1254 HRESULT hr
= WINED3D_OK
;
1255 IUnknown
*bufferParent
;
1258 TRACE("(%p) : Created Aditional Swap Chain\n", This
);
1260 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1261 * does a device hold a reference to a swap chain giving them a lifetime of the device
1262 * or does the swap chain notify the device of its destruction.
1263 *******************************/
1265 /* Check the params */
1266 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1267 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1268 return WINED3DERR_INVALIDCALL
;
1269 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1270 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");
1273 D3DCREATEOBJECTINSTANCE(object
, SwapChain
)
1275 /*********************
1276 * Lookup the window Handle and the relating X window handle
1277 ********************/
1279 /* Setup hwnd we are using, plus which display this equates to */
1280 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1281 if (!object
->win_handle
) {
1282 object
->win_handle
= This
->createParms
.hFocusWindow
;
1285 object
->win_handle
= GetAncestor(object
->win_handle
, GA_ROOT
);
1286 if ( !( object
->win
= (Window
)GetPropA(object
->win_handle
, "__wine_x11_whole_window") ) ) {
1287 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object
->win_handle
);
1288 return WINED3DERR_NOTAVAILABLE
;
1290 hDc
= GetDC(object
->win_handle
);
1291 display
= get_display(hDc
);
1292 ReleaseDC(object
->win_handle
, hDc
);
1293 TRACE("Using a display of %p %p\n", display
, hDc
);
1295 if (NULL
== display
|| NULL
== hDc
) {
1296 WARN("Failed to get a display and HDc for Window %p\n", object
->win_handle
);
1297 return WINED3DERR_NOTAVAILABLE
;
1300 if (object
->win
== 0) {
1301 WARN("Failed to get a valid XVisuial ID for the window %p\n", object
->win_handle
);
1302 return WINED3DERR_NOTAVAILABLE
;
1305 object
->orig_width
= GetSystemMetrics(SM_CXSCREEN
);
1306 object
->orig_height
= GetSystemMetrics(SM_CYSCREEN
);
1307 object
->orig_fmt
= pixelformat_for_depth(GetDeviceCaps(hDc
, BITSPIXEL
) * GetDeviceCaps(hDc
, PLANES
));
1309 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1310 * then the corresponding dimension of the client area of the hDeviceWindow
1311 * (or the focus window, if hDeviceWindow is NULL) is taken.
1312 **********************/
1314 if (pPresentationParameters
->Windowed
&&
1315 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1316 (pPresentationParameters
->BackBufferHeight
== 0))) {
1319 GetClientRect(object
->win_handle
, &Rect
);
1321 if (pPresentationParameters
->BackBufferWidth
== 0) {
1322 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1323 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1325 if (pPresentationParameters
->BackBufferHeight
== 0) {
1326 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1327 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1331 /* Put the correct figures in the presentation parameters */
1332 TRACE("Copying across presentation parameters\n");
1333 object
->presentParms
= *pPresentationParameters
;
1335 TRACE("calling rendertarget CB\n");
1336 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1338 object
->presentParms
.BackBufferWidth
,
1339 object
->presentParms
.BackBufferHeight
,
1340 object
->presentParms
.BackBufferFormat
,
1341 object
->presentParms
.MultiSampleType
,
1342 object
->presentParms
.MultiSampleQuality
,
1343 TRUE
/* Lockable */,
1344 &object
->frontBuffer
,
1345 NULL
/* pShared (always null)*/);
1346 if (object
->frontBuffer
!= NULL
) {
1347 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1349 ERR("Failed to create the front buffer\n");
1354 * Create an opengl context for the display visual
1355 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1356 * use different properties after that point in time. FIXME: How to handle when requested format
1357 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1358 * it chooses is identical to the one already being used!
1359 **********************************/
1361 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1363 object
->context
= CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, display
, object
->win
);
1366 if (!object
->context
) {
1367 ERR("Failed to create a new context\n");
1368 hr
= WINED3DERR_NOTAVAILABLE
;
1371 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1372 object
->win_handle
, object
->context
->glCtx
, object
->win
);
1375 /*********************
1376 * Windowed / Fullscreen
1377 *******************/
1380 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1381 * so we should really check to see if there is a fullscreen swapchain already
1382 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1383 **************************************/
1385 if (!pPresentationParameters
->Windowed
) {
1392 /* Get info on the current display setup */
1394 bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1397 /* Change the display settings */
1398 memset(&devmode
, 0, sizeof(DEVMODEW
));
1399 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1400 devmode
.dmBitsPerPel
= (bpp
>= 24) ? 32 : bpp
; /* Stupid XVidMode cannot change bpp */
1401 devmode
.dmPelsWidth
= pPresentationParameters
->BackBufferWidth
;
1402 devmode
.dmPelsHeight
= pPresentationParameters
->BackBufferHeight
;
1403 MultiByteToWideChar(CP_ACP
, 0, "Gamers CG", -1, devmode
.dmDeviceName
, CCHDEVICENAME
);
1404 ChangeDisplaySettingsExW(devmode
.dmDeviceName
, &devmode
, object
->win_handle
, CDS_FULLSCREEN
, NULL
);
1406 /* For GetDisplayMode */
1407 This
->ddraw_width
= devmode
.dmPelsWidth
;
1408 This
->ddraw_height
= devmode
.dmPelsHeight
;
1409 This
->ddraw_format
= pPresentationParameters
->BackBufferFormat
;
1411 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
1413 /* And finally clip mouse to our screen */
1414 SetRect(&clip_rc
, 0, 0, devmode
.dmPelsWidth
, devmode
.dmPelsHeight
);
1415 ClipCursor(&clip_rc
);
1418 /*********************
1419 * Create the back, front and stencil buffers
1420 *******************/
1421 if(object
->presentParms
.BackBufferCount
> 0) {
1424 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1425 if(!object
->backBuffer
) {
1426 ERR("Out of memory\n");
1431 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1432 TRACE("calling rendertarget CB\n");
1433 hr
= D3DCB_CreateRenderTarget((IUnknown
*) This
->parent
,
1435 object
->presentParms
.BackBufferWidth
,
1436 object
->presentParms
.BackBufferHeight
,
1437 object
->presentParms
.BackBufferFormat
,
1438 object
->presentParms
.MultiSampleType
,
1439 object
->presentParms
.MultiSampleQuality
,
1440 TRUE
/* Lockable */,
1441 &object
->backBuffer
[i
],
1442 NULL
/* pShared (always null)*/);
1443 if(hr
== WINED3D_OK
&& object
->backBuffer
[i
]) {
1444 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1446 ERR("Cannot create new back buffer\n");
1450 glDrawBuffer(GL_BACK
);
1451 checkGLcall("glDrawBuffer(GL_BACK)");
1455 object
->backBuffer
= NULL
;
1457 /* Single buffering - draw to front buffer */
1459 glDrawBuffer(GL_FRONT
);
1460 checkGLcall("glDrawBuffer(GL_FRONT)");
1464 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1465 if (pPresentationParameters
->EnableAutoDepthStencil
&& hr
== WINED3D_OK
) {
1466 TRACE("Creating depth stencil buffer\n");
1467 if (This
->depthStencilBuffer
== NULL
) {
1468 hr
= D3DCB_CreateDepthStencil((IUnknown
*) This
->parent
,
1470 object
->presentParms
.BackBufferWidth
,
1471 object
->presentParms
.BackBufferHeight
,
1472 object
->presentParms
.AutoDepthStencilFormat
,
1473 object
->presentParms
.MultiSampleType
,
1474 object
->presentParms
.MultiSampleQuality
,
1475 FALSE
/* FIXME: Discard */,
1476 &This
->depthStencilBuffer
,
1477 NULL
/* pShared (always null)*/ );
1478 if (This
->depthStencilBuffer
!= NULL
)
1479 IWineD3DSurface_SetContainer(This
->depthStencilBuffer
, 0);
1482 /** TODO: A check on width, height and multisample types
1483 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1484 ****************************/
1485 object
->wantsDepthStencilBuffer
= TRUE
;
1487 object
->wantsDepthStencilBuffer
= FALSE
;
1490 TRACE("Created swapchain %p\n", object
);
1491 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, object
->wantsDepthStencilBuffer
);
1495 if (object
->backBuffer
) {
1497 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1498 if(object
->backBuffer
[i
]) {
1499 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
1500 IUnknown_Release(bufferParent
); /* once for the get parent */
1501 if (IUnknown_Release(bufferParent
) > 0) {
1502 FIXME("(%p) Something's still holding the back buffer\n",This
);
1506 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1507 object
->backBuffer
= NULL
;
1509 if(object
->context
) {
1510 DestroyContext(This
, object
->context
);
1512 if(object
->frontBuffer
) {
1513 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
1514 IUnknown_Release(bufferParent
); /* once for the get parent */
1515 if (IUnknown_Release(bufferParent
) > 0) {
1516 FIXME("(%p) Something's still holding the front buffer\n",This
);
1519 if(object
) HeapFree(GetProcessHeap(), 0, object
);
1523 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1524 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1525 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1526 TRACE("(%p)\n", This
);
1528 return This
->NumberOfSwapChains
;
1531 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1532 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1533 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1535 if(iSwapChain
< This
->NumberOfSwapChains
) {
1536 *pSwapChain
= This
->swapchains
[iSwapChain
];
1537 IWineD3DSwapChain_AddRef(*pSwapChain
);
1538 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1541 TRACE("Swapchain out of range\n");
1543 return WINED3DERR_INVALIDCALL
;
1548 * Vertex Declaration
1550 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
1551 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, size_t element_count
) {
1552 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1553 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1554 HRESULT hr
= WINED3D_OK
;
1556 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1557 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
1559 D3DCREATEOBJECTINSTANCE(object
, VertexDeclaration
)
1562 hr
= IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration
*)object
, elements
, element_count
);
1567 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1568 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
1569 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1570 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
1571 HRESULT hr
= WINED3D_OK
;
1572 D3DCREATESHADEROBJECTINSTANCE(object
, VertexShader
)
1573 object
->baseShader
.shader_ins
= IWineD3DVertexShaderImpl_shader_ins
;
1575 TRACE("(%p) : Created Vertex shader %p\n", This
, *ppVertexShader
);
1577 if (vertex_declaration
) {
1578 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
1581 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
1583 if (WINED3D_OK
!= hr
) {
1584 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface
);
1585 IWineD3DVertexShader_Release(*ppVertexShader
);
1586 return WINED3DERR_INVALIDCALL
;
1592 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
1593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1594 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
1595 HRESULT hr
= WINED3D_OK
;
1597 D3DCREATESHADEROBJECTINSTANCE(object
, PixelShader
)
1598 object
->baseShader
.shader_ins
= IWineD3DPixelShaderImpl_shader_ins
;
1599 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
1600 if (WINED3D_OK
== hr
) {
1601 TRACE("(%p) : Created Pixel shader %p\n", This
, *ppPixelShader
);
1603 WARN("(%p) : Failed to create pixel shader\n", This
);
1609 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
, PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
) {
1610 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1611 IWineD3DPaletteImpl
*object
;
1613 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1615 /* Create the new object */
1616 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1618 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1619 return E_OUTOFMEMORY
;
1622 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1624 object
->Flags
= Flags
;
1625 object
->parent
= Parent
;
1626 object
->wineD3DDevice
= This
;
1627 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1629 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1632 HeapFree( GetProcessHeap(), 0, object
);
1633 return E_OUTOFMEMORY
;
1636 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1638 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1642 *Palette
= (IWineD3DPalette
*) object
;
1647 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain
) {
1648 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1649 IWineD3DSwapChainImpl
*swapchain
;
1652 TRACE("(%p)->(%p,%p)\n", This
, pPresentationParameters
, D3DCB_CreateAdditionalSwapChain
);
1653 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1655 /* TODO: Test if OpenGL is compiled in and loaded */
1657 /* Initialize the texture unit mapping to a 1:1 mapping */
1658 for(state
= 0; state
< MAX_SAMPLERS
; state
++) {
1659 This
->texUnitMap
[state
] = state
;
1661 This
->oneToOneTexUnitMap
= TRUE
;
1663 /* Setup the implicit swapchain */
1664 TRACE("Creating implicit swapchain\n");
1665 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown
*) This
->parent
, pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
)) || !swapchain
) {
1666 WARN("Failed to create implicit swapchain\n");
1667 return WINED3DERR_INVALIDCALL
;
1670 This
->NumberOfSwapChains
= 1;
1671 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1672 if(!This
->swapchains
) {
1673 ERR("Out of memory!\n");
1674 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1675 return E_OUTOFMEMORY
;
1677 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1679 if(!This
->ddraw_window
) IWineD3DDevice_SetHWND(iface
, swapchain
->win_handle
);
1681 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1682 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1683 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1684 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
1687 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1688 This
->render_targets
[0] = swapchain
->frontBuffer
;
1689 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
1691 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1692 This
->activeContext
= swapchain
->context
;
1694 /* Depth Stencil support */
1695 This
->stencilBufferTarget
= This
->depthStencilBuffer
;
1696 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
1697 set_depth_stencil_fbo(iface
, This
->depthStencilBuffer
);
1699 if (NULL
!= This
->stencilBufferTarget
) {
1700 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1703 /* Set up some starting GL setup */
1706 * Initialize openGL extension related variables
1707 * with Default values
1710 ((IWineD3DImpl
*) This
->wineD3D
)->isGLInfoValid
= IWineD3DImpl_FillGLCaps( This
->wineD3D
, swapchain
->context
->display
);
1711 /* Setup all the devices defaults */
1712 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1714 IWineD3DImpl_CheckGraphicsMemory();
1717 /* Initialize our list of GLSL programs */
1718 list_init(&This
->glsl_shader_progs
);
1720 { /* Set a default viewport */
1724 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
1725 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
1728 IWineD3DDevice_SetViewport((IWineD3DDevice
*)This
, &vp
);
1731 /* Initialize the current view state */
1732 This
->view_ident
= 1;
1733 This
->contexts
[0]->last_was_rhw
= 0;
1734 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1735 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1736 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1739 /* Clear the screen */
1740 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
, WINED3DCLEAR_STENCIL
|WINED3DCLEAR_ZBUFFER
|WINED3DCLEAR_TARGET
, 0x00, 1.0, 0);
1742 This
->d3d_initialized
= TRUE
;
1746 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1750 TRACE("(%p)\n", This
);
1752 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1754 /* Delete the pbuffer context if there is any */
1755 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
1757 /* Delete the mouse cursor texture */
1758 if(This
->cursorTexture
) {
1760 glDeleteTextures(1, &This
->cursorTexture
);
1762 This
->cursorTexture
= 0;
1765 for(sampler
= 0; sampler
< GL_LIMITS(sampler_stages
); ++sampler
) {
1766 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1769 /* Release the buffers (with sanity checks)*/
1770 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1771 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1772 if(This
->depthStencilBuffer
!= This
->stencilBufferTarget
)
1773 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This
);
1775 This
->stencilBufferTarget
= NULL
;
1777 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1778 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1779 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1781 TRACE("Setting rendertarget to NULL\n");
1782 This
->render_targets
[0] = NULL
;
1784 if (This
->depthStencilBuffer
) {
1785 if(D3DCB_DestroyDepthStencilSurface(This
->depthStencilBuffer
) > 0) {
1786 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This
);
1788 This
->depthStencilBuffer
= NULL
;
1791 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1792 TRACE("Releasing the implicit swapchain %d\n", i
);
1793 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1794 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1798 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1799 This
->swapchains
= NULL
;
1800 This
->NumberOfSwapChains
= 0;
1802 This
->d3d_initialized
= FALSE
;
1806 static void WINAPI
IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice
*iface
, BOOL fullscreen
) {
1807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1808 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This
, fullscreen
? "true" : "false");
1810 /* Setup the window for fullscreen mode */
1811 if(fullscreen
&& !This
->ddraw_fullscreen
) {
1812 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, This
->ddraw_window
);
1813 } else if(!fullscreen
&& This
->ddraw_fullscreen
) {
1814 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
1817 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1818 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1819 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1822 This
->ddraw_fullscreen
= fullscreen
;
1825 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice
*iface
, DWORD Flags
, UINT Width
, UINT Height
, WINED3DFORMAT pixelformat
, LPVOID context
, D3DCB_ENUMDISPLAYMODESCALLBACK callback
) {
1826 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1830 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(pixelformat
);
1832 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This
, Flags
, Width
, Height
, pixelformat
, context
, callback
);
1834 for (i
= 0; EnumDisplaySettingsExW(NULL
, i
, &DevModeW
, 0); i
++) {
1835 /* Ignore some modes if a description was passed */
1836 if ( (Width
> 0) && (Width
!= DevModeW
.dmPelsWidth
)) continue;
1837 if ( (Height
> 0) && (Height
!= DevModeW
.dmPelsHeight
)) continue;
1838 if ( (pixelformat
!= WINED3DFMT_UNKNOWN
) && ( formatDesc
->bpp
!= DevModeW
.dmBitsPerPel
) ) continue;
1840 TRACE("Enumerating %dx%d@%s\n", DevModeW
.dmPelsWidth
, DevModeW
.dmPelsHeight
, debug_d3dformat(pixelformat_for_depth(DevModeW
.dmBitsPerPel
)));
1842 if (callback((IUnknown
*) This
, (UINT
) DevModeW
.dmPelsWidth
, (UINT
) DevModeW
.dmPelsHeight
, pixelformat_for_depth(DevModeW
.dmBitsPerPel
), 60.0, context
) == DDENUMRET_CANCEL
)
1849 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
1851 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1853 const PixelFormatDesc
*formatDesc
= getFormatDescEntry(pMode
->Format
);
1856 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1858 /* Resize the screen even without a window:
1859 * The app could have unset it with SetCooperativeLevel, but not called
1860 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1861 * but we don't have any hwnd
1864 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1865 devmode
.dmBitsPerPel
= formatDesc
->bpp
* 8;
1866 if(devmode
.dmBitsPerPel
== 24) devmode
.dmBitsPerPel
= 32;
1867 devmode
.dmPelsWidth
= pMode
->Width
;
1868 devmode
.dmPelsHeight
= pMode
->Height
;
1870 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1871 if (pMode
->RefreshRate
!= 0) {
1872 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1875 /* Only change the mode if necessary */
1876 if( (This
->ddraw_width
== pMode
->Width
) &&
1877 (This
->ddraw_height
== pMode
->Height
) &&
1878 (This
->ddraw_format
== pMode
->Format
) &&
1879 (pMode
->RefreshRate
== 0) ) {
1883 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1884 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1885 if(devmode
.dmDisplayFrequency
!= 0) {
1886 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1887 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1888 devmode
.dmDisplayFrequency
= 0;
1889 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1891 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1892 return DDERR_INVALIDMODE
;
1896 /* Store the new values */
1897 This
->ddraw_width
= pMode
->Width
;
1898 This
->ddraw_height
= pMode
->Height
;
1899 This
->ddraw_format
= pMode
->Format
;
1901 /* Only do this with a window of course */
1902 if(This
->ddraw_window
)
1903 MoveWindow(This
->ddraw_window
, 0, 0, pMode
->Width
, pMode
->Height
, TRUE
);
1905 /* And finally clip mouse to our screen */
1906 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1907 ClipCursor(&clip_rc
);
1912 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1913 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1914 *ppD3D
= This
->wineD3D
;
1915 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
1916 IWineD3D_AddRef(*ppD3D
);
1920 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
1921 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1922 * into the video ram as possible and seeing how many fit
1923 * you can also get the correct initial value from nvidia and ATI's driver via X
1924 * texture memory is video memory + AGP memory
1925 *******************/
1926 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1927 static BOOL showfixmes
= TRUE
;
1929 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This
,
1930 (wined3d_settings
.emulated_textureram
/(1024*1024)),
1931 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
1934 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
1935 (wined3d_settings
.emulated_textureram
/(1024*1024)),
1936 ((wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
) / (1024*1024)));
1937 /* return simulated texture memory left */
1938 return (wined3d_settings
.emulated_textureram
- wineD3DGlobalStatistics
->glsurfaceram
);
1946 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFVF(IWineD3DDevice
*iface
, DWORD fvf
) {
1947 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1949 /* Update the current state block */
1950 This
->updateStateBlock
->changed
.fvf
= TRUE
;
1951 This
->updateStateBlock
->set
.fvf
= TRUE
;
1953 if(This
->updateStateBlock
->fvf
== fvf
) {
1954 TRACE("Application is setting the old fvf over, nothing to do\n");
1958 This
->updateStateBlock
->fvf
= fvf
;
1959 TRACE("(%p) : FVF Shader FVF set to %x\n", This
, fvf
);
1960 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
1965 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFVF(IWineD3DDevice
*iface
, DWORD
*pfvf
) {
1966 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1967 TRACE("(%p) : GetFVF returning %x\n", This
, This
->stateBlock
->fvf
);
1968 *pfvf
= This
->stateBlock
->fvf
;
1973 * Get / Set Stream Source
1975 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
* pStreamData
, UINT OffsetInBytes
, UINT Stride
) {
1976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1977 IWineD3DVertexBuffer
*oldSrc
;
1979 if (StreamNumber
>= MAX_STREAMS
) {
1980 WARN("Stream out of range %d\n", StreamNumber
);
1981 return WINED3DERR_INVALIDCALL
;
1984 oldSrc
= This
->stateBlock
->streamSource
[StreamNumber
];
1985 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This
, StreamNumber
, oldSrc
, pStreamData
, Stride
);
1987 This
->updateStateBlock
->changed
.streamSource
[StreamNumber
] = TRUE
;
1988 This
->updateStateBlock
->set
.streamSource
[StreamNumber
] = TRUE
;
1990 if(oldSrc
== pStreamData
&&
1991 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
1992 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
1993 TRACE("Application is setting the old values over, nothing to do\n");
1997 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
1999 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2000 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2003 /* Handle recording of state blocks */
2004 if (This
->isRecordingState
) {
2005 TRACE("Recording... not performing anything\n");
2009 /* Need to do a getParent and pass the reffs up */
2010 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2011 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2012 so for now, just count internally */
2013 if (pStreamData
!= NULL
) {
2014 IWineD3DVertexBufferImpl
*vbImpl
= (IWineD3DVertexBufferImpl
*) pStreamData
;
2015 InterlockedIncrement(&vbImpl
->bindCount
);
2017 if (oldSrc
!= NULL
) {
2018 InterlockedDecrement(&((IWineD3DVertexBufferImpl
*) oldSrc
)->bindCount
);
2021 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2026 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,IWineD3DVertexBuffer
** pStream
, UINT
*pOffset
, UINT
* pStride
) {
2027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2030 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This
, StreamNumber
,
2031 This
->stateBlock
->streamSource
[StreamNumber
], This
->stateBlock
->streamStride
[StreamNumber
]);
2034 streamFlags
= StreamNumber
&(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2036 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2037 FIXME("stream index data not supported\n");
2039 if (streamFlags
& WINED3DSTREAMSOURCE_INDEXEDDATA
) {
2040 FIXME("stream instance data not supported\n");
2044 StreamNumber
&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA
| WINED3DSTREAMSOURCE_INSTANCEDATA
);
2046 if (StreamNumber
>= MAX_STREAMS
) {
2047 WARN("Stream out of range %d\n", StreamNumber
);
2048 return WINED3DERR_INVALIDCALL
;
2050 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2051 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2053 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2056 if (*pStream
!= NULL
) {
2057 IWineD3DVertexBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2062 /*Should be quite easy, just an extension of vertexdata
2064 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2066 The divider is a bit odd though
2068 VertexOffset = StartVertex / Divider * StreamStride +
2069 VertexIndex / Divider * StreamStride + StreamOffset
2072 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2073 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2074 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2075 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2077 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2078 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2080 This
->updateStateBlock
->changed
.streamFreq
[StreamNumber
] = TRUE
;
2081 This
->updateStateBlock
->set
.streamFreq
[StreamNumber
] = TRUE
;
2082 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2084 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2085 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2086 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2092 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2093 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2095 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2096 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2098 TRACE("(%p) : returning %d\n", This
, *Divider
);
2104 * Get / Set & Multiply Transform
2106 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2107 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2109 /* Most of this routine, comments included copied from ddraw tree initially: */
2110 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2112 /* Handle recording of state blocks */
2113 if (This
->isRecordingState
) {
2114 TRACE("Recording... not performing anything\n");
2115 This
->updateStateBlock
->changed
.transform
[d3dts
] = TRUE
;
2116 This
->updateStateBlock
->set
.transform
[d3dts
] = TRUE
;
2117 memcpy(&This
->updateStateBlock
->transforms
[d3dts
], lpmatrix
, sizeof(WINED3DMATRIX
));
2122 * If the new matrix is the same as the current one,
2123 * we cut off any further processing. this seems to be a reasonable
2124 * optimization because as was noticed, some apps (warcraft3 for example)
2125 * tend towards setting the same matrix repeatedly for some reason.
2127 * From here on we assume that the new matrix is different, wherever it matters.
2129 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2130 TRACE("The app is setting the same matrix over again\n");
2133 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2137 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2138 where ViewMat = Camera space, WorldMat = world space.
2140 In OpenGL, camera and world space is combined into GL_MODELVIEW
2141 matrix. The Projection matrix stay projection matrix.
2144 /* Capture the times we can just ignore the change for now */
2145 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrice */
2146 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2147 /* Handled by the state manager */
2150 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2154 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2155 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2156 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2157 memcpy(pMatrix
, &This
->stateBlock
->transforms
[State
], sizeof(WINED3DMATRIX
));
2161 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2162 WINED3DMATRIX
*mat
= NULL
;
2165 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2166 * below means it will be recorded in a state block change, but it
2167 * works regardless where it is recorded.
2168 * If this is found to be wrong, change to StateBlock.
2170 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2171 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2173 if (State
< HIGHEST_TRANSFORMSTATE
)
2175 mat
= &This
->updateStateBlock
->transforms
[State
];
2177 FIXME("Unhandled transform state!!\n");
2180 multiply_matrix(&temp
, mat
, (const WINED3DMATRIX
*) pMatrix
);
2182 /* Apply change via set transform - will reapply to eg. lights this way */
2183 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2189 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2190 you can reference any indexes you want as long as that number max are enabled at any
2191 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2192 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2193 but when recording, just build a chain pretty much of commands to be replayed. */
2195 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2197 PLIGHTINFOEL
*object
= NULL
;
2198 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2201 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2202 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2204 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2205 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2206 if(object
->OriginalIndex
== Index
) break;
2211 TRACE("Adding new light\n");
2212 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2214 ERR("Out of memory error when allocating a light\n");
2215 return E_OUTOFMEMORY
;
2217 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2218 object
->glIndex
= -1;
2219 object
->OriginalIndex
= Index
;
2220 object
->changed
= TRUE
;
2223 /* Initialize the object */
2224 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
,
2225 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2226 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2227 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2228 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2229 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2230 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2232 /* Save away the information */
2233 memcpy(&object
->OriginalParms
, pLight
, sizeof(WINED3DLIGHT
));
2235 switch (pLight
->Type
) {
2236 case WINED3DLIGHT_POINT
:
2238 object
->lightPosn
[0] = pLight
->Position
.x
;
2239 object
->lightPosn
[1] = pLight
->Position
.y
;
2240 object
->lightPosn
[2] = pLight
->Position
.z
;
2241 object
->lightPosn
[3] = 1.0f
;
2242 object
->cutoff
= 180.0f
;
2246 case WINED3DLIGHT_DIRECTIONAL
:
2248 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2249 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2250 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2251 object
->lightPosn
[3] = 0.0;
2252 object
->exponent
= 0.0f
;
2253 object
->cutoff
= 180.0f
;
2256 case WINED3DLIGHT_SPOT
:
2258 object
->lightPosn
[0] = pLight
->Position
.x
;
2259 object
->lightPosn
[1] = pLight
->Position
.y
;
2260 object
->lightPosn
[2] = pLight
->Position
.z
;
2261 object
->lightPosn
[3] = 1.0;
2264 object
->lightDirn
[0] = pLight
->Direction
.x
;
2265 object
->lightDirn
[1] = pLight
->Direction
.y
;
2266 object
->lightDirn
[2] = pLight
->Direction
.z
;
2267 object
->lightDirn
[3] = 1.0;
2270 * opengl-ish and d3d-ish spot lights use too different models for the
2271 * light "intensity" as a function of the angle towards the main light direction,
2272 * so we only can approximate very roughly.
2273 * however spot lights are rather rarely used in games (if ever used at all).
2274 * furthermore if still used, probably nobody pays attention to such details.
2276 if (pLight
->Falloff
== 0) {
2279 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2281 if (rho
< 0.0001) rho
= 0.0001f
;
2282 object
->exponent
= -0.3/log(cos(rho
/2));
2283 if (object
->exponent
> 128.0) {
2284 object
->exponent
= 128.0;
2286 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2292 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2295 /* Update the live definitions if the light is currently assigned a glIndex */
2296 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2297 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2302 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
2303 PLIGHTINFOEL
*lightInfo
= NULL
;
2304 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2305 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2307 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2309 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2310 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2311 if(lightInfo
->OriginalIndex
== Index
) break;
2315 if (lightInfo
== NULL
) {
2316 TRACE("Light information requested but light not defined\n");
2317 return WINED3DERR_INVALIDCALL
;
2320 memcpy(pLight
, &lightInfo
->OriginalParms
, sizeof(WINED3DLIGHT
));
2325 * Get / Set Light Enable
2326 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2328 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
2329 PLIGHTINFOEL
*lightInfo
= NULL
;
2330 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2331 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2333 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2335 /* Tests show true = 128...not clear why */
2336 Enable
= Enable
? 128: 0;
2338 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2339 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2340 if(lightInfo
->OriginalIndex
== Index
) break;
2343 TRACE("Found light: %p\n", lightInfo
);
2345 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2346 if (lightInfo
== NULL
) {
2348 TRACE("Light enabled requested but light not defined, so defining one!\n");
2349 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2351 /* Search for it again! Should be fairly quick as near head of list */
2352 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
2353 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2354 if(lightInfo
->OriginalIndex
== Index
) break;
2357 if (lightInfo
== NULL
) {
2358 FIXME("Adding default lights has failed dismally\n");
2359 return WINED3DERR_INVALIDCALL
;
2363 lightInfo
->enabledChanged
= TRUE
;
2365 if(lightInfo
->glIndex
!= -1) {
2366 if(!This
->isRecordingState
) {
2367 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2370 This
->stateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2371 lightInfo
->glIndex
= -1;
2373 TRACE("Light already disabled, nothing to do\n");
2376 if (lightInfo
->glIndex
!= -1) {
2378 TRACE("Nothing to do as light was enabled\n");
2381 /* Find a free gl light */
2382 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2383 if(This
->stateBlock
->activeLights
[i
] == NULL
) {
2384 This
->stateBlock
->activeLights
[i
] = lightInfo
;
2385 lightInfo
->glIndex
= i
;
2389 if(lightInfo
->glIndex
== -1) {
2390 ERR("Too many concurrently active lights\n");
2391 return WINED3DERR_INVALIDCALL
;
2394 /* i == lightInfo->glIndex */
2395 if(!This
->isRecordingState
) {
2396 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2404 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
2406 PLIGHTINFOEL
*lightInfo
= NULL
;
2407 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2409 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2410 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2412 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
2413 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
2414 if(lightInfo
->OriginalIndex
== Index
) break;
2418 if (lightInfo
== NULL
) {
2419 TRACE("Light enabled state requested but light not defined\n");
2420 return WINED3DERR_INVALIDCALL
;
2422 /* true is 128 according to SetLightEnable */
2423 *pEnable
= lightInfo
->glIndex
!= -1 ? 128 : 0;
2428 * Get / Set Clip Planes
2430 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2431 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2432 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2434 /* Validate Index */
2435 if (Index
>= GL_LIMITS(clipplanes
)) {
2436 TRACE("Application has requested clipplane this device doesn't support\n");
2437 return WINED3DERR_INVALIDCALL
;
2440 This
->updateStateBlock
->changed
.clipplane
[Index
] = TRUE
;
2441 This
->updateStateBlock
->set
.clipplane
[Index
] = TRUE
;
2442 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2443 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2444 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2445 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2447 /* Handle recording of state blocks */
2448 if (This
->isRecordingState
) {
2449 TRACE("Recording... not performing anything\n");
2457 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2458 glMatrixMode(GL_MODELVIEW
);
2460 glLoadMatrixf((float *) &This
->stateBlock
->transforms
[WINED3DTS_VIEW
].u
.m
[0][0]);
2462 TRACE("Clipplane [%f,%f,%f,%f]\n",
2463 This
->updateStateBlock
->clipplane
[Index
][0],
2464 This
->updateStateBlock
->clipplane
[Index
][1],
2465 This
->updateStateBlock
->clipplane
[Index
][2],
2466 This
->updateStateBlock
->clipplane
[Index
][3]);
2467 glClipPlane(GL_CLIP_PLANE0
+ Index
, This
->updateStateBlock
->clipplane
[Index
]);
2468 checkGLcall("glClipPlane");
2476 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2477 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2478 TRACE("(%p) : for idx %d\n", This
, Index
);
2480 /* Validate Index */
2481 if (Index
>= GL_LIMITS(clipplanes
)) {
2482 TRACE("Application has requested clipplane this device doesn't support\n");
2483 return WINED3DERR_INVALIDCALL
;
2486 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2487 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2488 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2489 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2494 * Get / Set Clip Plane Status
2495 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2497 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2498 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2499 FIXME("(%p) : stub\n", This
);
2500 if (NULL
== pClipStatus
) {
2501 return WINED3DERR_INVALIDCALL
;
2503 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2504 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2508 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2509 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2510 FIXME("(%p) : stub\n", This
);
2511 if (NULL
== pClipStatus
) {
2512 return WINED3DERR_INVALIDCALL
;
2514 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2515 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2520 * Get / Set Material
2522 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2523 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2525 This
->updateStateBlock
->changed
.material
= TRUE
;
2526 This
->updateStateBlock
->set
.material
= TRUE
;
2527 memcpy(&This
->updateStateBlock
->material
, pMaterial
, sizeof(WINED3DMATERIAL
));
2529 /* Handle recording of state blocks */
2530 if (This
->isRecordingState
) {
2531 TRACE("Recording... not performing anything\n");
2536 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2537 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2538 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2539 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2540 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2541 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2542 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2543 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2544 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2546 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT
, (float*) &This
->updateStateBlock
->material
.Ambient
);
2547 checkGLcall("glMaterialfv(GL_AMBIENT)");
2548 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, (float*) &This
->updateStateBlock
->material
.Diffuse
);
2549 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2551 /* Only change material color if specular is enabled, otherwise it is set to black */
2552 if (This
->stateBlock
->renderState
[WINED3DRS_SPECULARENABLE
]) {
2553 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, (float*) &This
->updateStateBlock
->material
.Specular
);
2554 checkGLcall("glMaterialfv(GL_SPECULAR");
2556 float black
[4] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2557 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, &black
[0]);
2558 checkGLcall("glMaterialfv(GL_SPECULAR");
2560 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, (float*) &This
->updateStateBlock
->material
.Emissive
);
2561 checkGLcall("glMaterialfv(GL_EMISSION)");
2562 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, This
->updateStateBlock
->material
.Power
);
2563 checkGLcall("glMaterialf(GL_SHININESS");
2569 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2571 memcpy(pMaterial
, &This
->updateStateBlock
->material
, sizeof (WINED3DMATERIAL
));
2572 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2573 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2574 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2575 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2576 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2577 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2578 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2579 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2580 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2588 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
* pIndexData
,
2589 UINT BaseVertexIndex
) {
2590 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2591 IWineD3DIndexBuffer
*oldIdxs
;
2592 UINT oldBaseIndex
= This
->updateStateBlock
->baseVertexIndex
;
2594 TRACE("(%p) : Setting to %p, base %d\n", This
, pIndexData
, BaseVertexIndex
);
2595 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2597 This
->updateStateBlock
->changed
.indices
= TRUE
;
2598 This
->updateStateBlock
->set
.indices
= TRUE
;
2599 This
->updateStateBlock
->pIndexData
= pIndexData
;
2600 This
->updateStateBlock
->baseVertexIndex
= BaseVertexIndex
;
2602 /* Handle recording of state blocks */
2603 if (This
->isRecordingState
) {
2604 TRACE("Recording... not performing anything\n");
2608 /* So far only the base vertex index is tracked */
2609 if(BaseVertexIndex
!= oldBaseIndex
) {
2610 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2615 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DIndexBuffer
** ppIndexData
, UINT
* pBaseVertexIndex
) {
2616 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2618 *ppIndexData
= This
->stateBlock
->pIndexData
;
2620 /* up ref count on ppindexdata */
2622 IWineD3DIndexBuffer_AddRef(*ppIndexData
);
2623 *pBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
2624 TRACE("(%p) index data set to %p + %u\n", This
, ppIndexData
, This
->stateBlock
->baseVertexIndex
);
2626 TRACE("(%p) No index data set\n", This
);
2628 TRACE("Returning %p %d\n", *ppIndexData
, *pBaseVertexIndex
);
2633 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2634 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice
*iface
, UINT BaseIndex
) {
2635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2636 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2638 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2639 TRACE("Application is setting the old value over, nothing to do\n");
2643 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2645 if (This
->isRecordingState
) {
2646 TRACE("Recording... not performing anything\n");
2649 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2654 * Get / Set Viewports
2656 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2659 TRACE("(%p)\n", This
);
2660 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2661 This
->updateStateBlock
->set
.viewport
= TRUE
;
2662 memcpy(&This
->updateStateBlock
->viewport
, pViewport
, sizeof(WINED3DVIEWPORT
));
2664 /* Handle recording of state blocks */
2665 if (This
->isRecordingState
) {
2666 TRACE("Recording... not performing anything\n");
2670 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2671 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2673 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2678 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2679 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2680 TRACE("(%p)\n", This
);
2681 memcpy(pViewport
, &This
->stateBlock
->viewport
, sizeof(WINED3DVIEWPORT
));
2686 * Get / Set Render States
2687 * TODO: Verify against dx9 definitions
2689 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2691 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2692 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2694 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2696 This
->updateStateBlock
->changed
.renderState
[State
] = TRUE
;
2697 This
->updateStateBlock
->set
.renderState
[State
] = TRUE
;
2698 This
->updateStateBlock
->renderState
[State
] = Value
;
2700 /* Handle recording of state blocks */
2701 if (This
->isRecordingState
) {
2702 TRACE("Recording... not performing anything\n");
2706 /* Compared here and not before the assignment to allow proper stateblock recording */
2707 if(Value
== oldValue
) {
2708 TRACE("Application is setting the old value over, nothing to do\n");
2710 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2716 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2717 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2718 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2719 *pValue
= This
->stateBlock
->renderState
[State
];
2724 * Get / Set Sampler States
2725 * TODO: Verify against dx9 definitions
2728 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2730 DWORD oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2733 * SetSampler is designed to allow for more than the standard up to 8 textures
2734 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2735 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2737 * http://developer.nvidia.com/object/General_FAQ.html#t6
2739 * There are two new settings for GForce
2741 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2742 * and the texture one:
2743 * GL_MAX_TEXTURE_COORDS_ARB.
2744 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2746 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2747 if(Sampler
> GL_LIMITS(sampler_stages
) || Sampler
< 0 || Type
> WINED3D_HIGHEST_SAMPLER_STATE
|| Type
< 0) {
2748 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2749 Sampler
, debug_d3dsamplerstate(Type
), Type
, GL_LIMITS(sampler_stages
), WINED3D_HIGHEST_SAMPLER_STATE
);
2750 return WINED3DERR_INVALIDCALL
;
2753 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This
, Sampler
,
2754 debug_d3dsamplerstate(Type
), Type
, Value
);
2755 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2756 This
->updateStateBlock
->set
.samplerState
[Sampler
][Type
] = Value
;
2757 This
->updateStateBlock
->changed
.samplerState
[Sampler
][Type
] = Value
;
2759 /* Handle recording of state blocks */
2760 if (This
->isRecordingState
) {
2761 TRACE("Recording... not performing anything\n");
2765 if(oldValue
== Value
) {
2766 TRACE("Application is setting the old value over, nothing to do\n");
2770 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2775 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2776 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2777 /** TODO: check that sampler is in range **/
2778 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2779 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This
, Sampler
, Type
, *Value
);
2784 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2785 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2789 This
->updateStateBlock
->set
.scissorRect
= TRUE
;
2790 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2791 memcpy(&This
->updateStateBlock
->scissorRect
, pRect
, sizeof(*pRect
));
2793 if(This
->isRecordingState
) {
2794 TRACE("Recording... not performing anything\n");
2798 GetClientRect(((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->win_handle
, &windowRect
);
2799 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2800 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2802 winHeight
= windowRect
.bottom
- windowRect
.top
;
2803 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->bottom
- winHeight
,
2804 pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
2806 glScissor(pRect
->left
, winHeight
- pRect
->bottom
, pRect
->right
- pRect
->left
, pRect
->bottom
- pRect
->top
);
2807 checkGLcall("glScissor");
2813 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2814 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2816 memcpy(pRect
, &This
->updateStateBlock
->scissorRect
, sizeof(pRect
));
2817 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2821 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2822 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2823 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2825 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2827 This
->updateStateBlock
->vertexDecl
= pDecl
;
2828 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2829 This
->updateStateBlock
->set
.vertexDecl
= TRUE
;
2831 if (This
->isRecordingState
) {
2832 TRACE("Recording... not performing anything\n");
2834 } else if(pDecl
== oldDecl
) {
2835 /* Checked after the assignment to allow proper stateblock recording */
2836 TRACE("Application is setting the old declaration over, nothing to do\n");
2840 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2844 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2845 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2847 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2849 *ppDecl
= This
->stateBlock
->vertexDecl
;
2850 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2854 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2855 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2856 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2858 This
->updateStateBlock
->vertexShader
= pShader
;
2859 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2860 This
->updateStateBlock
->set
.vertexShader
= TRUE
;
2862 if (This
->isRecordingState
) {
2863 TRACE("Recording... not performing anything\n");
2865 } else if(oldShader
== pShader
) {
2866 /* Checked here to allow proper stateblock recording */
2867 TRACE("App is setting the old shader over, nothing to do\n");
2871 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2873 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2878 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2879 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2881 if (NULL
== ppShader
) {
2882 return WINED3DERR_INVALIDCALL
;
2884 *ppShader
= This
->stateBlock
->vertexShader
;
2885 if( NULL
!= *ppShader
)
2886 IWineD3DVertexShader_AddRef(*ppShader
);
2888 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2892 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2893 IWineD3DDevice
*iface
,
2895 CONST BOOL
*srcData
,
2898 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2899 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2902 iface
, srcData
, start
, count
);
2904 if (srcData
== NULL
|| cnt
< 0)
2905 return WINED3DERR_INVALIDCALL
;
2907 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2908 for (i
= 0; i
< cnt
; i
++)
2909 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2911 for (i
= start
; i
< cnt
+ start
; ++i
) {
2912 This
->updateStateBlock
->changed
.vertexShaderConstantsB
[i
] = TRUE
;
2913 This
->updateStateBlock
->set
.vertexShaderConstantsB
[i
] = TRUE
;
2916 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2921 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2922 IWineD3DDevice
*iface
,
2927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2928 int cnt
= min(count
, MAX_CONST_B
- start
);
2930 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2931 iface
, dstData
, start
, count
);
2933 if (dstData
== NULL
|| cnt
< 0)
2934 return WINED3DERR_INVALIDCALL
;
2936 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
2940 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
2941 IWineD3DDevice
*iface
,
2946 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2947 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
2949 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2950 iface
, srcData
, start
, count
);
2952 if (srcData
== NULL
|| cnt
< 0)
2953 return WINED3DERR_INVALIDCALL
;
2955 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
2956 for (i
= 0; i
< cnt
; i
++)
2957 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
2958 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2960 for (i
= start
; i
< cnt
+ start
; ++i
) {
2961 This
->updateStateBlock
->changed
.vertexShaderConstantsI
[i
] = TRUE
;
2962 This
->updateStateBlock
->set
.vertexShaderConstantsI
[i
] = TRUE
;
2965 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2970 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
2971 IWineD3DDevice
*iface
,
2976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2977 int cnt
= min(count
, MAX_CONST_I
- start
);
2979 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2980 iface
, dstData
, start
, count
);
2982 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
2983 return WINED3DERR_INVALIDCALL
;
2985 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
2989 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
2990 IWineD3DDevice
*iface
,
2992 CONST
float *srcData
,
2995 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2996 int i
, cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
2998 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2999 iface
, srcData
, start
, count
);
3001 if (srcData
== NULL
|| ((signed int) GL_LIMITS(vshader_constantsF
) - (signed int) start
) <= (signed int) 0)
3002 return WINED3DERR_INVALIDCALL
;
3004 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
3005 for (i
= 0; i
< cnt
; i
++)
3006 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3007 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3009 for (i
= start
; i
< cnt
+ start
; ++i
) {
3010 if (!This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
]) {
3011 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
3013 list_add_head(&This
->updateStateBlock
->set_vconstantsF
, &ptr
->entry
);
3014 This
->updateStateBlock
->set
.vertexShaderConstantsF
[i
] = TRUE
;
3016 This
->updateStateBlock
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
3019 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3024 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3025 IWineD3DDevice
*iface
,
3030 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3031 int cnt
= min(count
, GL_LIMITS(vshader_constantsF
) - start
);
3033 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3034 iface
, dstData
, start
, count
);
3036 if (dstData
== NULL
|| cnt
< 0)
3037 return WINED3DERR_INVALIDCALL
;
3039 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3043 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3045 for(i
= 0; i
< WINED3D_HIGHEST_TEXTURE_STATE
; i
++) {
3046 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3050 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3052 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3053 * it is never called.
3056 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3057 * that would be really messy and require shader recompilation
3058 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3059 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3060 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3061 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3063 if(This
->stateBlock
->pixelShader
|| This
->stateBlock
->lowest_disabled_stage
<= GL_LIMITS(textures
)) {
3064 if(This
->oneToOneTexUnitMap
) {
3065 TRACE("Not touching 1:1 map\n");
3068 TRACE("Restoring 1:1 texture unit mapping\n");
3069 /* Restore a 1:1 mapping */
3070 for(i
= 0; i
< MAX_SAMPLERS
; i
++) {
3071 if(This
->texUnitMap
[i
] != i
) {
3072 This
->texUnitMap
[i
] = i
;
3073 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3074 markTextureStagesDirty(This
, i
);
3077 This
->oneToOneTexUnitMap
= TRUE
;
3080 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3081 * First, see if we can succeed at all
3084 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3085 if(This
->stateBlock
->textures
[i
] == NULL
) tex
++;
3088 if(GL_LIMITS(textures
) + tex
< This
->stateBlock
->lowest_disabled_stage
) {
3089 FIXME("Too many bound textures to support the combiner settings\n");
3093 /* Now work out the mapping */
3095 This
->oneToOneTexUnitMap
= FALSE
;
3096 WARN("Non 1:1 mapping UNTESTED!\n");
3097 for(i
= 0; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3098 /* Skip NULL textures */
3099 if (!This
->stateBlock
->textures
[i
]) {
3100 /* Map to -1, so the check below doesn't fail if a non-NULL
3101 * texture is set on this stage */
3102 TRACE("Mapping texture stage %d to -1\n", i
);
3103 This
->texUnitMap
[i
] = -1;
3108 TRACE("Mapping texture stage %d to unit %d\n", i
, tex
);
3109 if(This
->texUnitMap
[i
] != tex
) {
3110 This
->texUnitMap
[i
] = tex
;
3111 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3112 markTextureStagesDirty(This
, i
);
3120 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3121 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3122 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3123 This
->updateStateBlock
->pixelShader
= pShader
;
3124 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3125 This
->updateStateBlock
->set
.pixelShader
= TRUE
;
3127 /* Handle recording of state blocks */
3128 if (This
->isRecordingState
) {
3129 TRACE("Recording... not performing anything\n");
3132 if (This
->isRecordingState
) {
3133 TRACE("Recording... not performing anything\n");
3137 if(pShader
== oldShader
) {
3138 TRACE("App is setting the old pixel shader over, nothing to do\n");
3142 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3143 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3145 /* Rebuild the texture unit mapping if nvrc's are supported */
3146 if(GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
3147 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3153 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3154 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3156 if (NULL
== ppShader
) {
3157 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3158 return WINED3DERR_INVALIDCALL
;
3161 *ppShader
= This
->stateBlock
->pixelShader
;
3162 if (NULL
!= *ppShader
) {
3163 IWineD3DPixelShader_AddRef(*ppShader
);
3165 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3169 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3170 IWineD3DDevice
*iface
,
3172 CONST BOOL
*srcData
,
3175 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3176 int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3178 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3179 iface
, srcData
, start
, count
);
3181 if (srcData
== NULL
|| cnt
< 0)
3182 return WINED3DERR_INVALIDCALL
;
3184 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3185 for (i
= 0; i
< cnt
; i
++)
3186 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3188 for (i
= start
; i
< cnt
+ start
; ++i
) {
3189 This
->updateStateBlock
->changed
.pixelShaderConstantsB
[i
] = TRUE
;
3190 This
->updateStateBlock
->set
.pixelShaderConstantsB
[i
] = TRUE
;
3193 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3198 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3199 IWineD3DDevice
*iface
,
3204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3205 int cnt
= min(count
, MAX_CONST_B
- start
);
3207 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3208 iface
, dstData
, start
, count
);
3210 if (dstData
== NULL
|| cnt
< 0)
3211 return WINED3DERR_INVALIDCALL
;
3213 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3217 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3218 IWineD3DDevice
*iface
,
3223 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3224 int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3226 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3227 iface
, srcData
, start
, count
);
3229 if (srcData
== NULL
|| cnt
< 0)
3230 return WINED3DERR_INVALIDCALL
;
3232 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3233 for (i
= 0; i
< cnt
; i
++)
3234 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3235 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3237 for (i
= start
; i
< cnt
+ start
; ++i
) {
3238 This
->updateStateBlock
->changed
.pixelShaderConstantsI
[i
] = TRUE
;
3239 This
->updateStateBlock
->set
.pixelShaderConstantsI
[i
] = TRUE
;
3242 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3247 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3248 IWineD3DDevice
*iface
,
3253 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3254 int cnt
= min(count
, MAX_CONST_I
- start
);
3256 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3257 iface
, dstData
, start
, count
);
3259 if (dstData
== NULL
|| cnt
< 0)
3260 return WINED3DERR_INVALIDCALL
;
3262 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3266 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3267 IWineD3DDevice
*iface
,
3269 CONST
float *srcData
,
3272 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3273 int i
, cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3275 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3276 iface
, srcData
, start
, count
);
3278 if (srcData
== NULL
|| cnt
< 0)
3279 return WINED3DERR_INVALIDCALL
;
3281 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, cnt
* sizeof(float) * 4);
3282 for (i
= 0; i
< cnt
; i
++)
3283 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3284 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3286 for (i
= start
; i
< cnt
+ start
; ++i
) {
3287 if (!This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
]) {
3288 constant_entry
*ptr
= HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry
));
3290 list_add_head(&This
->updateStateBlock
->set_pconstantsF
, &ptr
->entry
);
3291 This
->updateStateBlock
->set
.pixelShaderConstantsF
[i
] = TRUE
;
3293 This
->updateStateBlock
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
3296 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3301 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3302 IWineD3DDevice
*iface
,
3307 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3308 int cnt
= min(count
, GL_LIMITS(pshader_constantsF
) - start
);
3310 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3311 iface
, dstData
, start
, count
);
3313 if (dstData
== NULL
|| cnt
< 0)
3314 return WINED3DERR_INVALIDCALL
;
3316 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3320 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3322 process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
, WineDirect3DVertexStridedData
*lpStrideData
, DWORD SrcFVF
, IWineD3DVertexBufferImpl
*dest
, DWORD dwFlags
) {
3323 char *dest_ptr
, *dest_conv
= NULL
;
3325 DWORD DestFVF
= dest
->fvf
;
3327 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3331 if (SrcFVF
& WINED3DFVF_NORMAL
) {
3332 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3335 if ( (SrcFVF
& WINED3DFVF_POSITION_MASK
) != WINED3DFVF_XYZ
) {
3336 ERR("Source has no position mask\n");
3337 return WINED3DERR_INVALIDCALL
;
3340 /* We might access VBOs from this code, so hold the lock */
3343 if (dest
->resource
.allocatedMemory
== NULL
) {
3344 /* This may happen if we do direct locking into a vbo. Unlikely,
3345 * but theoretically possible(ddraw processvertices test)
3347 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
3348 if(!dest
->resource
.allocatedMemory
) {
3350 ERR("Out of memory\n");
3351 return E_OUTOFMEMORY
;
3355 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3356 checkGLcall("glBindBufferARB");
3357 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3359 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
3361 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3362 checkGLcall("glUnmapBufferARB");
3366 /* Get a pointer into the destination vbo(create one if none exists) and
3367 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3369 if(!dest
->vbo
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
3374 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->vbo
));
3375 dest_conv
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
));
3377 ERR("glMapBuffer failed\n");
3378 /* Continue without storing converted vertices */
3383 * a) WINED3DRS_CLIPPING is enabled
3384 * b) WINED3DVOP_CLIP is passed
3386 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3387 static BOOL warned
= FALSE
;
3389 * The clipping code is not quite correct. Some things need
3390 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3391 * so disable clipping for now.
3392 * (The graphics in Half-Life are broken, and my processvertices
3393 * test crashes with IDirect3DDevice3)
3399 FIXME("Clipping is broken and disabled for now\n");
3401 } else doClip
= FALSE
;
3402 dest_ptr
= ((char *) dest
->resource
.allocatedMemory
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3404 dest_conv
= ((char *) dest_conv
) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3407 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3410 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3411 WINED3DTS_PROJECTION
,
3413 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3414 WINED3DTS_WORLDMATRIX(0),
3417 TRACE("View mat:\n");
3418 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
);
3419 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
);
3420 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
);
3421 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
);
3423 TRACE("Proj mat:\n");
3424 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
);
3425 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
);
3426 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
);
3427 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
);
3429 TRACE("World mat:\n");
3430 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
);
3431 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
);
3432 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
);
3433 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
);
3435 /* Get the viewport */
3436 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3437 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3438 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3440 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3441 multiply_matrix(&mat
,&proj_mat
,&mat
);
3443 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3445 for (i
= 0; i
< dwCount
; i
+= 1) {
3446 unsigned int tex_index
;
3448 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3449 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3450 /* The position first */
3452 (float *) (((char *) lpStrideData
->u
.s
.position
.lpData
) + i
* lpStrideData
->u
.s
.position
.dwStride
);
3454 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3456 /* Multiplication with world, view and projection matrix */
3457 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
);
3458 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
);
3459 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
);
3460 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
);
3462 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3464 /* WARNING: The following things are taken from d3d7 and were not yet checked
3465 * against d3d8 or d3d9!
3468 /* Clipping conditions: From
3469 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3471 * A vertex is clipped if it does not match the following requirements
3475 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3477 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3478 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3483 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3484 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3487 /* "Normal" viewport transformation (not clipped)
3488 * 1) The values are divided by rhw
3489 * 2) The y axis is negative, so multiply it with -1
3490 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3491 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3492 * 4) Multiply x with Width/2 and add Width/2
3493 * 5) The same for the height
3494 * 6) Add the viewpoint X and Y to the 2D coordinates and
3495 * The minimum Z value to z
3496 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3498 * Well, basically it's simply a linear transformation into viewport
3510 z
*= vp
.MaxZ
- vp
.MinZ
;
3512 x
+= vp
.Width
/ 2 + vp
.X
;
3513 y
+= vp
.Height
/ 2 + vp
.Y
;
3518 /* That vertex got clipped
3519 * Contrary to OpenGL it is not dropped completely, it just
3520 * undergoes a different calculation.
3522 TRACE("Vertex got clipped\n");
3529 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3530 * outside of the main vertex buffer memory. That needs some more
3535 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3538 ( (float *) dest_ptr
)[0] = x
;
3539 ( (float *) dest_ptr
)[1] = y
;
3540 ( (float *) dest_ptr
)[2] = z
;
3541 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3543 dest_ptr
+= 3 * sizeof(float);
3545 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3546 dest_ptr
+= sizeof(float);
3551 ( (float *) dest_conv
)[0] = x
* w
;
3552 ( (float *) dest_conv
)[1] = y
* w
;
3553 ( (float *) dest_conv
)[2] = z
* w
;
3554 ( (float *) dest_conv
)[3] = w
;
3556 dest_conv
+= 3 * sizeof(float);
3558 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3559 dest_conv
+= sizeof(float);
3563 if (DestFVF
& WINED3DFVF_PSIZE
) {
3564 dest_ptr
+= sizeof(DWORD
);
3565 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3567 if (DestFVF
& WINED3DFVF_NORMAL
) {
3569 (float *) (((float *) lpStrideData
->u
.s
.normal
.lpData
) + i
* lpStrideData
->u
.s
.normal
.dwStride
);
3570 /* AFAIK this should go into the lighting information */
3571 FIXME("Didn't expect the destination to have a normal\n");
3572 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3574 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3578 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3580 (DWORD
*) (((char *) lpStrideData
->u
.s
.diffuse
.lpData
) + i
* lpStrideData
->u
.s
.diffuse
.dwStride
);
3582 static BOOL warned
= FALSE
;
3585 ERR("No diffuse color in source, but destination has one\n");
3589 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3590 dest_ptr
+= sizeof(DWORD
);
3593 *( (DWORD
*) dest_conv
) = 0xffffffff;
3594 dest_conv
+= sizeof(DWORD
);
3598 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3600 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3601 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3602 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3603 dest_conv
+= sizeof(DWORD
);
3608 if (DestFVF
& WINED3DFVF_SPECULAR
) {
3609 /* What's the color value in the feedback buffer? */
3611 (DWORD
*) (((char *) lpStrideData
->u
.s
.specular
.lpData
) + i
* lpStrideData
->u
.s
.specular
.dwStride
);
3613 static BOOL warned
= FALSE
;
3616 ERR("No specular color in source, but destination has one\n");
3620 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3621 dest_ptr
+= sizeof(DWORD
);
3624 *( (DWORD
*) dest_conv
) = 0xFF000000;
3625 dest_conv
+= sizeof(DWORD
);
3629 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3631 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3632 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3633 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3634 dest_conv
+= sizeof(DWORD
);
3639 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3641 (float *) (((char *) lpStrideData
->u
.s
.texCoords
[tex_index
].lpData
) +
3642 i
* lpStrideData
->u
.s
.texCoords
[tex_index
].dwStride
);
3644 ERR("No source texture, but destination requests one\n");
3645 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3646 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3649 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3651 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3658 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3659 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3666 #undef copy_and_next
3668 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
, UINT VertexCount
, IWineD3DVertexBuffer
* pDestBuffer
, IWineD3DVertexBuffer
* pVertexDecl
, DWORD Flags
) {
3669 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3670 IWineD3DVertexBufferImpl
*SrcImpl
= (IWineD3DVertexBufferImpl
*) pVertexDecl
;
3671 WineDirect3DVertexStridedData strided
;
3672 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3675 WARN("NULL source vertex buffer\n");
3676 return WINED3DERR_INVALIDCALL
;
3678 /* We don't need the source vbo because this buffer is only used as
3679 * a source for ProcessVertices. Avoid wasting resources by converting the
3680 * buffer and loading the VBO
3683 TRACE("Releasing the source vbo, it won't be needed\n");
3685 if(!SrcImpl
->resource
.allocatedMemory
) {
3686 /* Rescue the data from the buffer */
3688 SrcImpl
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, SrcImpl
->resource
.size
);
3689 if(!SrcImpl
->resource
.allocatedMemory
) {
3690 ERR("Out of memory\n");
3691 return E_OUTOFMEMORY
;
3695 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, SrcImpl
->vbo
));
3696 checkGLcall("glBindBufferARB");
3698 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
3700 memcpy(SrcImpl
->resource
.allocatedMemory
, src
, SrcImpl
->resource
.size
);
3703 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
3704 checkGLcall("glUnmapBufferARB");
3709 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, 0));
3710 checkGLcall("glBindBufferARB");
3711 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl
->vbo
));
3712 checkGLcall("glDeleteBuffersARB");
3718 memset(&strided
, 0, sizeof(strided
));
3719 primitiveConvertFVFtoOffset(SrcImpl
->fvf
, get_flexible_vertex_size(SrcImpl
->fvf
), SrcImpl
->resource
.allocatedMemory
+ get_flexible_vertex_size(SrcImpl
->fvf
) * SrcStartIndex
, &strided
, 0, 0);
3721 return process_vertices_strided(This
, DestIndex
, VertexCount
, &strided
, SrcImpl
->fvf
, (IWineD3DVertexBufferImpl
*) pDestBuffer
, Flags
);
3725 * Get / Set Texture Stage States
3726 * TODO: Verify against dx9 definitions
3728 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3730 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3732 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3734 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3736 /* Reject invalid texture units */
3737 if (Stage
>= GL_LIMITS(texture_stages
)) {
3738 TRACE("Attempt to access invalid texture rejected\n");
3739 return WINED3DERR_INVALIDCALL
;
3742 This
->updateStateBlock
->changed
.textureState
[Stage
][Type
] = TRUE
;
3743 This
->updateStateBlock
->set
.textureState
[Stage
][Type
] = TRUE
;
3744 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3746 if (This
->isRecordingState
) {
3747 TRACE("Recording... not performing anything\n");
3751 /* Checked after the assignments to allow proper stateblock recording */
3752 if(oldValue
== Value
) {
3753 TRACE("App is setting the old value over, nothing to do\n");
3757 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3758 StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3759 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3760 * Changes in other states are important on disabled stages too
3765 if(Type
== WINED3DTSS_COLOROP
) {
3768 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3769 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3770 * they have to be disabled
3772 * The current stage is dirtified below.
3774 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3775 TRACE("Additionally dirtifying stage %d\n", i
);
3776 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3778 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3779 TRACE("New lowest disabled: %d\n", Stage
);
3780 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3781 /* Previously disabled stage enabled. Stages above it may need enabling
3782 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3783 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3785 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3788 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
3789 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3792 TRACE("Additionally dirtifying stage %d due to enable\n", i
);
3793 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3795 This
->stateBlock
->lowest_disabled_stage
= i
;
3796 TRACE("New lowest disabled: %d\n", i
);
3798 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3799 /* TODO: Built a stage -> texture unit mapping for register combiners */
3803 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
3805 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3806 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3807 * will call FindTexUnitMap too.
3809 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3810 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3815 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
3816 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3817 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
3818 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3825 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
3827 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3828 IWineD3DBaseTexture
*oldTexture
;
3830 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
3831 TRACE("(%p) : Stage(%d), Texture (%p)\n", This
, Stage
, pTexture
);
3833 #if 0 /* TODO: check so vertex textures */
3834 if (Stage
>= D3DVERTEXTEXTURESAMPLER
&& Stage
<= D3DVERTEXTEXTURESAMPLER3
){
3835 This
->updateStateBlock
->vertexTextures
[Stage
- D3DVERTEXTEXTURESAMPLER
] = pTexture
;
3840 /* Reject invalid texture units */
3841 if (Stage
>= GL_LIMITS(sampler_stages
) || Stage
< 0) {
3842 WARN("Attempt to access invalid texture rejected\n");
3843 return WINED3DERR_INVALIDCALL
;
3846 if(pTexture
!= NULL
) {
3847 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3849 if(((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
) {
3850 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
3851 return WINED3DERR_INVALIDCALL
;
3853 This
->stateBlock
->textureDimensions
[Stage
] = IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
3856 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
3857 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
3859 This
->updateStateBlock
->set
.textures
[Stage
] = TRUE
;
3860 This
->updateStateBlock
->changed
.textures
[Stage
] = TRUE
;
3861 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
3862 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
3864 /* Handle recording of state blocks */
3865 if (This
->isRecordingState
) {
3866 TRACE("Recording... not performing anything\n");
3870 if(oldTexture
== pTexture
) {
3871 TRACE("App is setting the same texture again, nothing to do\n");
3875 /** NOTE: MSDN says that setTexture increases the reference count,
3876 * and the the application nust set the texture back to null (or have a leaky application),
3877 * This means we should pass the refcount up to the parent
3878 *******************************/
3879 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
3880 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
3881 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
3883 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
3884 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
3885 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3886 * so the COLOROP and ALPHAOP have to be dirtified.
3888 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
3889 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
3891 if(bindCount
== 1) {
3892 new->baseTexture
.sampler
= Stage
;
3894 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3898 if (NULL
!= oldTexture
) {
3899 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
3900 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
3902 IWineD3DBaseTexture_Release(oldTexture
);
3903 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
3904 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
3905 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
3908 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
3910 /* Have to do a search for the other sampler(s) where the texture is bound to
3911 * Shouldn't happen as long as apps bind a texture only to one stage
3913 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3914 for(i
= 0; i
< GL_LIMITS(sampler_stages
); i
++) {
3915 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
3916 old
->baseTexture
.sampler
= i
;
3923 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
3925 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3926 * pixel shader is used
3928 if(GL_SUPPORT(NV_REGISTER_COMBINERS
) && !This
->stateBlock
->pixelShader
) {
3929 IWineD3DDeviceImpl_FindTexUnitMap(This
);
3935 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
3936 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3937 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This
, Stage
, ppTexture
);
3939 /* Reject invalid texture units */
3940 if (Stage
>= GL_LIMITS(sampler_stages
)) {
3941 TRACE("Attempt to access invalid texture rejected\n");
3942 return WINED3DERR_INVALIDCALL
;
3944 *ppTexture
=This
->stateBlock
->textures
[Stage
];
3946 IWineD3DBaseTexture_AddRef(*ppTexture
);
3954 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
3955 IWineD3DSurface
**ppBackBuffer
) {
3956 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3957 IWineD3DSwapChain
*swapChain
;
3960 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
3962 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
3963 if (hr
== WINED3D_OK
) {
3964 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
3965 IWineD3DSwapChain_Release(swapChain
);
3967 *ppBackBuffer
= NULL
;
3972 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
3973 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3974 WARN("(%p) : stub, calling idirect3d for now\n", This
);
3975 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
3978 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
3979 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3980 IWineD3DSwapChain
*swapChain
;
3983 if(iSwapChain
> 0) {
3984 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
3985 if (hr
== WINED3D_OK
) {
3986 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
3987 IWineD3DSwapChain_Release(swapChain
);
3989 FIXME("(%p) Error getting display mode\n", This
);
3992 /* Don't read the real display mode,
3993 but return the stored mode instead. X11 can't change the color
3994 depth, and some apps are pretty angry if they SetDisplayMode from
3995 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3997 Also don't relay to the swapchain because with ddraw it's possible
3998 that there isn't a swapchain at all */
3999 pMode
->Width
= This
->ddraw_width
;
4000 pMode
->Height
= This
->ddraw_height
;
4001 pMode
->Format
= This
->ddraw_format
;
4002 pMode
->RefreshRate
= 0;
4009 static HRESULT WINAPI
IWineD3DDeviceImpl_SetHWND(IWineD3DDevice
*iface
, HWND hWnd
) {
4010 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4011 TRACE("(%p)->(%p)\n", This
, hWnd
);
4013 if(This
->ddraw_fullscreen
) {
4014 if(This
->ddraw_window
&& This
->ddraw_window
!= hWnd
) {
4015 IWineD3DDeviceImpl_RestoreWindow(iface
, This
->ddraw_window
);
4017 if(hWnd
&& This
->ddraw_window
!= hWnd
) {
4018 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, hWnd
);
4022 This
->ddraw_window
= hWnd
;
4026 static HRESULT WINAPI
IWineD3DDeviceImpl_GetHWND(IWineD3DDevice
*iface
, HWND
*hWnd
) {
4027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4028 TRACE("(%p)->(%p)\n", This
, hWnd
);
4030 *hWnd
= This
->ddraw_window
;
4035 * Stateblock related functions
4038 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4040 IWineD3DStateBlockImpl
*object
;
4041 HRESULT temp_result
;
4044 TRACE("(%p)\n", This
);
4046 if (This
->isRecordingState
) {
4047 return WINED3DERR_INVALIDCALL
;
4050 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DStateBlockImpl
));
4051 if (NULL
== object
) {
4052 FIXME("(%p)Error allocating memory for stateblock\n", This
);
4053 return E_OUTOFMEMORY
;
4055 TRACE("(%p) created object %p\n", This
, object
);
4056 object
->wineD3DDevice
= This
;
4057 /** FIXME: object->parent = parent; **/
4058 object
->parent
= NULL
;
4059 object
->blockType
= WINED3DSBT_ALL
;
4061 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
4063 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
4064 list_init(&object
->lightMap
[i
]);
4067 temp_result
= allocate_shader_constants(object
);
4068 if (WINED3D_OK
!= temp_result
)
4071 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4072 This
->updateStateBlock
= object
;
4073 This
->isRecordingState
= TRUE
;
4075 TRACE("(%p) recording stateblock %p\n",This
, object
);
4079 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4080 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4082 if (!This
->isRecordingState
) {
4083 FIXME("(%p) not recording! returning error\n", This
);
4084 *ppStateBlock
= NULL
;
4085 return WINED3DERR_INVALIDCALL
;
4088 *ppStateBlock
= (IWineD3DStateBlock
*)This
->updateStateBlock
;
4089 This
->isRecordingState
= FALSE
;
4090 This
->updateStateBlock
= This
->stateBlock
;
4091 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4092 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4093 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4098 * Scene related functions
4100 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4101 /* At the moment we have no need for any functionality at the beginning
4103 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4104 TRACE("(%p)\n", This
);
4107 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4108 return WINED3DERR_INVALIDCALL
;
4110 This
->inScene
= TRUE
;
4114 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
4115 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4116 TRACE("(%p)\n", This
);
4118 if(!This
->inScene
) {
4119 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4120 return WINED3DERR_INVALIDCALL
;
4124 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4126 checkGLcall("glFlush");
4129 This
->inScene
= FALSE
;
4133 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4134 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4135 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4136 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4137 IWineD3DSwapChain
*swapChain
= NULL
;
4139 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4141 TRACE("(%p) Presenting the frame\n", This
);
4143 for(i
= 0 ; i
< swapchains
; i
++) {
4145 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, (IWineD3DSwapChain
**)&swapChain
);
4146 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4147 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4148 IWineD3DSwapChain_Release(swapChain
);
4154 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4155 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4156 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4158 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4159 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4160 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4161 GLbitfield glMask
= 0;
4162 GLboolean old_ztest
;
4163 GLfloat old_z_clear_value
;
4164 GLint old_stencil_clear_value
;
4165 GLfloat old_color_clear_value
[4];
4167 CONST WINED3DRECT
* curRect
;
4169 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This
,
4170 Count
, pRects
, Flags
, Z
, Stencil
);
4174 glEnable(GL_SCISSOR_TEST
);
4175 checkGLcall("glEnable GL_SCISSOR_TEST");
4177 if (Count
> 0 && pRects
) {
4183 /* Only set the values up once, as they are not changing */
4184 if (Flags
& WINED3DCLEAR_STENCIL
) {
4185 glGetIntegerv(GL_STENCIL_CLEAR_VALUE
, &old_stencil_clear_value
);
4186 glClearStencil(Stencil
);
4187 checkGLcall("glClearStencil");
4188 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4189 glStencilMask(0xFFFFFFFF);
4192 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4193 glGetBooleanv(GL_DEPTH_WRITEMASK
, &old_ztest
);
4194 glDepthMask(GL_TRUE
);
4195 glGetFloatv(GL_DEPTH_CLEAR_VALUE
, &old_z_clear_value
);
4197 checkGLcall("glClearDepth");
4198 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4201 if (Flags
& WINED3DCLEAR_TARGET
) {
4202 TRACE("Clearing screen with glClear to color %x\n", Color
);
4203 glGetFloatv(GL_COLOR_CLEAR_VALUE
, old_color_clear_value
);
4204 glClearColor(D3DCOLOR_R(Color
),
4208 checkGLcall("glClearColor");
4210 /* Clear ALL colors! */
4211 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4212 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4215 /* Now process each rect in turn */
4216 for (i
= 0; i
< Count
|| i
== 0; i
++) {
4219 /* Note gl uses lower left, width/height */
4220 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
, curRect
,
4221 curRect
->x1
, curRect
->y1
, curRect
->x2
, curRect
->y2
,
4222 curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4223 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4224 glScissor(curRect
->x1
, (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
- curRect
->y2
),
4225 curRect
->x2
- curRect
->x1
, curRect
->y2
- curRect
->y1
);
4226 checkGLcall("glScissor");
4228 glScissor(This
->stateBlock
->viewport
.X
,
4229 (((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
-
4230 (This
->stateBlock
->viewport
.Y
+ This
->stateBlock
->viewport
.Height
)),
4231 This
->stateBlock
->viewport
.Width
,
4232 This
->stateBlock
->viewport
.Height
);
4233 checkGLcall("glScissor");
4236 /* Clear the selected rectangle (or full screen) */
4238 checkGLcall("glClear");
4240 /* Step to the next rectangle */
4241 if (curRect
) curRect
= curRect
+ sizeof(WINED3DRECT
);
4244 /* Restore the old values (why..?) */
4245 if (Flags
& WINED3DCLEAR_STENCIL
) {
4246 glClearStencil(old_stencil_clear_value
);
4247 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4249 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4250 glDepthMask(old_ztest
);
4251 glClearDepth(old_z_clear_value
);
4253 if (Flags
& WINED3DCLEAR_TARGET
) {
4254 glClearColor(old_color_clear_value
[0],
4255 old_color_clear_value
[1],
4256 old_color_clear_value
[2],
4257 old_color_clear_value
[3]);
4258 glColorMask(This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4259 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4260 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4261 This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
] & WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4264 glDisable(GL_SCISSOR_TEST
);
4265 checkGLcall("glDisable");
4268 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4269 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4271 ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->Flags
|= SFLAG_GLDIRTY
;
4278 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT StartVertex
,
4279 UINT PrimitiveCount
) {
4281 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4282 This
->stateBlock
->streamIsUP
= FALSE
;
4284 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This
, PrimitiveType
,
4285 debug_d3dprimitivetype(PrimitiveType
),
4286 StartVertex
, PrimitiveCount
);
4288 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4289 This
->stateBlock
->loadBaseVertexIndex
= 0;
4290 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4292 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4293 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, StartVertex
, 0/* NumVertices */, -1 /* indxStart */,
4294 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
4298 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4299 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
4300 WINED3DPRIMITIVETYPE PrimitiveType
,
4301 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT primCount
) {
4303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4305 IWineD3DIndexBuffer
*pIB
;
4306 WINED3DINDEXBUFFER_DESC IdxBufDsc
;
4308 pIB
= This
->stateBlock
->pIndexData
;
4309 This
->stateBlock
->streamIsUP
= FALSE
;
4311 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This
,
4312 PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4313 minIndex
, NumVertices
, startIndex
, primCount
);
4315 IWineD3DIndexBuffer_GetDesc(pIB
, &IdxBufDsc
);
4316 if (IdxBufDsc
.Format
== WINED3DFMT_INDEX16
) {
4322 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4323 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4324 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4327 drawPrimitive(iface
, PrimitiveType
, primCount
, 0, NumVertices
, startIndex
,
4328 idxStride
, ((IWineD3DIndexBufferImpl
*) pIB
)->resource
.allocatedMemory
, minIndex
);
4333 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4334 UINT PrimitiveCount
, CONST
void* pVertexStreamZeroData
,
4335 UINT VertexStreamZeroStride
) {
4336 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4338 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This
, PrimitiveType
,
4339 debug_d3dprimitivetype(PrimitiveType
),
4340 PrimitiveCount
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4342 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4343 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4344 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4345 This
->stateBlock
->streamIsUP
= TRUE
;
4346 This
->stateBlock
->loadBaseVertexIndex
= 0;
4348 /* TODO: Only mark dirty if drawing from a different UP address */
4349 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4351 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* start vertex */, 0 /* NumVertices */,
4352 0 /* indxStart*/, 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
4354 /* MSDN specifies stream zero settings must be set to NULL */
4355 This
->stateBlock
->streamStride
[0] = 0;
4356 This
->stateBlock
->streamSource
[0] = NULL
;
4358 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4359 * the new stream sources or use UP drawing again
4364 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
,
4365 UINT MinVertexIndex
, UINT NumVertices
,
4366 UINT PrimitiveCount
, CONST
void* pIndexData
,
4367 WINED3DFORMAT IndexDataFormat
,CONST
void* pVertexStreamZeroData
,
4368 UINT VertexStreamZeroStride
) {
4370 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4372 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4373 This
, PrimitiveType
, debug_d3dprimitivetype(PrimitiveType
),
4374 MinVertexIndex
, NumVertices
, PrimitiveCount
, pIndexData
,
4375 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4377 if (IndexDataFormat
== WINED3DFMT_INDEX16
) {
4383 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4384 This
->stateBlock
->streamSource
[0] = (IWineD3DVertexBuffer
*)pVertexStreamZeroData
;
4385 This
->stateBlock
->streamIsUP
= TRUE
;
4386 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4388 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4389 This
->stateBlock
->baseVertexIndex
= 0;
4390 This
->stateBlock
->loadBaseVertexIndex
= 0;
4391 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4392 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4394 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0 /* vertexStart */, NumVertices
, 0 /* indxStart */, idxStride
, pIndexData
, MinVertexIndex
);
4396 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4397 This
->stateBlock
->streamSource
[0] = NULL
;
4398 This
->stateBlock
->streamStride
[0] = 0;
4399 This
->stateBlock
->pIndexData
= NULL
;
4400 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4401 * SetStreamSource to specify a vertex buffer
4407 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice
*iface
, WINED3DPRIMITIVETYPE PrimitiveType
, UINT PrimitiveCount
, WineDirect3DVertexStridedData
*DrawPrimStrideData
) {
4408 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4410 /* Mark the state dirty until we have nicer tracking
4411 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4414 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4415 This
->stateBlock
->baseVertexIndex
= 0;
4416 This
->up_strided
= DrawPrimStrideData
;
4417 drawPrimitive(iface
, PrimitiveType
, PrimitiveCount
, 0, 0, 0, 0, NULL
, 0);
4418 This
->up_strided
= NULL
;
4421 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4422 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
4423 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4424 HRESULT hr
= WINED3D_OK
;
4425 WINED3DRESOURCETYPE sourceType
;
4426 WINED3DRESOURCETYPE destinationType
;
4429 /* TODO: think about moving the code into IWineD3DBaseTexture */
4431 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
4433 /* verify that the source and destination textures aren't NULL */
4434 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
4435 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4436 This
, pSourceTexture
, pDestinationTexture
);
4437 hr
= WINED3DERR_INVALIDCALL
;
4440 if (pSourceTexture
== pDestinationTexture
) {
4441 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4442 This
, pSourceTexture
, pDestinationTexture
);
4443 hr
= WINED3DERR_INVALIDCALL
;
4445 /* Verify that the source and destination textures are the same type */
4446 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
4447 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
4449 if (sourceType
!= destinationType
) {
4450 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4452 hr
= WINED3DERR_INVALIDCALL
;
4455 /* check that both textures have the identical numbers of levels */
4456 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
4457 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
4458 hr
= WINED3DERR_INVALIDCALL
;
4461 if (WINED3D_OK
== hr
) {
4463 /* Make sure that the destination texture is loaded */
4464 IWineD3DBaseTexture_PreLoad(pDestinationTexture
);
4466 /* Update every surface level of the texture */
4467 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
4469 switch (sourceType
) {
4470 case WINED3DRTYPE_TEXTURE
:
4472 IWineD3DSurface
*srcSurface
;
4473 IWineD3DSurface
*destSurface
;
4475 for (i
= 0 ; i
< levels
; ++i
) {
4476 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
4477 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
4478 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4479 IWineD3DSurface_Release(srcSurface
);
4480 IWineD3DSurface_Release(destSurface
);
4481 if (WINED3D_OK
!= hr
) {
4482 WARN("(%p) : Call to update surface failed\n", This
);
4488 case WINED3DRTYPE_CUBETEXTURE
:
4490 IWineD3DSurface
*srcSurface
;
4491 IWineD3DSurface
*destSurface
;
4492 WINED3DCUBEMAP_FACES faceType
;
4494 for (i
= 0 ; i
< levels
; ++i
) {
4495 /* Update each cube face */
4496 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
4497 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
4498 if (WINED3D_OK
!= hr
) {
4499 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4501 TRACE("Got srcSurface %p\n", srcSurface
);
4503 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
4504 if (WINED3D_OK
!= hr
) {
4505 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
4507 TRACE("Got desrSurface %p\n", destSurface
);
4509 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
4510 IWineD3DSurface_Release(srcSurface
);
4511 IWineD3DSurface_Release(destSurface
);
4512 if (WINED3D_OK
!= hr
) {
4513 WARN("(%p) : Call to update surface failed\n", This
);
4520 #if 0 /* TODO: Add support for volume textures */
4521 case WINED3DRTYPE_VOLUMETEXTURE
:
4523 IWineD3DVolume srcVolume
= NULL
;
4524 IWineD3DSurface destVolume
= NULL
;
4526 for (i
= 0 ; i
< levels
; ++i
) {
4527 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
4528 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
4529 hr
= IWineD3DFoo_UpdateVolume(iface
, srcVolume
, NULL
, destVolume
, NULL
);
4530 IWineD3DVolume_Release(srcSurface
);
4531 IWineD3DVolume_Release(destSurface
);
4532 if (WINED3D_OK
!= hr
) {
4533 WARN("(%p) : Call to update volume failed\n", This
);
4541 FIXME("(%p) : Unsupported source and destination type\n", This
);
4542 hr
= WINED3DERR_INVALIDCALL
;
4549 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4550 IWineD3DSwapChain
*swapChain
;
4552 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4553 if(hr
== WINED3D_OK
) {
4554 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4555 IWineD3DSwapChain_Release(swapChain
);
4560 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4561 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4562 /* return a sensible default */
4564 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4565 FIXME("(%p) : stub\n", This
);
4569 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4570 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4572 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4573 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4574 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4575 return WINED3DERR_INVALIDCALL
;
4577 for (j
= 0; j
< 256; ++j
) {
4578 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
4579 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
4580 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
4581 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
4583 TRACE("(%p) : returning\n", This
);
4587 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
4588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4590 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4591 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4592 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4593 return WINED3DERR_INVALIDCALL
;
4595 for (j
= 0; j
< 256; ++j
) {
4596 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
4597 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
4598 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
4599 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
4601 TRACE("(%p) : returning\n", This
);
4605 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
4606 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4607 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4608 if ( PaletteNumber
< 0 || PaletteNumber
>= MAX_PALETTES
) {
4609 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4610 return WINED3DERR_INVALIDCALL
;
4612 /*TODO: stateblocks */
4613 This
->currentPalette
= PaletteNumber
;
4614 TRACE("(%p) : returning\n", This
);
4618 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
4619 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4620 if (PaletteNumber
== NULL
) {
4621 WARN("(%p) : returning Invalid Call\n", This
);
4622 return WINED3DERR_INVALIDCALL
;
4624 /*TODO: stateblocks */
4625 *PaletteNumber
= This
->currentPalette
;
4626 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
4630 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
4631 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4632 static BOOL showFixmes
= TRUE
;
4634 FIXME("(%p) : stub\n", This
);
4638 This
->softwareVertexProcessing
= bSoftware
;
4643 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
4644 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4645 static BOOL showFixmes
= TRUE
;
4647 FIXME("(%p) : stub\n", This
);
4650 return This
->softwareVertexProcessing
;
4654 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
4655 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4656 IWineD3DSwapChain
*swapChain
;
4659 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
4661 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, (IWineD3DSwapChain
**)&swapChain
);
4662 if(hr
== WINED3D_OK
){
4663 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
4664 IWineD3DSwapChain_Release(swapChain
);
4666 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
4672 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
4673 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4674 static BOOL showfixmes
= TRUE
;
4675 if(nSegments
!= 0.0f
) {
4677 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
4684 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
4685 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4686 static BOOL showfixmes
= TRUE
;
4688 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
4694 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
4695 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4696 /** TODO: remove casts to IWineD3DSurfaceImpl
4697 * NOTE: move code to surface to accomplish this
4698 ****************************************/
4699 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
4700 int srcWidth
, srcHeight
;
4701 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
4702 WINED3DFORMAT destFormat
, srcFormat
;
4704 int srcLeft
, destLeft
, destTop
;
4705 WINED3DPOOL srcPool
, destPool
;
4707 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4708 glDescriptor
*glDescription
= NULL
;
4709 GLenum textureDimensions
= GL_TEXTURE_2D
;
4710 IWineD3DBaseTexture
*baseTexture
;
4712 WINED3DSURFACE_DESC winedesc
;
4714 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
4715 memset(&winedesc
, 0, sizeof(winedesc
));
4716 winedesc
.Width
= &srcSurfaceWidth
;
4717 winedesc
.Height
= &srcSurfaceHeight
;
4718 winedesc
.Pool
= &srcPool
;
4719 winedesc
.Format
= &srcFormat
;
4721 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
4723 winedesc
.Width
= &destSurfaceWidth
;
4724 winedesc
.Height
= &destSurfaceHeight
;
4725 winedesc
.Pool
= &destPool
;
4726 winedesc
.Format
= &destFormat
;
4727 winedesc
.Size
= &destSize
;
4729 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
4731 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
4732 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
4733 return WINED3DERR_INVALIDCALL
;
4736 if (destFormat
== WINED3DFMT_UNKNOWN
) {
4737 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
4738 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
4740 /* Get the update surface description */
4741 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
4744 /* Make sure the surface is loaded and up to date */
4745 IWineD3DSurface_PreLoad(pDestinationSurface
);
4747 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
4751 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4752 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
4753 srcHeight
= pSourceRect
? pSourceRect
->top
- pSourceRect
->bottom
: srcSurfaceHeight
;
4754 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
4755 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
4756 destTop
= pDestPoint
? pDestPoint
->y
: 0;
4759 /* This function doesn't support compressed textures
4760 the pitch is just bytesPerPixel * width */
4761 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
4762 rowoffset
= (srcSurfaceWidth
- srcWidth
) * pSrcSurface
->bytesPerPixel
;
4763 offset
+= srcLeft
* pSrcSurface
->bytesPerPixel
;
4764 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4766 /* TODO DXT formats */
4768 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
4769 offset
+= pSourceRect
->top
* srcWidth
* pSrcSurface
->bytesPerPixel
;
4771 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4773 ,glDescription
->level
4778 ,glDescription
->glFormat
4779 ,glDescription
->glType
4780 ,IWineD3DSurface_GetData(pSourceSurface
)
4784 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
4786 /* need to lock the surface to get the data */
4787 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4790 /* TODO: Cube and volume support */
4792 /* not a whole row so we have to do it a line at a time */
4795 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4796 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
4798 for(j
= destTop
; j
< (srcHeight
+ destTop
) ; j
++){
4800 glTexSubImage2D(glDescription
->target
4801 ,glDescription
->level
4806 ,glDescription
->glFormat
4807 ,glDescription
->glType
4808 ,data
/* could be quicker using */
4813 } else { /* Full width, so just write out the whole texture */
4815 if (WINED3DFMT_DXT1
== destFormat
||
4816 WINED3DFMT_DXT2
== destFormat
||
4817 WINED3DFMT_DXT3
== destFormat
||
4818 WINED3DFMT_DXT4
== destFormat
||
4819 WINED3DFMT_DXT5
== destFormat
) {
4820 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
4821 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
4822 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4823 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4824 } if (destFormat
!= srcFormat
) {
4825 FIXME("Updating mixed format compressed texture is not curretly support\n");
4827 GL_EXTCALL(glCompressedTexImage2DARB
)(glDescription
->target
,
4828 glDescription
->level
,
4829 glDescription
->glFormatInternal
,
4834 IWineD3DSurface_GetData(pSourceSurface
));
4837 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4842 glTexSubImage2D(glDescription
->target
4843 ,glDescription
->level
4848 ,glDescription
->glFormat
4849 ,glDescription
->glType
4850 ,IWineD3DSurface_GetData(pSourceSurface
)
4854 checkGLcall("glTexSubImage2D");
4855 ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->Flags
|= SFLAG_GLDIRTY
;
4857 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4858 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4859 * surface bigger than it needs to be hmm.. */
4860 if (WINED3D_OK
== IWineD3DSurface_GetContainer(pDestinationSurface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
)) {
4861 textureDimensions
= IWineD3DBaseTexture_GetTextureDimensions(baseTexture
);
4862 IWineD3DBaseTexture_Release(baseTexture
);
4865 glDisable(textureDimensions
); /* This needs to be managed better.... */
4871 /* Implementation details at http://developer.nvidia.com/attach/6494
4873 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4874 hmm.. no longer supported use
4875 OpenGL evaluators or tessellate surfaces within your application.
4878 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4879 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
4880 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4881 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
4882 FIXME("(%p) : Stub\n", This
);
4887 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4888 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
4889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4890 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
4891 FIXME("(%p) : Stub\n", This
);
4895 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
4896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4897 TRACE("(%p) Handle(%d)\n", This
, Handle
);
4898 FIXME("(%p) : Stub\n", This
);
4902 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
4903 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4904 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
4906 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This
, pSurface
, pRect
, color
);
4908 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
4909 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4910 return WINED3DERR_INVALIDCALL
;
4913 /* Just forward this to the DirectDraw blitting engine */
4914 memset(&BltFx
, 0, sizeof(BltFx
));
4915 BltFx
.dwSize
= sizeof(BltFx
);
4916 BltFx
.u5
.dwFillColor
= color
;
4917 return IWineD3DSurface_Blt(pSurface
, (RECT
*) pRect
, NULL
, NULL
, DDBLT_COLORFILL
, &BltFx
);
4920 /* rendertarget and deptth stencil functions */
4921 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
4922 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4924 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
4925 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
4926 return WINED3DERR_INVALIDCALL
;
4929 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
4930 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
4931 /* Note inc ref on returned surface */
4932 if(*ppRenderTarget
!= NULL
)
4933 IWineD3DSurface_AddRef(*ppRenderTarget
);
4937 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
4938 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4939 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
4940 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
4941 IWineD3DSwapChainImpl
*Swapchain
;
4944 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
4946 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
4947 if(hr
!= WINED3D_OK
) {
4948 ERR("Can't get the swapchain\n");
4952 /* Make sure to release the swapchain */
4953 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
4955 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
4956 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4957 return WINED3DERR_INVALIDCALL
;
4959 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
4960 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4961 return WINED3DERR_INVALIDCALL
;
4964 if(Swapchain
->frontBuffer
!= Front
) {
4965 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
4967 if(Swapchain
->frontBuffer
)
4968 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
4969 Swapchain
->frontBuffer
= Front
;
4971 if(Swapchain
->frontBuffer
) {
4972 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
4976 if(Back
&& !Swapchain
->backBuffer
) {
4977 /* We need memory for the back buffer array - only one back buffer this way */
4978 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
4979 if(!Swapchain
->backBuffer
) {
4980 ERR("Out of memory\n");
4981 return E_OUTOFMEMORY
;
4985 if(Swapchain
->backBuffer
[0] != Back
) {
4986 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
4988 if(!Swapchain
->backBuffer
[0]) {
4989 /* GL was told to draw to the front buffer at creation,
4992 glDrawBuffer(GL_BACK
);
4993 checkGLcall("glDrawBuffer(GL_BACK)");
4994 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4995 Swapchain
->presentParms
.BackBufferCount
= 1;
4997 /* That makes problems - disable for now */
4998 /* glDrawBuffer(GL_FRONT); */
4999 checkGLcall("glDrawBuffer(GL_FRONT)");
5000 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5001 Swapchain
->presentParms
.BackBufferCount
= 0;
5005 if(Swapchain
->backBuffer
[0])
5006 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5007 Swapchain
->backBuffer
[0] = Back
;
5009 if(Swapchain
->backBuffer
[0]) {
5010 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5012 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
5020 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5021 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5022 *ppZStencilSurface
= This
->depthStencilBuffer
;
5023 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5025 if(*ppZStencilSurface
!= NULL
) {
5026 /* Note inc ref on returned surface */
5027 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5032 static void bind_fbo(IWineD3DDevice
*iface
) {
5033 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5036 GL_EXTCALL(glGenFramebuffersEXT(1, &This
->fbo
));
5037 checkGLcall("glGenFramebuffersEXT()");
5039 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, This
->fbo
));
5040 checkGLcall("glBindFramebuffer()");
5043 /* TODO: Handle stencil attachments */
5044 static void set_depth_stencil_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
) {
5045 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5046 IWineD3DSurfaceImpl
*depth_stencil_impl
= (IWineD3DSurfaceImpl
*)depth_stencil
;
5048 This
->depth_copy_state
= WINED3D_DCS_NO_COPY
;
5052 if (depth_stencil_impl
) {
5053 GLenum texttarget
, target
;
5054 GLint old_binding
= 0;
5056 IWineD3DSurface_PreLoad(depth_stencil
);
5057 texttarget
= depth_stencil_impl
->glDescription
.target
;
5058 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5060 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5061 glBindTexture(target
, depth_stencil_impl
->glDescription
.textureName
);
5062 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5063 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5064 glTexParameteri(target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5065 glBindTexture(target
, old_binding
);
5067 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, texttarget
, depth_stencil_impl
->glDescription
.textureName
, 0));
5068 checkGLcall("glFramebufferTexture2DEXT()");
5070 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_TEXTURE_2D
, 0, 0));
5071 checkGLcall("glFramebufferTexture2DEXT()");
5074 if (!This
->render_offscreen
) {
5075 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5076 checkGLcall("glBindFramebuffer()");
5080 void set_render_target_fbo(IWineD3DDevice
*iface
, DWORD idx
, IWineD3DSurface
*render_target
) {
5081 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5082 IWineD3DSurfaceImpl
*rtimpl
= (IWineD3DSurfaceImpl
*)render_target
;
5084 if (idx
>= GL_LIMITS(buffers
)) {
5085 ERR("%p : Trying to set render target %d, but only %d supported\n", This
, idx
, GL_LIMITS(buffers
));
5091 GLenum texttarget
, target
;
5092 GLint old_binding
= 0;
5094 IWineD3DSurface_PreLoad(render_target
);
5095 texttarget
= rtimpl
->glDescription
.target
;
5096 target
= texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_2D
: GL_TEXTURE_CUBE_MAP_ARB
;
5098 glGetIntegerv(texttarget
== GL_TEXTURE_2D
? GL_TEXTURE_BINDING_2D
: GL_TEXTURE_BINDING_CUBE_MAP_ARB
, &old_binding
);
5099 glBindTexture(target
, rtimpl
->glDescription
.textureName
);
5100 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
5101 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
5102 glBindTexture(target
, old_binding
);
5104 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, texttarget
, rtimpl
->glDescription
.textureName
, 0));
5105 checkGLcall("glFramebufferTexture2DEXT()");
5107 This
->draw_buffers
[idx
] = GL_COLOR_ATTACHMENT0_EXT
+ idx
;
5109 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
+ idx
, GL_TEXTURE_2D
, 0, 0));
5110 checkGLcall("glFramebufferTexture2DEXT()");
5112 This
->draw_buffers
[idx
] = GL_NONE
;
5115 if (GL_SUPPORT(ARB_DRAW_BUFFERS
)) {
5116 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers
), This
->draw_buffers
));
5117 checkGLcall("glDrawBuffers()");
5120 if (!This
->render_offscreen
) {
5121 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
5122 checkGLcall("glBindFramebuffer()");
5126 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
5127 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5128 WINED3DVIEWPORT viewport
;
5130 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5132 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
5133 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
5134 return WINED3DERR_INVALIDCALL
;
5137 /* MSDN says that null disables the render target
5138 but a device must always be associated with a render target
5139 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5141 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5144 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5145 FIXME("Trying to set render target 0 to NULL\n");
5146 return WINED3DERR_INVALIDCALL
;
5148 if (pRenderTarget
&& !((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
5149 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
);
5150 return WINED3DERR_INVALIDCALL
;
5153 /* If we are trying to set what we already have, don't bother */
5154 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5155 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5158 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5159 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5160 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5162 /* Render target 0 is special */
5163 if(RenderTargetIndex
== 0) {
5164 /* Finally, reset the viewport as the MSDN states. */
5165 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5166 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5169 viewport
.MaxZ
= 1.0f
;
5170 viewport
.MinZ
= 0.0f
;
5171 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
5173 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5175 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5176 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5178 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5180 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5181 set_render_target_fbo(iface
, RenderTargetIndex
, pRenderTarget
);
5186 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5188 HRESULT hr
= WINED3D_OK
;
5189 IWineD3DSurface
*tmp
;
5191 TRACE("(%p) Swapping z-buffer\n",This
);
5193 if (pNewZStencil
== This
->stencilBufferTarget
) {
5194 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5196 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5197 * depending on the renter target implementation being used.
5198 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5199 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5200 * stencil buffer and incure an extra memory overhead
5201 ******************************************************/
5204 tmp
= This
->stencilBufferTarget
;
5205 This
->stencilBufferTarget
= pNewZStencil
;
5206 /* should we be calling the parent or the wined3d surface? */
5207 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5208 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5210 /** TODO: glEnable/glDisable on depth/stencil depending on
5211 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5212 **********************************************************/
5213 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5214 set_depth_stencil_fbo(iface
, pNewZStencil
);
5221 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5222 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5223 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5224 /* TODO: the use of Impl is deprecated. */
5225 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5227 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5229 /* some basic validation checks */
5230 if(This
->cursorTexture
) {
5232 glDeleteTextures(1, &This
->cursorTexture
);
5234 This
->cursorTexture
= 0;
5238 /* MSDN: Cursor must be A8R8G8B8 */
5239 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format
) {
5240 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5241 return WINED3DERR_INVALIDCALL
;
5244 /* MSDN: Cursor must be smaller than the display mode */
5245 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
5246 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
5247 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
);
5248 return WINED3DERR_INVALIDCALL
;
5251 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5252 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5253 * Texture and Blitting code to draw the cursor
5255 pSur
->Flags
|= SFLAG_FORCELOAD
;
5256 IWineD3DSurface_PreLoad(pCursorBitmap
);
5257 pSur
->Flags
&= ~SFLAG_FORCELOAD
;
5258 /* Do not store the surface's pointer because the application may release
5259 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5260 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5262 This
->cursorTexture
= pSur
->glDescription
.textureName
;
5263 This
->cursorWidth
= pSur
->currentDesc
.Width
;
5264 This
->cursorHeight
= pSur
->currentDesc
.Height
;
5265 pSur
->glDescription
.textureName
= 0; /* Prevent the texture from being changed or deleted */
5268 This
->xHotSpot
= XHotSpot
;
5269 This
->yHotSpot
= YHotSpot
;
5273 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
5274 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5275 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
5277 This
->xScreenSpace
= XScreenSpace
;
5278 This
->yScreenSpace
= YScreenSpace
;
5284 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
5285 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5286 BOOL oldVisible
= This
->bCursorVisible
;
5287 TRACE("(%p) : visible(%d)\n", This
, bShow
);
5289 if(This
->cursorTexture
)
5290 This
->bCursorVisible
= bShow
;
5295 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
5296 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5297 TRACE("(%p) : state (%u)\n", This
, This
->state
);
5298 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5299 switch (This
->state
) {
5302 case WINED3DERR_DEVICELOST
:
5304 ResourceList
*resourceList
= This
->resources
;
5305 while (NULL
!= resourceList
) {
5306 if (((IWineD3DResourceImpl
*)resourceList
->resource
)->resource
.pool
== WINED3DPOOL_DEFAULT
/* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5307 return WINED3DERR_DEVICENOTRESET
;
5308 resourceList
= resourceList
->next
;
5310 return WINED3DERR_DEVICELOST
;
5312 case WINED3DERR_DRIVERINTERNALERROR
:
5313 return WINED3DERR_DRIVERINTERNALERROR
;
5317 return WINED3DERR_DRIVERINTERNALERROR
;
5321 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
5322 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5323 /** FIXME: Resource tracking needs to be done,
5324 * The closes we can do to this is set the priorities of all managed textures low
5325 * and then reset them.
5326 ***********************************************************/
5327 FIXME("(%p) : stub\n", This
);
5331 void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
5332 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
5334 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5335 if(surface
->Flags
& SFLAG_DIBSECTION
) {
5336 /* Release the DC */
5337 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
5338 DeleteDC(surface
->hDC
);
5339 /* Release the DIB section */
5340 DeleteObject(surface
->dib
.DIBsection
);
5341 surface
->dib
.bitmap_data
= NULL
;
5342 surface
->resource
.allocatedMemory
= NULL
;
5343 surface
->Flags
&= ~SFLAG_DIBSECTION
;
5345 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
5346 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
5347 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
)) {
5348 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
5349 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
5351 surface
->pow2Width
= surface
->pow2Height
= 1;
5352 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
5353 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
5355 if(surface
->glDescription
.textureName
) {
5357 glDeleteTextures(1, &surface
->glDescription
.textureName
);
5359 surface
->glDescription
.textureName
= 0;
5361 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
5362 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
5363 surface
->Flags
|= SFLAG_NONPOW2
;
5365 surface
->Flags
&= ~SFLAG_NONPOW2
;
5367 HeapFree(GetProcessHeap(), 0, surface
->resource
.allocatedMemory
);
5368 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
5371 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
5372 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5373 IWineD3DSwapChainImpl
*swapchain
;
5375 BOOL DisplayModeChanged
= FALSE
;
5376 WINED3DDISPLAYMODE mode
;
5377 TRACE("(%p)\n", This
);
5379 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
5381 ERR("Failed to get the first implicit swapchain\n");
5385 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5386 * on an existing gl context, so there's no real need for recreation.
5388 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5390 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5392 TRACE("New params:\n");
5393 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
5394 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
5395 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
5396 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
5397 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
5398 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
5399 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
5400 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
5401 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
5402 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
5403 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
5404 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
5405 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
5407 /* No special treatment of these parameters. Just store them */
5408 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
5409 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
5410 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
5411 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
5413 /* What to do about these? */
5414 if(pPresentationParameters
->BackBufferCount
!= 0 &&
5415 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
5416 ERR("Cannot change the back buffer count yet\n");
5418 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
5419 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
5420 ERR("Cannot change the back buffer format yet\n");
5422 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
5423 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
5424 ERR("Cannot change the device window yet\n");
5426 if(pPresentationParameters
->EnableAutoDepthStencil
!= swapchain
->presentParms
.EnableAutoDepthStencil
) {
5427 ERR("What do do about a changed auto depth stencil parameter?\n");
5430 if(pPresentationParameters
->Windowed
) {
5431 mode
.Width
= swapchain
->orig_width
;
5432 mode
.Height
= swapchain
->orig_height
;
5433 mode
.RefreshRate
= 0;
5434 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
5436 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
5437 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
5438 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
5439 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
5442 /* Should Width == 800 && Height == 0 set 800x600? */
5443 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
5444 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
5445 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
5452 vp
.Width
= pPresentationParameters
->BackBufferWidth
;
5453 vp
.Height
= pPresentationParameters
->BackBufferHeight
;
5457 if(!pPresentationParameters
->Windowed
) {
5458 DisplayModeChanged
= TRUE
;
5460 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
5461 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
5463 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
5464 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
5465 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
5468 /* Now set the new viewport */
5469 IWineD3DDevice_SetViewport(iface
, &vp
);
5472 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
5473 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
5474 DisplayModeChanged
) {
5476 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5477 if(!pPresentationParameters
->Windowed
) {
5478 IWineD3DDevice_SetFullscreen(iface
, TRUE
);
5481 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
5483 /* Switching out of fullscreen mode? First set the original res, then change the window */
5484 if(pPresentationParameters
->Windowed
) {
5485 IWineD3DDevice_SetFullscreen(iface
, FALSE
);
5487 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
5490 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5494 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
5495 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5496 /** FIXME: always true at the moment **/
5497 if(!bEnableDialogs
) {
5498 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
5504 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
5505 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5506 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
5508 *pParameters
= This
->createParms
;
5512 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
5513 IWineD3DSwapChain
*swapchain
;
5514 HRESULT hrc
= WINED3D_OK
;
5516 TRACE("Relaying to swapchain\n");
5518 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
5519 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, (WINED3DGAMMARAMP
*)pRamp
);
5520 IWineD3DSwapChain_Release(swapchain
);
5525 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
5526 IWineD3DSwapChain
*swapchain
;
5527 HRESULT hrc
= WINED3D_OK
;
5529 TRACE("Relaying to swapchain\n");
5531 if ((hrc
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
)) == WINED3D_OK
) {
5532 hrc
=IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
5533 IWineD3DSwapChain_Release(swapchain
);
5539 /** ********************************************************
5540 * Notification functions
5541 ** ********************************************************/
5542 /** This function must be called in the release of a resource when ref == 0,
5543 * the contents of resource must still be correct,
5544 * any handels to other resource held by the caller must be closed
5545 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5546 *****************************************************/
5547 static void WINAPI
IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5548 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5549 ResourceList
* resourceList
;
5551 TRACE("(%p) : resource %p\n", This
, resource
);
5553 EnterCriticalSection(&resourceStoreCriticalSection
);
5555 /* add a new texture to the frot of the linked list */
5556 resourceList
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ResourceList
));
5557 resourceList
->resource
= resource
;
5559 /* Get the old head */
5560 resourceList
->next
= This
->resources
;
5562 This
->resources
= resourceList
;
5563 TRACE("Added resource %p with element %p pointing to %p\n", resource
, resourceList
, resourceList
->next
);
5566 LeaveCriticalSection(&resourceStoreCriticalSection
);
5571 static void WINAPI
IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5572 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5573 ResourceList
* resourceList
= NULL
;
5574 ResourceList
* previousResourceList
= NULL
;
5576 TRACE("(%p) : resource %p\n", This
, resource
);
5579 EnterCriticalSection(&resourceStoreCriticalSection
);
5581 resourceList
= This
->resources
;
5583 while (resourceList
!= NULL
) {
5584 if(resourceList
->resource
== resource
) break;
5585 previousResourceList
= resourceList
;
5586 resourceList
= resourceList
->next
;
5589 if (resourceList
== NULL
) {
5590 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource
);
5592 LeaveCriticalSection(&resourceStoreCriticalSection
);
5596 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList
->resource
, resourceList
, resourceList
->next
, previousResourceList
);
5598 /* make sure we don't leave a hole in the list */
5599 if (previousResourceList
!= NULL
) {
5600 previousResourceList
->next
= resourceList
->next
;
5602 This
->resources
= resourceList
->next
;
5606 LeaveCriticalSection(&resourceStoreCriticalSection
);
5612 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
5613 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5616 TRACE("(%p) : resource %p\n", This
, resource
);
5617 switch(IWineD3DResource_GetType(resource
)){
5618 case WINED3DRTYPE_SURFACE
:
5619 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5621 case WINED3DRTYPE_TEXTURE
:
5622 case WINED3DRTYPE_CUBETEXTURE
:
5623 case WINED3DRTYPE_VOLUMETEXTURE
:
5624 for (counter
= 0; counter
< GL_LIMITS(sampler_stages
); counter
++) {
5625 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
5626 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
5627 This
->stateBlock
->textures
[counter
] = NULL
;
5629 if (This
->updateStateBlock
!= This
->stateBlock
){
5630 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
5631 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
5632 This
->updateStateBlock
->textures
[counter
] = NULL
;
5637 case WINED3DRTYPE_VOLUME
:
5638 /* TODO: nothing really? */
5640 case WINED3DRTYPE_VERTEXBUFFER
:
5641 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5644 TRACE("Cleaning up stream pointers\n");
5646 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
5647 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5648 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5650 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5651 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
5652 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
5653 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
5654 /* Set changed flag? */
5657 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) */
5658 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
5659 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
5660 This
->stateBlock
->streamSource
[streamNumber
] = 0;
5663 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5664 else { /* This shouldn't happen */
5665 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5672 case WINED3DRTYPE_INDEXBUFFER
:
5673 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5674 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5675 if (This
->updateStateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
5676 This
->updateStateBlock
->pIndexData
= NULL
;
5679 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
5680 if (This
->stateBlock
->pIndexData
== (IWineD3DIndexBuffer
*)resource
) {
5681 This
->stateBlock
->pIndexData
= NULL
;
5687 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
5692 /* Remove the resoruce from the resourceStore */
5693 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
5695 TRACE("Resource released\n");
5699 /**********************************************************
5700 * IWineD3DDevice VTbl follows
5701 **********************************************************/
5703 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
5705 /*** IUnknown methods ***/
5706 IWineD3DDeviceImpl_QueryInterface
,
5707 IWineD3DDeviceImpl_AddRef
,
5708 IWineD3DDeviceImpl_Release
,
5709 /*** IWineD3DDevice methods ***/
5710 IWineD3DDeviceImpl_GetParent
,
5711 /*** Creation methods**/
5712 IWineD3DDeviceImpl_CreateVertexBuffer
,
5713 IWineD3DDeviceImpl_CreateIndexBuffer
,
5714 IWineD3DDeviceImpl_CreateStateBlock
,
5715 IWineD3DDeviceImpl_CreateSurface
,
5716 IWineD3DDeviceImpl_CreateTexture
,
5717 IWineD3DDeviceImpl_CreateVolumeTexture
,
5718 IWineD3DDeviceImpl_CreateVolume
,
5719 IWineD3DDeviceImpl_CreateCubeTexture
,
5720 IWineD3DDeviceImpl_CreateQuery
,
5721 IWineD3DDeviceImpl_CreateAdditionalSwapChain
,
5722 IWineD3DDeviceImpl_CreateVertexDeclaration
,
5723 IWineD3DDeviceImpl_CreateVertexShader
,
5724 IWineD3DDeviceImpl_CreatePixelShader
,
5725 IWineD3DDeviceImpl_CreatePalette
,
5726 /*** Odd functions **/
5727 IWineD3DDeviceImpl_Init3D
,
5728 IWineD3DDeviceImpl_Uninit3D
,
5729 IWineD3DDeviceImpl_SetFullscreen
,
5730 IWineD3DDeviceImpl_EnumDisplayModes
,
5731 IWineD3DDeviceImpl_EvictManagedResources
,
5732 IWineD3DDeviceImpl_GetAvailableTextureMem
,
5733 IWineD3DDeviceImpl_GetBackBuffer
,
5734 IWineD3DDeviceImpl_GetCreationParameters
,
5735 IWineD3DDeviceImpl_GetDeviceCaps
,
5736 IWineD3DDeviceImpl_GetDirect3D
,
5737 IWineD3DDeviceImpl_GetDisplayMode
,
5738 IWineD3DDeviceImpl_SetDisplayMode
,
5739 IWineD3DDeviceImpl_GetHWND
,
5740 IWineD3DDeviceImpl_SetHWND
,
5741 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
5742 IWineD3DDeviceImpl_GetRasterStatus
,
5743 IWineD3DDeviceImpl_GetSwapChain
,
5744 IWineD3DDeviceImpl_Reset
,
5745 IWineD3DDeviceImpl_SetDialogBoxMode
,
5746 IWineD3DDeviceImpl_SetCursorProperties
,
5747 IWineD3DDeviceImpl_SetCursorPosition
,
5748 IWineD3DDeviceImpl_ShowCursor
,
5749 IWineD3DDeviceImpl_TestCooperativeLevel
,
5750 /*** Getters and setters **/
5751 IWineD3DDeviceImpl_SetClipPlane
,
5752 IWineD3DDeviceImpl_GetClipPlane
,
5753 IWineD3DDeviceImpl_SetClipStatus
,
5754 IWineD3DDeviceImpl_GetClipStatus
,
5755 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
5756 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
5757 IWineD3DDeviceImpl_SetDepthStencilSurface
,
5758 IWineD3DDeviceImpl_GetDepthStencilSurface
,
5759 IWineD3DDeviceImpl_SetFVF
,
5760 IWineD3DDeviceImpl_GetFVF
,
5761 IWineD3DDeviceImpl_SetGammaRamp
,
5762 IWineD3DDeviceImpl_GetGammaRamp
,
5763 IWineD3DDeviceImpl_SetIndices
,
5764 IWineD3DDeviceImpl_GetIndices
,
5765 IWineD3DDeviceImpl_SetBasevertexIndex
,
5766 IWineD3DDeviceImpl_SetLight
,
5767 IWineD3DDeviceImpl_GetLight
,
5768 IWineD3DDeviceImpl_SetLightEnable
,
5769 IWineD3DDeviceImpl_GetLightEnable
,
5770 IWineD3DDeviceImpl_SetMaterial
,
5771 IWineD3DDeviceImpl_GetMaterial
,
5772 IWineD3DDeviceImpl_SetNPatchMode
,
5773 IWineD3DDeviceImpl_GetNPatchMode
,
5774 IWineD3DDeviceImpl_SetPaletteEntries
,
5775 IWineD3DDeviceImpl_GetPaletteEntries
,
5776 IWineD3DDeviceImpl_SetPixelShader
,
5777 IWineD3DDeviceImpl_GetPixelShader
,
5778 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
5779 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
5780 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
5781 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
5782 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
5783 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
5784 IWineD3DDeviceImpl_SetRenderState
,
5785 IWineD3DDeviceImpl_GetRenderState
,
5786 IWineD3DDeviceImpl_SetRenderTarget
,
5787 IWineD3DDeviceImpl_GetRenderTarget
,
5788 IWineD3DDeviceImpl_SetFrontBackBuffers
,
5789 IWineD3DDeviceImpl_SetSamplerState
,
5790 IWineD3DDeviceImpl_GetSamplerState
,
5791 IWineD3DDeviceImpl_SetScissorRect
,
5792 IWineD3DDeviceImpl_GetScissorRect
,
5793 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
5794 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
5795 IWineD3DDeviceImpl_SetStreamSource
,
5796 IWineD3DDeviceImpl_GetStreamSource
,
5797 IWineD3DDeviceImpl_SetStreamSourceFreq
,
5798 IWineD3DDeviceImpl_GetStreamSourceFreq
,
5799 IWineD3DDeviceImpl_SetTexture
,
5800 IWineD3DDeviceImpl_GetTexture
,
5801 IWineD3DDeviceImpl_SetTextureStageState
,
5802 IWineD3DDeviceImpl_GetTextureStageState
,
5803 IWineD3DDeviceImpl_SetTransform
,
5804 IWineD3DDeviceImpl_GetTransform
,
5805 IWineD3DDeviceImpl_SetVertexDeclaration
,
5806 IWineD3DDeviceImpl_GetVertexDeclaration
,
5807 IWineD3DDeviceImpl_SetVertexShader
,
5808 IWineD3DDeviceImpl_GetVertexShader
,
5809 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
5810 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
5811 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
5812 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
5813 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
5814 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
5815 IWineD3DDeviceImpl_SetViewport
,
5816 IWineD3DDeviceImpl_GetViewport
,
5817 IWineD3DDeviceImpl_MultiplyTransform
,
5818 IWineD3DDeviceImpl_ValidateDevice
,
5819 IWineD3DDeviceImpl_ProcessVertices
,
5820 /*** State block ***/
5821 IWineD3DDeviceImpl_BeginStateBlock
,
5822 IWineD3DDeviceImpl_EndStateBlock
,
5823 /*** Scene management ***/
5824 IWineD3DDeviceImpl_BeginScene
,
5825 IWineD3DDeviceImpl_EndScene
,
5826 IWineD3DDeviceImpl_Present
,
5827 IWineD3DDeviceImpl_Clear
,
5829 IWineD3DDeviceImpl_DrawPrimitive
,
5830 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
5831 IWineD3DDeviceImpl_DrawPrimitiveUP
,
5832 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
5833 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
5834 IWineD3DDeviceImpl_DrawRectPatch
,
5835 IWineD3DDeviceImpl_DrawTriPatch
,
5836 IWineD3DDeviceImpl_DeletePatch
,
5837 IWineD3DDeviceImpl_ColorFill
,
5838 IWineD3DDeviceImpl_UpdateTexture
,
5839 IWineD3DDeviceImpl_UpdateSurface
,
5840 IWineD3DDeviceImpl_GetFrontBufferData
,
5841 /*** object tracking ***/
5842 IWineD3DDeviceImpl_ResourceReleased
5846 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
5847 WINED3DRS_ALPHABLENDENABLE
,
5848 WINED3DRS_ALPHAFUNC
,
5849 WINED3DRS_ALPHAREF
,
5850 WINED3DRS_ALPHATESTENABLE
,
5852 WINED3DRS_COLORWRITEENABLE
,
5853 WINED3DRS_DESTBLEND
,
5854 WINED3DRS_DITHERENABLE
,
5855 WINED3DRS_FILLMODE
,
5856 WINED3DRS_FOGDENSITY
,
5858 WINED3DRS_FOGSTART
,
5859 WINED3DRS_LASTPIXEL
,
5860 WINED3DRS_SHADEMODE
,
5861 WINED3DRS_SRCBLEND
,
5862 WINED3DRS_STENCILENABLE
,
5863 WINED3DRS_STENCILFAIL
,
5864 WINED3DRS_STENCILFUNC
,
5865 WINED3DRS_STENCILMASK
,
5866 WINED3DRS_STENCILPASS
,
5867 WINED3DRS_STENCILREF
,
5868 WINED3DRS_STENCILWRITEMASK
,
5869 WINED3DRS_STENCILZFAIL
,
5870 WINED3DRS_TEXTUREFACTOR
,
5881 WINED3DRS_ZWRITEENABLE
5884 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
5885 WINED3DTSS_ADDRESSW
,
5886 WINED3DTSS_ALPHAARG0
,
5887 WINED3DTSS_ALPHAARG1
,
5888 WINED3DTSS_ALPHAARG2
,
5889 WINED3DTSS_ALPHAOP
,
5890 WINED3DTSS_BUMPENVLOFFSET
,
5891 WINED3DTSS_BUMPENVLSCALE
,
5892 WINED3DTSS_BUMPENVMAT00
,
5893 WINED3DTSS_BUMPENVMAT01
,
5894 WINED3DTSS_BUMPENVMAT10
,
5895 WINED3DTSS_BUMPENVMAT11
,
5896 WINED3DTSS_COLORARG0
,
5897 WINED3DTSS_COLORARG1
,
5898 WINED3DTSS_COLORARG2
,
5899 WINED3DTSS_COLOROP
,
5900 WINED3DTSS_RESULTARG
,
5901 WINED3DTSS_TEXCOORDINDEX
,
5902 WINED3DTSS_TEXTURETRANSFORMFLAGS
5905 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
5906 WINED3DSAMP_ADDRESSU
,
5907 WINED3DSAMP_ADDRESSV
,
5908 WINED3DSAMP_ADDRESSW
,
5909 WINED3DSAMP_BORDERCOLOR
,
5910 WINED3DSAMP_MAGFILTER
,
5911 WINED3DSAMP_MINFILTER
,
5912 WINED3DSAMP_MIPFILTER
,
5913 WINED3DSAMP_MIPMAPLODBIAS
,
5914 WINED3DSAMP_MAXMIPLEVEL
,
5915 WINED3DSAMP_MAXANISOTROPY
,
5916 WINED3DSAMP_SRGBTEXTURE
,
5917 WINED3DSAMP_ELEMENTINDEX
5920 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
5922 WINED3DRS_AMBIENTMATERIALSOURCE
,
5923 WINED3DRS_CLIPPING
,
5924 WINED3DRS_CLIPPLANEENABLE
,
5925 WINED3DRS_COLORVERTEX
,
5926 WINED3DRS_DIFFUSEMATERIALSOURCE
,
5927 WINED3DRS_EMISSIVEMATERIALSOURCE
,
5928 WINED3DRS_FOGDENSITY
,
5930 WINED3DRS_FOGSTART
,
5931 WINED3DRS_FOGTABLEMODE
,
5932 WINED3DRS_FOGVERTEXMODE
,
5933 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
5934 WINED3DRS_LIGHTING
,
5935 WINED3DRS_LOCALVIEWER
,
5936 WINED3DRS_MULTISAMPLEANTIALIAS
,
5937 WINED3DRS_MULTISAMPLEMASK
,
5938 WINED3DRS_NORMALIZENORMALS
,
5939 WINED3DRS_PATCHEDGESTYLE
,
5940 WINED3DRS_POINTSCALE_A
,
5941 WINED3DRS_POINTSCALE_B
,
5942 WINED3DRS_POINTSCALE_C
,
5943 WINED3DRS_POINTSCALEENABLE
,
5944 WINED3DRS_POINTSIZE
,
5945 WINED3DRS_POINTSIZE_MAX
,
5946 WINED3DRS_POINTSIZE_MIN
,
5947 WINED3DRS_POINTSPRITEENABLE
,
5948 WINED3DRS_RANGEFOGENABLE
,
5949 WINED3DRS_SPECULARMATERIALSOURCE
,
5950 WINED3DRS_TWEENFACTOR
,
5951 WINED3DRS_VERTEXBLEND
5954 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
5955 WINED3DTSS_TEXCOORDINDEX
,
5956 WINED3DTSS_TEXTURETRANSFORMFLAGS
5959 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
5960 WINED3DSAMP_DMAPOFFSET
5963 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
5964 DWORD rep
= StateTable
[state
].representative
;
5968 WineD3DContext
*context
;
5971 for(i
= 0; i
< This
->numContexts
; i
++) {
5972 context
= This
->contexts
[i
];
5973 if(isStateDirty(context
, rep
)) continue;
5975 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
5978 context
->isStateDirty
[idx
] |= (1 << shift
);