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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
225 case D3DLIGHT_DIRECTIONAL:
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 ptr = list_head( &This->glsl_shader_progs );
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
293 This->stateBlock->shaderPrgId = curLink->programId;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
303 This->stateBlock->shaderPrgId = programId;
305 /* Allocate a new link for the list of programs */
306 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
307 newLink->programId = programId;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
350 /** Detach the GLSL pixel or vertex shader object from the shader program */
351 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
355 if (shaderObj != 0 && programId != 0) {
356 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
357 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
358 checkGLcall("glDetachObjectARB");
362 /** Delete a GLSL shader program */
363 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
368 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
369 GL_EXTCALL(glDeleteObjectARB(obj));
370 checkGLcall("glDeleteObjectARB");
374 /** Delete the list of linked programs this shader is associated with.
375 * Also at this point, check to see if there are any objects left attached
376 * to each GLSL program. If not, delete the GLSL program object.
377 * This will be run when a device is released. */
378 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
380 struct list *ptr = NULL;
381 struct glsl_shader_prog_link *curLink = NULL;
382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
386 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
387 (one pixel shader and one vertex shader at most) */
389 ptr = list_head( &This->glsl_shader_progs );
391 /* First, get the current item,
392 * save the link to the next pointer,
393 * detach and delete shader objects,
394 * then de-allocate the list item's memory */
395 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
396 ptr = list_next( &This->glsl_shader_progs, ptr );
398 /* See if this object is still attached to the program - it may have been detached already */
399 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
400 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
401 for (i = 0; i < numAttached; i++) {
402 detach_glsl_shader(iface, objList[i], curLink->programId);
405 delete_glsl_shader_program(iface, curLink->programId);
407 /* Free the memory for this list item */
408 HeapFree(GetProcessHeap(), 0, curLink);
413 /* Apply the current values to the specified texture stage */
414 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
423 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
424 clamping, MIPLOD, etc. This will work for up to 16 samplers.
427 if (Sampler >= GL_LIMITS(sampler_stages)) {
428 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
431 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
432 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
434 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
435 checkGLcall("glActiveTextureARB");
437 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
438 } else if (Sampler > 0) {
439 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
443 /* TODO: change this to a lookup table
444 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
445 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
446 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
447 especially when there are a number of groups of states. */
449 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
451 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
452 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
453 /* these are the only two supported states that need to be applied */
454 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
455 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
456 #if 0 /* not supported at the moment */
457 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
458 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
459 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
460 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
461 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
462 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
463 APPLY_STATE(WINED3DTSS_RESULTARG);
464 APPLY_STATE(WINED3DTSS_CONSTANT);
466 /* a quick sanity check in case someone forgot to update this function */
467 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
468 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
472 /* apply any sampler states that always need applying */
473 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
474 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
475 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
476 GL_TEXTURE_LOD_BIAS_EXT,
478 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
481 /* Note the D3DRS value applies to all textures, but GL has one
482 * per texture, so apply it now ready to be used!
484 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
485 /* Set the default alpha blend color */
486 if (GL_SUPPORT(ARB_IMAGING)) {
487 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
488 checkGLcall("glBlendColor");
490 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
493 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
494 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
495 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
497 /* TODO: NV_POINT_SPRITE */
498 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
499 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
500 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
501 glDisable(GL_POINT_SMOOTH);
503 /* Centre the texture on the vertex */
504 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
505 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
507 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
508 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
509 checkGLcall("glTexEnvf(...)");
510 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
511 glEnable( GL_POINT_SPRITE_ARB );
512 checkGLcall("glEnable(...)");
514 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
515 glDisable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
520 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
523 /**********************************************************
524 * IUnknown parts follows
525 **********************************************************/
527 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
532 if (IsEqualGUID(riid, &IID_IUnknown)
533 || IsEqualGUID(riid, &IID_IWineD3DBase)
534 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
535 IUnknown_AddRef(iface);
540 return E_NOINTERFACE;
543 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
545 ULONG refCount = InterlockedIncrement(&This->ref);
547 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
551 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
553 ULONG refCount = InterlockedDecrement(&This->ref);
555 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
558 /* TODO: Clean up all the surfaces and textures! */
559 /* NOTE: You must release the parent if the object was created via a callback
560 ** ***************************/
562 /* Delete any GLSL shader programs that may exist */
563 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
564 wined3d_settings.ps_selected_mode == SHADER_GLSL)
565 delete_glsl_shader_list(iface);
567 /* Release the update stateblock */
568 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
569 if(This->updateStateBlock != This->stateBlock)
570 FIXME("(%p) Something's still holding the Update stateblock\n",This);
572 This->updateStateBlock = NULL;
573 { /* because were not doing proper internal refcounts releasing the primary state block
574 causes recursion with the extra checks in ResourceReleased, to avoid this we have
575 to set this->stateBlock = NULL; first */
576 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
577 This->stateBlock = NULL;
579 /* Release the stateblock */
580 if(IWineD3DStateBlock_Release(stateBlock) > 0){
581 FIXME("(%p) Something's still holding the Update stateblock\n",This);
585 if (This->resources != NULL ) {
586 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
587 dumpResources(This->resources);
591 IWineD3D_Release(This->wineD3D);
592 This->wineD3D = NULL;
593 HeapFree(GetProcessHeap(), 0, This);
594 TRACE("Freed device %p\n", This);
600 /**********************************************************
601 * IWineD3DDevice implementation follows
602 **********************************************************/
603 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
605 *pParent = This->parent;
606 IUnknown_AddRef(This->parent);
610 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
611 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
612 GLenum error, glUsage;
613 DWORD vboUsage = object->resource.usage;
614 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
615 WARN("Creating a vbo failed once, not trying again\n");
619 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
622 /* Make sure that the gl error is cleared. Do not use checkGLcall
623 * here because checkGLcall just prints a fixme and continues. However,
624 * if an error during VBO creation occurs we can fall back to non-vbo operation
625 * with full functionality(but performance loss)
627 while(glGetError() != GL_NO_ERROR);
629 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
630 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
631 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
632 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
633 * to check if the rhw and color values are in the correct format.
636 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
637 error = glGetError();
638 if(object->vbo == 0 || error != GL_NO_ERROR) {
639 WARN("Failed to create a VBO with error %d\n", error);
643 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
644 error = glGetError();
645 if(error != GL_NO_ERROR) {
646 WARN("Failed to bind the VBO, error %d\n", error);
650 /* Transformed vertices are horribly inflexible. If the app specifies an
651 * vertex buffer with transformed vertices in default pool without DYNAMIC
652 * usage assume DYNAMIC usage and print a warning. The app will have to update
653 * the vertices regularily for them to be useful
655 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
656 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
657 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
658 vboUsage |= WINED3DUSAGE_DYNAMIC;
661 /* Don't use static, because dx apps tend to update the buffer
662 * quite often even if they specify 0 usage
664 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
665 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
666 TRACE("Gl usage = GL_STREAM_DRAW\n");
667 glUsage = GL_STREAM_DRAW_ARB;
669 case D3DUSAGE_WRITEONLY:
670 TRACE("Gl usage = GL_STATIC_DRAW\n");
671 glUsage = GL_DYNAMIC_DRAW_ARB;
673 case D3DUSAGE_DYNAMIC:
674 TRACE("Gl usage = GL_STREAM_COPY\n");
675 glUsage = GL_STREAM_COPY_ARB;
678 TRACE("Gl usage = GL_STATIC_COPY\n");
679 glUsage = GL_DYNAMIC_COPY_ARB;
683 /* Reserve memory for the buffer. The amount of data won't change
684 * so we are safe with calling glBufferData once with a NULL ptr and
685 * calling glBufferSubData on updates
687 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
688 error = glGetError();
689 if(error != GL_NO_ERROR) {
690 WARN("glBufferDataARB failed with error %d\n", error);
698 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
699 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
700 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
702 object->Flags |= VBFLAG_VBOCREATEFAIL;
707 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
708 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
711 IWineD3DVertexBufferImpl *object;
712 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
713 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
715 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
717 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
718 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
720 if(Size == 0) return WINED3DERR_INVALIDCALL;
722 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
723 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
727 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
728 * drawStridedFast (half-life 2).
730 * Basically converting the vertices in the buffer is quite expensive, and observations
731 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
732 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
734 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
735 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
736 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
737 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
739 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
740 * more. In this call we can convert dx7 buffers too.
742 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
743 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
744 (dxVersion > 7 || !conv) ) {
747 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
748 if(dxVersion == 7 && object->vbo) {
749 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
750 object->resource.allocatedMemory = NULL;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
758 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
759 HANDLE *sharedHandle, IUnknown *parent) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DIndexBufferImpl *object;
762 TRACE("(%p) Creating index buffer\n", This);
764 /* Allocate the storage for the device */
765 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
768 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
769 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
772 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
773 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
774 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DStateBlockImpl *object;
786 D3DCREATEOBJECTINSTANCE(object, StateBlock)
787 object->blockType = Type;
789 /* Special case - Used during initialization to produce a placeholder stateblock
790 so other functions called can update a state block */
791 if (Type == WINED3DSBT_INIT) {
792 /* Don't bother increasing the reference count otherwise a device will never
793 be freed due to circular dependencies */
797 temp_result = allocate_shader_constants(object);
798 if (WINED3D_OK != temp_result)
801 /* Otherwise, might as well set the whole state block to the appropriate values */
802 if (This->stateBlock != NULL)
803 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
805 memset(object->streamFreq, 1, sizeof(object->streamFreq));
807 /* Reset the ref and type after kludging it */
808 object->wineD3DDevice = This;
810 object->blockType = Type;
812 TRACE("Updating changed flags appropriate for type %d\n", Type);
814 if (Type == WINED3DSBT_ALL) {
816 TRACE("ALL => Pretend everything has changed\n");
817 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
819 } else if (Type == WINED3DSBT_PIXELSTATE) {
821 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
822 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
824 object->changed.pixelShader = TRUE;
826 /* Pixel Shader Constants */
827 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
828 object->changed.pixelShaderConstantsF[i] = TRUE;
829 for (i = 0; i < MAX_CONST_B; ++i)
830 object->changed.pixelShaderConstantsB[i] = TRUE;
831 for (i = 0; i < MAX_CONST_I; ++i)
832 object->changed.pixelShaderConstantsI[i] = TRUE;
834 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
835 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
837 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
839 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
842 for (j = 0 ; j < 16; j++) {
843 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
845 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
849 } else if (Type == WINED3DSBT_VERTEXSTATE) {
851 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
852 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
854 object->changed.vertexShader = TRUE;
856 /* Vertex Shader Constants */
857 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
858 object->changed.vertexShaderConstantsF[i] = TRUE;
859 for (i = 0; i < MAX_CONST_B; ++i)
860 object->changed.vertexShaderConstantsB[i] = TRUE;
861 for (i = 0; i < MAX_CONST_I; ++i)
862 object->changed.vertexShaderConstantsI[i] = TRUE;
864 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
865 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
867 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
869 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
872 for (j = 0 ; j < 16; j++){
873 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
874 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
878 /* Duplicate light chain */
880 PLIGHTINFOEL *src = NULL;
881 PLIGHTINFOEL *dst = NULL;
882 PLIGHTINFOEL *newEl = NULL;
883 src = This->stateBlock->lights;
884 object->lights = NULL;
888 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
889 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
890 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
892 newEl->changed = TRUE;
893 newEl->enabledChanged = TRUE;
895 object->lights = newEl;
906 FIXME("Unrecognized state block type %d\n", Type);
909 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
914 /* ************************************
916 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
919 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
921 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.
923 ******************************** */
925 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) {
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
928 unsigned int pow2Width, pow2Height;
929 unsigned int Size = 1;
930 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
931 TRACE("(%p) Create surface\n",This);
933 /** FIXME: Check ranges on the inputs are valid
936 * [in] Quality level. The valid range is between zero and one less than the level
937 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
938 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
939 * values of paired render targets, depth stencil surfaces, and the MultiSample type
941 *******************************/
946 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
948 * If this flag is set, the contents of the depth stencil buffer will be
949 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
950 * with a different depth surface.
952 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
953 ***************************/
955 if(MultisampleQuality < 0) {
956 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
957 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
960 if(MultisampleQuality > 0) {
961 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
962 MultisampleQuality=0;
965 /** FIXME: Check that the format is supported
967 *******************************/
969 /* Non-power2 support */
971 /* Find the nearest pow2 match */
972 pow2Width = pow2Height = 1;
973 while (pow2Width < Width) pow2Width <<= 1;
974 while (pow2Height < Height) pow2Height <<= 1;
976 if (pow2Width > Width || pow2Height > Height) {
977 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
978 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
979 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
980 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
981 This, Width, Height);
982 return WINED3DERR_NOTAVAILABLE;
986 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
987 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
989 *********************************/
990 if (WINED3DFMT_UNKNOWN == Format) {
992 } else if (Format == WINED3DFMT_DXT1) {
993 /* DXT1 is half byte per pixel */
994 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
996 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
997 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
998 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1000 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1003 /** Create and initialise the surface resource **/
1004 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1005 /* "Standalone" surface */
1006 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1008 object->currentDesc.Width = Width;
1009 object->currentDesc.Height = Height;
1010 object->currentDesc.MultiSampleType = MultiSample;
1011 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1013 /* Setup some glformat defaults */
1014 object->glDescription.glFormat = tableEntry->glFormat;
1015 object->glDescription.glFormatInternal = tableEntry->glInternal;
1016 object->glDescription.glType = tableEntry->glType;
1018 object->glDescription.textureName = 0;
1019 object->glDescription.level = Level;
1020 object->glDescription.target = GL_TEXTURE_2D;
1023 object->pow2Width = pow2Width;
1024 object->pow2Height = pow2Height;
1027 object->Flags = 0; /* We start without flags set */
1028 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1029 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1030 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1031 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1034 if (WINED3DFMT_UNKNOWN != Format) {
1035 object->bytesPerPixel = tableEntry->bpp;
1036 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1038 object->bytesPerPixel = 0;
1039 object->pow2Size = 0;
1042 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1044 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1046 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1047 * this function is too deap to need to care about things like this.
1048 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1049 * ****************************************/
1051 case WINED3DPOOL_SCRATCH:
1052 if(Lockable == FALSE)
1053 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1054 which are mutually exclusive, setting lockable to true\n");
1057 case WINED3DPOOL_SYSTEMMEM:
1058 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1059 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1060 case WINED3DPOOL_MANAGED:
1061 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1062 Usage of DYNAMIC which are mutually exclusive, not doing \
1063 anything just telling you.\n");
1065 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1066 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1067 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1068 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1071 FIXME("(%p) Unknown pool %d\n", This, Pool);
1075 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1076 FIXME("Trying to create a render target that isn't in the default pool\n");
1079 /* mark the texture as dirty so that it get's loaded first time around*/
1080 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1081 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1082 This, Width, Height, Format, debug_d3dformat(Format),
1083 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1085 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1086 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1087 This->ddraw_primary = (IWineD3DSurface *) object;
1089 /* Look at the implementation and set the correct Vtable */
1091 case SURFACE_OPENGL:
1092 /* Nothing to do, it's set already */
1096 object->lpVtbl = &IWineGDISurface_Vtbl;
1100 /* To be sure to catch this */
1101 ERR("Unknown requested surface implementation %d!\n", Impl);
1102 IWineD3DSurface_Release((IWineD3DSurface *) object);
1103 return WINED3DERR_INVALIDCALL;
1106 /* Call the private setup routine */
1107 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1111 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1112 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1113 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1114 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1117 IWineD3DTextureImpl *object;
1122 unsigned int pow2Width = Width;
1123 unsigned int pow2Height = Height;
1126 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1128 /* TODO: It should only be possible to create textures for formats
1129 that are reported as supported */
1130 if (WINED3DFMT_UNKNOWN >= Format) {
1131 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1132 return WINED3DERR_INVALIDCALL;
1135 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1136 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 object->width = Width;
1138 object->height = Height;
1140 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1142 pow2Width = pow2Height = 1;
1143 while (pow2Width < Width) pow2Width <<= 1;
1144 while (pow2Height < Height) pow2Height <<= 1;
1146 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1149 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1150 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1152 /* Calculate levels for mip mapping */
1154 TRACE("calculating levels %d\n", object->baseTexture.levels);
1155 object->baseTexture.levels++;
1158 while (tmpW > 1 || tmpH > 1) {
1159 tmpW = max(1, tmpW >> 1);
1160 tmpH = max(1, tmpH >> 1);
1161 object->baseTexture.levels++;
1163 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1166 /* Generate all the surfaces */
1169 for (i = 0; i < object->baseTexture.levels; i++)
1171 /* use the callback to create the texture surface */
1172 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1173 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1174 FIXME("Failed to create surface %p\n", object);
1176 object->surfaces[i] = NULL;
1177 IWineD3DTexture_Release((IWineD3DTexture *)object);
1183 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1184 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1185 /* calculate the next mipmap level */
1186 tmpW = max(1, tmpW >> 1);
1187 tmpH = max(1, tmpH >> 1);
1190 TRACE("(%p) : Created texture %p\n", This, object);
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1195 UINT Width, UINT Height, UINT Depth,
1196 UINT Levels, DWORD Usage,
1197 WINED3DFORMAT Format, WINED3DPOOL Pool,
1198 IWineD3DVolumeTexture **ppVolumeTexture,
1199 HANDLE *pSharedHandle, IUnknown *parent,
1200 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1203 IWineD3DVolumeTextureImpl *object;
1209 /* TODO: It should only be possible to create textures for formats
1210 that are reported as supported */
1211 if (WINED3DFMT_UNKNOWN >= Format) {
1212 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1213 return WINED3DERR_INVALIDCALL;
1216 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1217 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1219 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1220 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1222 object->width = Width;
1223 object->height = Height;
1224 object->depth = Depth;
1226 /* Calculate levels for mip mapping */
1228 object->baseTexture.levels++;
1232 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1233 tmpW = max(1, tmpW >> 1);
1234 tmpH = max(1, tmpH >> 1);
1235 tmpD = max(1, tmpD >> 1);
1236 object->baseTexture.levels++;
1238 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1241 /* Generate all the surfaces */
1246 for (i = 0; i < object->baseTexture.levels; i++)
1248 /* Create the volume */
1249 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1250 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1252 /* Set it's container to this object */
1253 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1255 /* calcualte the next mipmap level */
1256 tmpW = max(1, tmpW >> 1);
1257 tmpH = max(1, tmpH >> 1);
1258 tmpD = max(1, tmpD >> 1);
1261 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1262 TRACE("(%p) : Created volume texture %p\n", This, object);
1266 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1267 UINT Width, UINT Height, UINT Depth,
1269 WINED3DFORMAT Format, WINED3DPOOL Pool,
1270 IWineD3DVolume** ppVolume,
1271 HANDLE* pSharedHandle, IUnknown *parent) {
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1277 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1279 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1280 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1282 object->currentDesc.Width = Width;
1283 object->currentDesc.Height = Height;
1284 object->currentDesc.Depth = Depth;
1285 object->bytesPerPixel = formatDesc->bpp;
1287 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1288 object->lockable = TRUE;
1289 object->locked = FALSE;
1290 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1291 object->dirty = TRUE;
1293 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1297 UINT Levels, DWORD Usage,
1298 WINED3DFORMAT Format, WINED3DPOOL Pool,
1299 IWineD3DCubeTexture **ppCubeTexture,
1300 HANDLE *pSharedHandle, IUnknown *parent,
1301 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1308 unsigned int pow2EdgeLength = EdgeLength;
1310 /* TODO: It should only be possible to create textures for formats
1311 that are reported as supported */
1312 if (WINED3DFMT_UNKNOWN >= Format) {
1313 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1314 return WINED3DERR_INVALIDCALL;
1317 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1318 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1320 TRACE("(%p) Create Cube Texture\n", This);
1322 /** Non-power2 support **/
1324 /* Find the nearest pow2 match */
1326 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1328 object->edgeLength = EdgeLength;
1329 /* TODO: support for native non-power 2 */
1330 /* Precalculated scaling for 'faked' non power of two texture coords */
1331 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1333 /* Calculate levels for mip mapping */
1335 object->baseTexture.levels++;
1338 tmpW = max(1, tmpW >> 1);
1339 object->baseTexture.levels++;
1341 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1344 /* Generate all the surfaces */
1346 for (i = 0; i < object->baseTexture.levels; i++) {
1348 /* Create the 6 faces */
1349 for (j = 0; j < 6; j++) {
1351 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1352 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1354 if(hr!= WINED3D_OK) {
1358 for (l = 0; l < j; l++) {
1359 IWineD3DSurface_Release(object->surfaces[j][i]);
1361 for (k = 0; k < i; k++) {
1362 for (l = 0; l < 6; l++) {
1363 IWineD3DSurface_Release(object->surfaces[l][j]);
1367 FIXME("(%p) Failed to create surface\n",object);
1368 HeapFree(GetProcessHeap(),0,object);
1369 *ppCubeTexture = NULL;
1372 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1373 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1375 tmpW = max(1, tmpW >> 1);
1378 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1379 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1385 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1387 if (NULL == ppQuery) {
1388 /* Just a check to see if we support this type of query */
1389 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1391 case WINED3DQUERYTYPE_OCCLUSION:
1392 TRACE("(%p) occlusion query\n", This);
1393 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1396 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1398 case WINED3DQUERYTYPE_VCACHE:
1399 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1400 case WINED3DQUERYTYPE_VERTEXSTATS:
1401 case WINED3DQUERYTYPE_EVENT:
1402 case WINED3DQUERYTYPE_TIMESTAMP:
1403 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1404 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1405 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1406 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1407 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1408 case WINED3DQUERYTYPE_PIXELTIMINGS:
1409 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1410 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1412 FIXME("(%p) Unhandled query type %d\n", This, Type);
1417 D3DCREATEOBJECTINSTANCE(object, Query)
1418 object->type = Type;
1419 /* allocated the 'extended' data based on the type of query requested */
1421 case D3DQUERYTYPE_OCCLUSION:
1422 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1423 TRACE("(%p) Allocating data for an occlusion query\n", This);
1424 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1427 case D3DQUERYTYPE_VCACHE:
1428 case D3DQUERYTYPE_RESOURCEMANAGER:
1429 case D3DQUERYTYPE_VERTEXSTATS:
1430 case D3DQUERYTYPE_EVENT:
1431 case D3DQUERYTYPE_TIMESTAMP:
1432 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1433 case D3DQUERYTYPE_TIMESTAMPFREQ:
1434 case D3DQUERYTYPE_PIPELINETIMINGS:
1435 case D3DQUERYTYPE_INTERFACETIMINGS:
1436 case D3DQUERYTYPE_VERTEXTIMINGS:
1437 case D3DQUERYTYPE_PIXELTIMINGS:
1438 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1439 case D3DQUERYTYPE_CACHEUTILIZATION:
1441 object->extendedData = 0;
1442 FIXME("(%p) Unhandled query type %d\n",This , Type);
1444 TRACE("(%p) : Created Query %p\n", This, object);
1448 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1449 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1451 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1452 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1456 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1458 XVisualInfo template;
1459 GLXContext oldContext;
1460 Drawable oldDrawable;
1461 HRESULT hr = WINED3D_OK;
1463 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1465 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1466 * does a device hold a reference to a swap chain giving them a lifetime of the device
1467 * or does the swap chain notify the device of its destruction.
1468 *******************************/
1470 /* Check the params */
1471 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1472 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1473 return WINED3DERR_INVALIDCALL;
1474 } else if (*pPresentationParameters->BackBufferCount > 1) {
1475 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");
1478 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1480 /*********************
1481 * Lookup the window Handle and the relating X window handle
1482 ********************/
1484 /* Setup hwnd we are using, plus which display this equates to */
1485 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1486 if (!object->win_handle) {
1487 object->win_handle = This->createParms.hFocusWindow;
1490 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1491 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1492 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1493 return WINED3DERR_NOTAVAILABLE;
1495 hDc = GetDC(object->win_handle);
1496 object->display = get_display(hDc);
1497 ReleaseDC(object->win_handle, hDc);
1498 TRACE("Using a display of %p %p\n", object->display, hDc);
1500 if (NULL == object->display || NULL == hDc) {
1501 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1502 return WINED3DERR_NOTAVAILABLE;
1505 if (object->win == 0) {
1506 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1507 return WINED3DERR_NOTAVAILABLE;
1510 * Create an opengl context for the display visual
1511 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1512 * use different properties after that point in time. FIXME: How to handle when requested format
1513 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1514 * it chooses is identical to the one already being used!
1515 **********************************/
1517 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1520 /* Create a new context for this swapchain */
1521 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1522 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1523 (or the best possible if none is requested) */
1524 TRACE("Found x visual ID : %ld\n", template.visualid);
1526 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1527 if (NULL == object->visInfo) {
1528 ERR("cannot really get XVisual\n");
1530 return WINED3DERR_NOTAVAILABLE;
1533 /* Write out some debug info about the visual/s */
1534 TRACE("Using x visual ID : %ld\n", template.visualid);
1535 TRACE(" visual info: %p\n", object->visInfo);
1536 TRACE(" num items : %d\n", num);
1537 for (n = 0;n < num; n++) {
1538 TRACE("=====item=====: %d\n", n + 1);
1539 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1540 TRACE(" screen : %d\n", object->visInfo[n].screen);
1541 TRACE(" depth : %u\n", object->visInfo[n].depth);
1542 TRACE(" class : %d\n", object->visInfo[n].class);
1543 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1544 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1545 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1546 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1547 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1548 /* log some extra glx info */
1549 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1550 TRACE(" gl_aux_buffers : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1552 TRACE(" gl_buffer_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1554 TRACE(" gl_red_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1556 TRACE(" gl_green_size : %d\n", value);
1557 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1558 TRACE(" gl_blue_size : %d\n", value);
1559 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1560 TRACE(" gl_alpha_size : %d\n", value);
1561 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1562 TRACE(" gl_depth_size : %d\n", value);
1563 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1564 TRACE(" gl_stencil_size : %d\n", value);
1566 /* Now choose a simila visual ID*/
1568 #ifdef USE_CONTEXT_MANAGER
1570 /** TODO: use a context mamager **/
1574 IWineD3DSwapChain *implSwapChain;
1575 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1576 /* The first time around we create the context that is shared with all other swapchains and render targets */
1577 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1578 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1581 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1582 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1583 /* and create a new context with the implicit swapchains context as the shared context */
1584 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1585 IWineD3DSwapChain_Release(implSwapChain);
1590 XFree(object->visInfo);
1591 object->visInfo = NULL;
1595 if (!object->glCtx) {
1596 ERR("Failed to create GLX context\n");
1597 return WINED3DERR_NOTAVAILABLE;
1599 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1600 object->win_handle, object->glCtx, object->win, object->visInfo);
1603 /*********************
1604 * Windowed / Fullscreen
1605 *******************/
1608 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1609 * so we should really check to see if there is a fullscreen swapchain already
1610 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1611 **************************************/
1613 if (!*(pPresentationParameters->Windowed)) {
1619 /* Get info on the current display setup */
1620 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1621 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1624 /* Change the display settings */
1625 memset(&devmode, 0, sizeof(DEVMODEW));
1626 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1627 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1628 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1629 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1630 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1631 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1633 /* Make popup window */
1634 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1635 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1636 *(pPresentationParameters->BackBufferWidth),
1637 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1639 /* For GetDisplayMode */
1640 This->ddraw_width = devmode.dmPelsWidth;
1641 This->ddraw_height = devmode.dmPelsHeight;
1642 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1646 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1647 * then the corresponding dimension of the client area of the hDeviceWindow
1648 * (or the focus window, if hDeviceWindow is NULL) is taken.
1649 **********************/
1651 if (*(pPresentationParameters->Windowed) &&
1652 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1653 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1656 GetClientRect(object->win_handle, &Rect);
1658 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1659 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1660 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1662 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1663 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1664 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1668 /*********************
1669 * finish off parameter initialization
1670 *******************/
1672 /* Put the correct figures in the presentation parameters */
1673 TRACE("Coppying accross presentaion paraneters\n");
1674 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1675 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1676 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1677 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1678 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1679 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1680 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1681 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1682 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1683 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1684 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1685 object->presentParms.Flags = *(pPresentationParameters->Flags);
1686 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1687 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1690 /*********************
1691 * Create the back, front and stencil buffers
1692 *******************/
1694 TRACE("calling rendertarget CB\n");
1695 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1696 object->presentParms.BackBufferWidth,
1697 object->presentParms.BackBufferHeight,
1698 object->presentParms.BackBufferFormat,
1699 object->presentParms.MultiSampleType,
1700 object->presentParms.MultiSampleQuality,
1701 TRUE /* Lockable */,
1702 &object->frontBuffer,
1703 NULL /* pShared (always null)*/);
1704 if (object->frontBuffer != NULL)
1705 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1707 if(object->presentParms.BackBufferCount > 0) {
1710 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1711 if(!object->backBuffer) {
1712 ERR("Out of memory\n");
1714 if (object->frontBuffer) {
1715 IUnknown *bufferParent;
1716 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1717 IUnknown_Release(bufferParent); /* once for the get parent */
1718 if (IUnknown_Release(bufferParent) > 0) {
1719 FIXME("(%p) Something's still holding the front buffer\n",This);
1722 HeapFree(GetProcessHeap(), 0, object);
1723 return E_OUTOFMEMORY;
1726 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1727 TRACE("calling rendertarget CB\n");
1728 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1729 object->presentParms.BackBufferWidth,
1730 object->presentParms.BackBufferHeight,
1731 object->presentParms.BackBufferFormat,
1732 object->presentParms.MultiSampleType,
1733 object->presentParms.MultiSampleQuality,
1734 TRUE /* Lockable */,
1735 &object->backBuffer[i],
1736 NULL /* pShared (always null)*/);
1737 if(hr == WINED3D_OK && object->backBuffer[i]) {
1738 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1744 object->backBuffer = NULL;
1747 if (object->backBuffer != NULL) {
1749 glDrawBuffer(GL_BACK);
1750 checkGLcall("glDrawBuffer(GL_BACK)");
1753 /* Single buffering - draw to front buffer */
1755 glDrawBuffer(GL_FRONT);
1756 checkGLcall("glDrawBuffer(GL_FRONT)");
1760 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1761 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1762 TRACE("Creating depth stencil buffer\n");
1763 if (This->depthStencilBuffer == NULL ) {
1764 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1765 object->presentParms.BackBufferWidth,
1766 object->presentParms.BackBufferHeight,
1767 object->presentParms.AutoDepthStencilFormat,
1768 object->presentParms.MultiSampleType,
1769 object->presentParms.MultiSampleQuality,
1770 FALSE /* FIXME: Discard */,
1771 &This->depthStencilBuffer,
1772 NULL /* pShared (always null)*/ );
1773 if (This->depthStencilBuffer != NULL)
1774 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1777 /** TODO: A check on width, height and multisample types
1778 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1779 ****************************/
1780 object->wantsDepthStencilBuffer = TRUE;
1782 object->wantsDepthStencilBuffer = FALSE;
1785 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1788 /*********************
1789 * init the default renderTarget management
1790 *******************/
1791 object->drawable = object->win;
1792 object->render_ctx = object->glCtx;
1794 if (hr == WINED3D_OK) {
1795 /*********************
1796 * Setup some defaults and clear down the buffers
1797 *******************/
1799 /** save current context and drawable **/
1800 oldContext = glXGetCurrentContext();
1801 oldDrawable = glXGetCurrentDrawable();
1803 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1804 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1805 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1807 checkGLcall("glXMakeCurrent");
1809 TRACE("Setting up the screen\n");
1810 /* Clear the screen */
1811 glClearColor(1.0, 0.0, 0.0, 0.0);
1812 checkGLcall("glClearColor");
1815 glClearStencil(0xffff);
1817 checkGLcall("glClear");
1819 glColor3f(1.0, 1.0, 1.0);
1820 checkGLcall("glColor3f");
1822 glEnable(GL_LIGHTING);
1823 checkGLcall("glEnable");
1825 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1826 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1828 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1829 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1831 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1832 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1834 /* switch back to the original context (if there was one)*/
1835 if (This->swapchains) {
1836 /** TODO: restore the context and drawable **/
1837 glXMakeCurrent(object->display, oldDrawable, oldContext);
1842 TRACE("Set swapchain to %p\n", object);
1843 } else { /* something went wrong so clean up */
1844 IUnknown* bufferParent;
1845 if (object->frontBuffer) {
1847 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1848 IUnknown_Release(bufferParent); /* once for the get parent */
1849 if (IUnknown_Release(bufferParent) > 0) {
1850 FIXME("(%p) Something's still holding the front buffer\n",This);
1853 if (object->backBuffer) {
1855 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1856 if(object->backBuffer[i]) {
1857 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1858 IUnknown_Release(bufferParent); /* once for the get parent */
1859 if (IUnknown_Release(bufferParent) > 0) {
1860 FIXME("(%p) Something's still holding the back buffer\n",This);
1864 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1865 object->backBuffer = NULL;
1867 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1868 /* Clean up the context */
1869 /* check that we are the current context first (we shouldn't be though!) */
1870 if (object->glCtx != 0) {
1871 if(glXGetCurrentContext() == object->glCtx) {
1872 glXMakeCurrent(object->display, None, NULL);
1874 glXDestroyContext(object->display, object->glCtx);
1876 HeapFree(GetProcessHeap(), 0, object);
1883 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1884 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 TRACE("(%p)\n", This);
1888 return This->NumberOfSwapChains;
1891 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1895 if(iSwapChain < This->NumberOfSwapChains) {
1896 *pSwapChain = This->swapchains[iSwapChain];
1897 IWineD3DSwapChain_AddRef(*pSwapChain);
1898 TRACE("(%p) returning %p\n", This, *pSwapChain);
1901 TRACE("Swapchain out of range\n");
1903 return WINED3DERR_INVALIDCALL;
1908 * Vertex Declaration
1910 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 IWineD3DVertexDeclarationImpl *object = NULL;
1913 HRESULT hr = WINED3D_OK;
1914 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1915 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1918 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1923 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1927 HRESULT hr = WINED3D_OK;
1928 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1929 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1931 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1933 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1934 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1935 if (pDeclaration != NULL) {
1936 IWineD3DVertexDeclaration *vertexDeclaration;
1937 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1938 if (WINED3D_OK == hr) {
1939 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1940 object->vertexDeclaration = vertexDeclaration;
1942 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1943 IWineD3DVertexShader_Release(*ppVertexShader);
1944 return WINED3DERR_INVALIDCALL;
1948 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1950 if (WINED3D_OK != hr) {
1951 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1952 IWineD3DVertexShader_Release(*ppVertexShader);
1953 return WINED3DERR_INVALIDCALL;
1956 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1957 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1968 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1970 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1971 HRESULT hr = WINED3D_OK;
1973 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1974 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1975 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1976 if (WINED3D_OK == hr) {
1977 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1979 WARN("(%p) : Failed to create pixel shader\n", This);
1985 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 IWineD3DPaletteImpl *object;
1989 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1991 /* Create the new object */
1992 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1994 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1995 return E_OUTOFMEMORY;
1998 object->lpVtbl = &IWineD3DPalette_Vtbl;
2000 object->Flags = Flags;
2001 object->parent = Parent;
2002 object->wineD3DDevice = This;
2003 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2005 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2008 HeapFree( GetProcessHeap(), 0, object);
2009 return E_OUTOFMEMORY;
2012 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2014 IWineD3DPalette_Release((IWineD3DPalette *) object);
2018 *Palette = (IWineD3DPalette *) object;
2023 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2025 IWineD3DSwapChainImpl *swapchain;
2027 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2028 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2030 /* TODO: Test if OpenGL is compiled in and loaded */
2032 /* Setup the implicit swapchain */
2033 TRACE("Creating implicit swapchain\n");
2034 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2035 WARN("Failed to create implicit swapchain\n");
2036 return WINED3DERR_INVALIDCALL;
2039 This->NumberOfSwapChains = 1;
2040 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2041 if(!This->swapchains) {
2042 ERR("Out of memory!\n");
2043 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2044 return E_OUTOFMEMORY;
2046 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2048 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2049 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2050 This->renderTarget = swapchain->backBuffer[0];
2053 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2054 This->renderTarget = swapchain->frontBuffer;
2056 IWineD3DSurface_AddRef(This->renderTarget);
2057 /* Depth Stencil support */
2058 This->stencilBufferTarget = This->depthStencilBuffer;
2059 if (NULL != This->stencilBufferTarget) {
2060 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2063 /* Set up some starting GL setup */
2066 * Initialize openGL extension related variables
2067 * with Default values
2070 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2071 /* Setup all the devices defaults */
2072 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2074 IWineD3DImpl_CheckGraphicsMemory();
2078 /* Initialize our list of GLSL programs */
2079 list_init(&This->glsl_shader_progs);
2081 { /* Set a default viewport */
2085 vp.Width = *(pPresentationParameters->BackBufferWidth);
2086 vp.Height = *(pPresentationParameters->BackBufferHeight);
2089 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2092 /* Initialize the current view state */
2093 This->modelview_valid = 1;
2094 This->proj_valid = 0;
2095 This->view_ident = 1;
2096 This->last_was_rhw = 0;
2097 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2098 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2100 /* Clear the screen */
2101 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2103 This->d3d_initialized = TRUE;
2107 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2110 IUnknown* stencilBufferParent;
2111 IUnknown* swapChainParent;
2113 TRACE("(%p)\n", This);
2115 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2117 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2118 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2121 /* Release the buffers (with sanity checks)*/
2122 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2123 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2124 if(This->depthStencilBuffer != This->stencilBufferTarget)
2125 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2127 This->stencilBufferTarget = NULL;
2129 TRACE("Releasing the render target at %p\n", This->renderTarget);
2130 if(IWineD3DSurface_Release(This->renderTarget) >0){
2131 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2133 TRACE("Setting rendertarget to NULL\n");
2134 This->renderTarget = NULL;
2136 if (This->depthStencilBuffer) {
2137 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2138 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2139 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2140 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2142 This->depthStencilBuffer = NULL;
2145 for(i=0; i < This->NumberOfSwapChains; i++) {
2146 TRACE("Releasing the implicit swapchain %d\n", i);
2147 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2148 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2149 IUnknown_Release(swapChainParent); /* once for the get parent */
2150 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2151 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2155 HeapFree(GetProcessHeap(), 0, This->swapchains);
2156 This->swapchains = NULL;
2157 This->NumberOfSwapChains = 0;
2159 This->d3d_initialized = FALSE;
2163 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2168 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2170 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2172 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2173 /* Ignore some modes if a description was passed */
2174 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2175 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2176 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2178 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2180 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2187 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2191 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2193 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2195 /* Resize the screen even without a window:
2196 * The app could have unset it with SetCooperativeLevel, but not called
2197 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2198 * but we don't have any hwnd
2201 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2202 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2203 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2204 devmode.dmPelsWidth = pMode->Width;
2205 devmode.dmPelsHeight = pMode->Height;
2207 devmode.dmDisplayFrequency = pMode->RefreshRate;
2208 if (pMode->RefreshRate != 0) {
2209 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2212 /* Only change the mode if necessary */
2213 if( (This->ddraw_width == pMode->Width) &&
2214 (This->ddraw_height == pMode->Height) &&
2215 (This->ddraw_format == pMode->Format) &&
2216 (pMode->RefreshRate == 0) ) {
2220 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2221 if (ret != DISP_CHANGE_SUCCESSFUL) {
2222 if(devmode.dmDisplayFrequency != 0) {
2223 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2224 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2225 devmode.dmDisplayFrequency = 0;
2226 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2228 if(ret != DISP_CHANGE_SUCCESSFUL) {
2229 return DDERR_INVALIDMODE;
2233 /* Store the new values */
2234 This->ddraw_width = pMode->Width;
2235 This->ddraw_height = pMode->Height;
2236 This->ddraw_format = pMode->Format;
2238 /* Only do this with a window of course */
2239 if(This->ddraw_window)
2240 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2245 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2247 *ppD3D= This->wineD3D;
2248 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2249 IWineD3D_AddRef(*ppD3D);
2253 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2254 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2255 * Into the video ram as possible and seeing how many fit
2256 * you can also get the correct initial value from via X and ATI's driver
2257 *******************/
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2259 static BOOL showfixmes = TRUE;
2261 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2262 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2265 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2266 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2267 /* videomemory is simulated videomemory + AGP memory left */
2268 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2276 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2278 HRESULT hr = WINED3D_OK;
2280 /* Update the current state block */
2281 This->updateStateBlock->fvf = fvf;
2282 This->updateStateBlock->changed.fvf = TRUE;
2283 This->updateStateBlock->set.fvf = TRUE;
2285 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2290 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2292 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2293 *pfvf = This->stateBlock->fvf;
2298 * Get / Set Stream Source
2300 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 IWineD3DVertexBuffer *oldSrc;
2304 /**TODO: instance and index data, see
2305 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2307 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2310 /* D3d9 only, but shouldn't hurt d3d8 */
2313 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2315 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2316 FIXME("stream index data not supported\n");
2318 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2319 FIXME("stream instance data not supported\n");
2323 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2325 if (StreamNumber >= MAX_STREAMS) {
2326 WARN("Stream out of range %d\n", StreamNumber);
2327 return WINED3DERR_INVALIDCALL;
2330 oldSrc = This->stateBlock->streamSource[StreamNumber];
2331 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2333 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2334 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2335 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2336 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2337 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2338 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2340 /* Handle recording of state blocks */
2341 if (This->isRecordingState) {
2342 TRACE("Recording... not performing anything\n");
2346 /* Same stream object: no action */
2347 if (oldSrc == pStreamData)
2350 /* Need to do a getParent and pass the reffs up */
2351 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2352 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2353 so for now, just count internally */
2354 if (pStreamData != NULL) {
2355 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2356 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2357 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2359 vbImpl->stream = StreamNumber;
2360 vbImpl->Flags |= VBFLAG_STREAM;
2361 IWineD3DVertexBuffer_AddRef(pStreamData);
2363 if (oldSrc != NULL) {
2364 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2365 IWineD3DVertexBuffer_Release(oldSrc);
2371 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2376 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2379 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2381 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2382 FIXME("stream index data not supported\n");
2384 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2385 FIXME("stream instance data not supported\n");
2389 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2391 if (StreamNumber >= MAX_STREAMS) {
2392 WARN("Stream out of range %d\n", StreamNumber);
2393 return WINED3DERR_INVALIDCALL;
2395 *pStream = This->stateBlock->streamSource[StreamNumber];
2396 *pStride = This->stateBlock->streamStride[StreamNumber];
2397 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2399 if (*pStream == NULL) {
2400 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2401 return WINED3DERR_INVALIDCALL;
2404 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2408 /*Should be quite easy, just an extension of vertexdata
2410 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2412 The divider is a bit odd though
2414 VertexOffset = StartVertex / Divider * StreamStride +
2415 VertexIndex / Divider * StreamStride + StreamOffset
2418 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2422 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2424 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2425 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2426 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2428 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2429 FIXME("Stream indexing not fully supported\n");
2435 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2439 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2441 TRACE("(%p) : returning %d\n", This, *Divider);
2447 * Get / Set & Multiply Transform
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2452 /* Most of this routine, comments included copied from ddraw tree initially: */
2453 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2455 /* Handle recording of state blocks */
2456 if (This->isRecordingState) {
2457 TRACE("Recording... not performing anything\n");
2458 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2459 This->updateStateBlock->set.transform[d3dts] = TRUE;
2460 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2465 * If the new matrix is the same as the current one,
2466 * we cut off any further processing. this seems to be a reasonable
2467 * optimization because as was noticed, some apps (warcraft3 for example)
2468 * tend towards setting the same matrix repeatedly for some reason.
2470 * From here on we assume that the new matrix is different, wherever it matters.
2472 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2473 TRACE("The app is setting the same matrix over again\n");
2476 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2480 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2481 where ViewMat = Camera space, WorldMat = world space.
2483 In OpenGL, camera and world space is combined into GL_MODELVIEW
2484 matrix. The Projection matrix stay projection matrix.
2487 /* Capture the times we can just ignore the change for now */
2488 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2489 This->modelview_valid = FALSE;
2492 } else if (d3dts == D3DTS_PROJECTION) {
2493 This->proj_valid = FALSE;
2496 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2497 /* Indexed Vertex Blending Matrices 256 -> 511 */
2498 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2499 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2503 /* Now we really are going to have to change a matrix */
2506 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2507 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2508 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2511 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2512 * NOTE: We have to reset the positions even if the light/plane is not currently
2513 * enabled, since the call to enable it will not reset the position.
2514 * NOTE2: Apparently texture transforms do NOT need reapplying
2517 PLIGHTINFOEL *lightChain = NULL;
2518 This->modelview_valid = FALSE;
2519 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2521 glMatrixMode(GL_MODELVIEW);
2522 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2524 glLoadMatrixf((float *)lpmatrix);
2525 checkGLcall("glLoadMatrixf(...)");
2528 lightChain = This->stateBlock->lights;
2529 while (lightChain && lightChain->glIndex != -1) {
2530 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2531 checkGLcall("glLightfv posn");
2532 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2533 checkGLcall("glLightfv dirn");
2534 lightChain = lightChain->next;
2537 /* Reset Clipping Planes if clipping is enabled */
2538 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2539 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2540 checkGLcall("glClipPlane");
2544 } else { /* What was requested!?? */
2545 WARN("invalid matrix specified: %i\n", d3dts);
2548 /* Release lock, all done */
2553 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2555 TRACE("(%p) : for Transform State %d\n", This, State);
2556 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2560 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2561 D3DMATRIX *mat = NULL;
2564 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2565 * below means it will be recorded in a state block change, but it
2566 * works regardless where it is recorded.
2567 * If this is found to be wrong, change to StateBlock.
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 TRACE("(%p) : For state %u\n", This, State);
2572 if (State < HIGHEST_TRANSFORMSTATE)
2574 mat = &This->updateStateBlock->transforms[State];
2576 FIXME("Unhandled transform state!!\n");
2579 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2581 /* Apply change via set transform - will reapply to eg. lights this way */
2582 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2587 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2589 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2590 you can reference any indexes you want as long as that number max are enabled at any
2591 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2592 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2593 but when recording, just build a chain pretty much of commands to be replayed. */
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2597 PLIGHTINFOEL *object, *temp;
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2602 /* If recording state block, just add to end of lights chain */
2603 if (This->isRecordingState) {
2604 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2605 if (NULL == object) {
2606 return WINED3DERR_OUTOFVIDEOMEMORY;
2608 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2609 object->OriginalIndex = Index;
2610 object->glIndex = -1;
2611 object->changed = TRUE;
2613 /* Add to the END of the chain of lights changes to be replayed */
2614 if (This->updateStateBlock->lights == NULL) {
2615 This->updateStateBlock->lights = object;
2617 temp = This->updateStateBlock->lights;
2618 while (temp->next != NULL) temp=temp->next;
2619 temp->next = object;
2621 TRACE("Recording... not performing anything more\n");
2625 /* Ok, not recording any longer so do real work */
2626 object = This->stateBlock->lights;
2627 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2629 /* If we didn't find it in the list of lights, time to add it */
2630 if (object == NULL) {
2631 PLIGHTINFOEL *insertAt,*prevPos;
2633 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2634 if (NULL == object) {
2635 return WINED3DERR_OUTOFVIDEOMEMORY;
2637 object->OriginalIndex = Index;
2638 object->glIndex = -1;
2640 /* Add it to the front of list with the idea that lights will be changed as needed
2641 BUT after any lights currently assigned GL indexes */
2642 insertAt = This->stateBlock->lights;
2644 while (insertAt != NULL && insertAt->glIndex != -1) {
2646 insertAt = insertAt->next;
2649 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2650 This->stateBlock->lights = object;
2651 } else if (insertAt == NULL) { /* End of list */
2652 prevPos->next = object;
2653 object->prev = prevPos;
2654 } else { /* Middle of chain */
2655 if (prevPos == NULL) {
2656 This->stateBlock->lights = object;
2658 prevPos->next = object;
2660 object->prev = prevPos;
2661 object->next = insertAt;
2662 insertAt->prev = object;
2666 /* Initialize the object */
2667 TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2668 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2669 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2670 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2671 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2672 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2673 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2675 /* Save away the information */
2676 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2678 switch (pLight->Type) {
2679 case D3DLIGHT_POINT:
2681 object->lightPosn[0] = pLight->Position.x;
2682 object->lightPosn[1] = pLight->Position.y;
2683 object->lightPosn[2] = pLight->Position.z;
2684 object->lightPosn[3] = 1.0f;
2685 object->cutoff = 180.0f;
2689 case D3DLIGHT_DIRECTIONAL:
2691 object->lightPosn[0] = -pLight->Direction.x;
2692 object->lightPosn[1] = -pLight->Direction.y;
2693 object->lightPosn[2] = -pLight->Direction.z;
2694 object->lightPosn[3] = 0.0;
2695 object->exponent = 0.0f;
2696 object->cutoff = 180.0f;
2701 object->lightPosn[0] = pLight->Position.x;
2702 object->lightPosn[1] = pLight->Position.y;
2703 object->lightPosn[2] = pLight->Position.z;
2704 object->lightPosn[3] = 1.0;
2707 object->lightDirn[0] = pLight->Direction.x;
2708 object->lightDirn[1] = pLight->Direction.y;
2709 object->lightDirn[2] = pLight->Direction.z;
2710 object->lightDirn[3] = 1.0;
2713 * opengl-ish and d3d-ish spot lights use too different models for the
2714 * light "intensity" as a function of the angle towards the main light direction,
2715 * so we only can approximate very roughly.
2716 * however spot lights are rather rarely used in games (if ever used at all).
2717 * furthermore if still used, probably nobody pays attention to such details.
2719 if (pLight->Falloff == 0) {
2722 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2724 if (rho < 0.0001) rho = 0.0001f;
2725 object->exponent = -0.3/log(cos(rho/2));
2726 object->cutoff = pLight->Phi*90/M_PI;
2732 FIXME("Unrecognized light type %d\n", pLight->Type);
2735 /* Update the live definitions if the light is currently assigned a glIndex */
2736 if (object->glIndex != -1) {
2737 setup_light(iface, object->glIndex, object);
2742 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2743 PLIGHTINFOEL *lightInfo = NULL;
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2745 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2747 /* Locate the light in the live lights */
2748 lightInfo = This->stateBlock->lights;
2749 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2751 if (lightInfo == NULL) {
2752 TRACE("Light information requested but light not defined\n");
2753 return WINED3DERR_INVALIDCALL;
2756 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2761 * Get / Set Light Enable
2762 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2764 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2765 PLIGHTINFOEL *lightInfo = NULL;
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2769 /* Tests show true = 128...not clear why */
2771 Enable = Enable? 128: 0;
2773 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2774 if (This->isRecordingState) {
2775 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2776 if (NULL == lightInfo) {
2777 return WINED3DERR_OUTOFVIDEOMEMORY;
2779 lightInfo->OriginalIndex = Index;
2780 lightInfo->glIndex = -1;
2781 lightInfo->enabledChanged = TRUE;
2782 lightInfo->lightEnabled = Enable;
2784 /* Add to the END of the chain of lights changes to be replayed */
2785 if (This->updateStateBlock->lights == NULL) {
2786 This->updateStateBlock->lights = lightInfo;
2788 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2789 while (temp->next != NULL) temp=temp->next;
2790 temp->next = lightInfo;
2792 TRACE("Recording... not performing anything more\n");
2796 /* Not recording... So, locate the light in the live lights */
2797 lightInfo = This->stateBlock->lights;
2798 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2800 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2801 if (lightInfo == NULL) {
2803 TRACE("Light enabled requested but light not defined, so defining one!\n");
2804 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2806 /* Search for it again! Should be fairly quick as near head of list */
2807 lightInfo = This->stateBlock->lights;
2808 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2809 if (lightInfo == NULL) {
2810 FIXME("Adding default lights has failed dismally\n");
2811 return WINED3DERR_INVALIDCALL;
2815 /* OK, we now have a light... */
2816 if (Enable == FALSE) {
2818 /* If we are disabling it, check it was enabled, and
2819 still only do something if it has assigned a glIndex (which it should have!) */
2820 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2821 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2823 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2824 checkGLcall("glDisable GL_LIGHT0+Index");
2827 TRACE("Nothing to do as light was not enabled\n");
2829 lightInfo->lightEnabled = Enable;
2832 /* We are enabling it. If it is enabled, it's really simple */
2833 if (lightInfo->lightEnabled) {
2835 TRACE("Nothing to do as light was enabled\n");
2837 /* If it already has a glIndex, it's still simple */
2838 } else if (lightInfo->glIndex != -1) {
2839 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2840 lightInfo->lightEnabled = Enable;
2842 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2843 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2846 /* Otherwise got to find space - lights are ordered gl indexes first */
2848 PLIGHTINFOEL *bsf = NULL;
2849 PLIGHTINFOEL *pos = This->stateBlock->lights;
2850 PLIGHTINFOEL *prev = NULL;
2854 /* Try to minimize changes as much as possible */
2855 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2857 /* Try to remember which index can be replaced if necessary */
2858 if (bsf==NULL && pos->lightEnabled == FALSE) {
2859 /* Found a light we can replace, save as best replacement */
2863 /* Step to next space */
2869 /* If we have too many active lights, fail the call */
2870 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2871 FIXME("Program requests too many concurrent lights\n");
2872 return WINED3DERR_INVALIDCALL;
2874 /* If we have allocated all lights, but not all are enabled,
2875 reuse one which is not enabled */
2876 } else if (Index == This->maxConcurrentLights) {
2877 /* use bsf - Simply swap the new light and the BSF one */
2878 PLIGHTINFOEL *bsfNext = bsf->next;
2879 PLIGHTINFOEL *bsfPrev = bsf->prev;
2882 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2883 if (bsf->prev != NULL) {
2884 bsf->prev->next = lightInfo;
2886 This->stateBlock->lights = lightInfo;
2889 /* If not side by side, lots of chains to update */
2890 if (bsf->next != lightInfo) {
2891 lightInfo->prev->next = bsf;
2892 bsf->next->prev = lightInfo;
2893 bsf->next = lightInfo->next;
2894 bsf->prev = lightInfo->prev;
2895 lightInfo->next = bsfNext;
2896 lightInfo->prev = bsfPrev;
2900 bsf->prev = lightInfo;
2901 bsf->next = lightInfo->next;
2902 lightInfo->next = bsf;
2903 lightInfo->prev = bsfPrev;
2908 glIndex = bsf->glIndex;
2910 lightInfo->glIndex = glIndex;
2911 lightInfo->lightEnabled = Enable;
2913 /* Finally set up the light in gl itself */
2914 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2916 setup_light(iface, glIndex, lightInfo);
2917 glEnable(GL_LIGHT0 + glIndex);
2918 checkGLcall("glEnable GL_LIGHT0 new setup");
2921 /* If we reached the end of the allocated lights, with space in the
2922 gl lights, setup a new light */
2923 } else if (pos->glIndex == -1) {
2925 /* We reached the end of the allocated gl lights, so already
2926 know the index of the next one! */
2928 lightInfo->glIndex = glIndex;
2929 lightInfo->lightEnabled = Enable;
2931 /* In an ideal world, it's already in the right place */
2932 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2933 /* No need to move it */
2935 /* Remove this light from the list */
2936 lightInfo->prev->next = lightInfo->next;
2937 if (lightInfo->next != NULL) {
2938 lightInfo->next->prev = lightInfo->prev;
2941 /* Add in at appropriate place (inbetween prev and pos) */
2942 lightInfo->prev = prev;
2943 lightInfo->next = pos;
2945 This->stateBlock->lights = lightInfo;
2947 prev->next = lightInfo;
2950 pos->prev = lightInfo;
2954 /* Finally set up the light in gl itself */
2955 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2957 setup_light(iface, glIndex, lightInfo);
2958 glEnable(GL_LIGHT0 + glIndex);
2959 checkGLcall("glEnable GL_LIGHT0 new setup");
2968 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2970 PLIGHTINFOEL *lightInfo = NULL;
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 TRACE("(%p) : for idx(%ld)\n", This, Index);
2974 /* Locate the light in the live lights */
2975 lightInfo = This->stateBlock->lights;
2976 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2978 if (lightInfo == NULL) {
2979 TRACE("Light enabled state requested but light not defined\n");
2980 return WINED3DERR_INVALIDCALL;
2982 *pEnable = lightInfo->lightEnabled;
2987 * Get / Set Clip Planes
2989 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2993 /* Validate Index */
2994 if (Index >= GL_LIMITS(clipplanes)) {
2995 TRACE("Application has requested clipplane this device doesn't support\n");
2996 return WINED3DERR_INVALIDCALL;
2999 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3000 This->updateStateBlock->set.clipplane[Index] = TRUE;
3001 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3002 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3003 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3004 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3006 /* Handle recording of state blocks */
3007 if (This->isRecordingState) {
3008 TRACE("Recording... not performing anything\n");
3016 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3017 glMatrixMode(GL_MODELVIEW);
3019 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3021 TRACE("Clipplane [%f,%f,%f,%f]\n",
3022 This->updateStateBlock->clipplane[Index][0],
3023 This->updateStateBlock->clipplane[Index][1],
3024 This->updateStateBlock->clipplane[Index][2],
3025 This->updateStateBlock->clipplane[Index][3]);
3026 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3027 checkGLcall("glClipPlane");
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 TRACE("(%p) : for idx %ld\n", This, Index);
3039 /* Validate Index */
3040 if (Index >= GL_LIMITS(clipplanes)) {
3041 TRACE("Application has requested clipplane this device doesn't support\n");
3042 return WINED3DERR_INVALIDCALL;
3045 pPlane[0] = This->stateBlock->clipplane[Index][0];
3046 pPlane[1] = This->stateBlock->clipplane[Index][1];
3047 pPlane[2] = This->stateBlock->clipplane[Index][2];
3048 pPlane[3] = This->stateBlock->clipplane[Index][3];
3053 * Get / Set Clip Plane Status
3054 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3056 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 FIXME("(%p) : stub\n", This);
3059 if (NULL == pClipStatus) {
3060 return WINED3DERR_INVALIDCALL;
3062 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3063 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3067 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 FIXME("(%p) : stub\n", This);
3070 if (NULL == pClipStatus) {
3071 return WINED3DERR_INVALIDCALL;
3073 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3074 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3079 * Get / Set Material
3080 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 This->updateStateBlock->changed.material = TRUE;
3086 This->updateStateBlock->set.material = TRUE;
3087 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3089 /* Handle recording of state blocks */
3090 if (This->isRecordingState) {
3091 TRACE("Recording... not performing anything\n");
3096 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3097 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3098 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3099 pMaterial->Ambient.b, pMaterial->Ambient.a);
3100 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3101 pMaterial->Specular.b, pMaterial->Specular.a);
3102 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3103 pMaterial->Emissive.b, pMaterial->Emissive.a);
3104 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3106 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3107 checkGLcall("glMaterialfv(GL_AMBIENT)");
3108 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3109 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3111 /* Only change material color if specular is enabled, otherwise it is set to black */
3112 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3113 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3114 checkGLcall("glMaterialfv(GL_SPECULAR");
3116 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3117 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3118 checkGLcall("glMaterialfv(GL_SPECULAR");
3120 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3121 checkGLcall("glMaterialfv(GL_EMISSION)");
3122 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3123 checkGLcall("glMaterialf(GL_SHININESS");
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3132 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3133 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3134 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3135 pMaterial->Ambient.b, pMaterial->Ambient.a);
3136 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3137 pMaterial->Specular.b, pMaterial->Specular.a);
3138 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3139 pMaterial->Emissive.b, pMaterial->Emissive.a);
3140 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3149 UINT BaseVertexIndex) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 IWineD3DIndexBuffer *oldIdxs;
3153 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3154 oldIdxs = This->updateStateBlock->pIndexData;
3156 This->updateStateBlock->changed.indices = TRUE;
3157 This->updateStateBlock->set.indices = TRUE;
3158 This->updateStateBlock->pIndexData = pIndexData;
3159 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3161 /* Handle recording of state blocks */
3162 if (This->isRecordingState) {
3163 TRACE("Recording... not performing anything\n");
3167 if (NULL != pIndexData) {
3168 IWineD3DIndexBuffer_AddRef(pIndexData);
3170 if (NULL != oldIdxs) {
3171 IWineD3DIndexBuffer_Release(oldIdxs);
3176 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3179 *ppIndexData = This->stateBlock->pIndexData;
3181 /* up ref count on ppindexdata */
3183 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3184 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3185 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3187 TRACE("(%p) No index data set\n", This);
3189 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3195 * Get / Set Viewports
3197 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 TRACE("(%p)\n", This);
3201 This->updateStateBlock->changed.viewport = TRUE;
3202 This->updateStateBlock->set.viewport = TRUE;
3203 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3205 /* Handle recording of state blocks */
3206 if (This->isRecordingState) {
3207 TRACE("Recording... not performing anything\n");
3210 This->viewport_changed = TRUE;
3214 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3215 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3217 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3218 checkGLcall("glDepthRange");
3219 /* Note: GL requires lower left, DirectX supplies upper left */
3220 /* TODO: replace usage of renderTarget with context management */
3221 glViewport(pViewport->X,
3222 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3223 pViewport->Width, pViewport->Height);
3225 checkGLcall("glViewport");
3233 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3235 TRACE("(%p)\n", This);
3236 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3240 static void renderstate_stencil_twosided(
3241 IWineD3DDeviceImpl *This,
3248 GLint stencilPass ) {
3249 #if 0 /* Don't use OpenGL 2.0 calls for now */
3250 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3251 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3252 checkGLcall("glStencilFuncSeparate(...)");
3253 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3254 checkGLcall("glStencilOpSeparate(...)");
3258 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3259 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3260 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3261 GL_EXTCALL(glActiveStencilFaceEXT(face));
3262 checkGLcall("glActiveStencilFaceEXT(...)");
3263 glStencilFunc(func, ref, mask);
3264 checkGLcall("glStencilFunc(...)");
3265 glStencilOp(stencilFail, depthFail, stencilPass);
3266 checkGLcall("glStencilOp(...)");
3267 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3268 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3269 checkGLcall("glStencilFuncSeparateATI(...)");
3270 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3271 checkGLcall("glStencilOpSeparateATI(...)");
3273 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3277 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3278 DWORD onesided_enable = FALSE;
3279 DWORD twosided_enable = FALSE;
3280 GLint func = GL_ALWAYS;
3281 GLint func_ccw = GL_ALWAYS;
3284 GLint stencilFail = GL_KEEP;
3285 GLint depthFail = GL_KEEP;
3286 GLint stencilPass = GL_KEEP;
3287 GLint stencilFail_ccw = GL_KEEP;
3288 GLint depthFail_ccw = GL_KEEP;
3289 GLint stencilPass_ccw = GL_KEEP;
3291 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3292 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3293 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3294 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3295 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3296 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3297 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3298 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3299 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3300 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3301 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3302 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3303 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3304 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3305 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3306 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3307 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3308 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3309 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3310 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3311 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3312 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3313 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3314 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3317 case WINED3DRS_STENCILENABLE :
3318 onesided_enable = Value;
3320 case WINED3DRS_TWOSIDEDSTENCILMODE :
3321 twosided_enable = Value;
3323 case WINED3DRS_STENCILFUNC :
3324 func = StencilFunc(Value);
3326 case WINED3DRS_CCW_STENCILFUNC :
3327 func_ccw = StencilFunc(Value);
3329 case WINED3DRS_STENCILREF :
3332 case WINED3DRS_STENCILMASK :
3335 case WINED3DRS_STENCILFAIL :
3336 stencilFail = StencilOp(Value);
3338 case WINED3DRS_STENCILZFAIL :
3339 depthFail = StencilOp(Value);
3341 case WINED3DRS_STENCILPASS :
3342 stencilPass = StencilOp(Value);
3344 case WINED3DRS_CCW_STENCILFAIL :
3345 stencilFail_ccw = StencilOp(Value);
3347 case WINED3DRS_CCW_STENCILZFAIL :
3348 depthFail_ccw = StencilOp(Value);
3350 case WINED3DRS_CCW_STENCILPASS :
3351 stencilPass_ccw = StencilOp(Value);
3354 ERR("This should not happen!");
3357 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3358 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3359 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3360 onesided_enable, twosided_enable, ref, mask,
3361 func, stencilFail, depthFail, stencilPass,
3362 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3364 if (twosided_enable) {
3365 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3366 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3368 if (onesided_enable) {
3369 glEnable(GL_STENCIL_TEST);
3370 checkGLcall("glEnable GL_STENCIL_TEST");
3371 glStencilFunc(func, ref, mask);
3372 checkGLcall("glStencilFunc(...)");
3373 glStencilOp(stencilFail, depthFail, stencilPass);
3374 checkGLcall("glStencilOp(...)");
3376 glDisable(GL_STENCIL_TEST);
3377 checkGLcall("glDisable GL_STENCIL_TEST");
3383 * Get / Set Render States
3384 * TODO: Verify against dx9 definitions
3386 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 DWORD OldValue = This->stateBlock->renderState[State];
3391 /* Simple way of referring to either a DWORD or a 4 byte float */
3397 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3398 This->updateStateBlock->changed.renderState[State] = TRUE;
3399 This->updateStateBlock->set.renderState[State] = TRUE;
3400 This->updateStateBlock->renderState[State] = Value;
3402 /* Handle recording of state blocks */
3403 if (This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3411 case WINED3DRS_FILLMODE :
3412 switch ((D3DFILLMODE) Value) {
3413 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3414 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3415 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3417 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3419 checkGLcall("glPolygonMode (fillmode)");
3422 case WINED3DRS_LIGHTING :
3424 glEnable(GL_LIGHTING);
3425 checkGLcall("glEnable GL_LIGHTING");
3427 glDisable(GL_LIGHTING);
3428 checkGLcall("glDisable GL_LIGHTING");
3432 case WINED3DRS_ZENABLE :
3433 switch ((D3DZBUFFERTYPE) Value) {
3435 glDisable(GL_DEPTH_TEST);
3436 checkGLcall("glDisable GL_DEPTH_TEST");
3439 glEnable(GL_DEPTH_TEST);
3440 checkGLcall("glEnable GL_DEPTH_TEST");
3443 glEnable(GL_DEPTH_TEST);
3444 checkGLcall("glEnable GL_DEPTH_TEST");
3445 FIXME("W buffer is not well handled\n");
3448 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3452 case WINED3DRS_CULLMODE :
3454 /* If we are culling "back faces with clockwise vertices" then
3455 set front faces to be counter clockwise and enable culling
3457 switch ((D3DCULL) Value) {
3459 glDisable(GL_CULL_FACE);
3460 checkGLcall("glDisable GL_CULL_FACE");
3463 glEnable(GL_CULL_FACE);
3464 checkGLcall("glEnable GL_CULL_FACE");
3465 if (This->renderUpsideDown) {
3467 checkGLcall("glFrontFace GL_CW");
3469 glFrontFace(GL_CCW);
3470 checkGLcall("glFrontFace GL_CCW");
3472 glCullFace(GL_BACK);
3475 glEnable(GL_CULL_FACE);
3476 checkGLcall("glEnable GL_CULL_FACE");
3477 if (This->renderUpsideDown) {
3478 glFrontFace(GL_CCW);
3479 checkGLcall("glFrontFace GL_CCW");
3482 checkGLcall("glFrontFace GL_CW");
3484 glCullFace(GL_BACK);
3487 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3491 case WINED3DRS_SHADEMODE :
3492 switch ((D3DSHADEMODE) Value) {
3494 glShadeModel(GL_FLAT);
3495 checkGLcall("glShadeModel");
3497 case D3DSHADE_GOURAUD:
3498 glShadeModel(GL_SMOOTH);
3499 checkGLcall("glShadeModel");
3501 case D3DSHADE_PHONG:
3502 FIXME("D3DSHADE_PHONG isn't supported\n");
3505 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3509 case WINED3DRS_DITHERENABLE :
3511 glEnable(GL_DITHER);
3512 checkGLcall("glEnable GL_DITHER");
3514 glDisable(GL_DITHER);
3515 checkGLcall("glDisable GL_DITHER");
3519 case WINED3DRS_ZWRITEENABLE :
3522 checkGLcall("glDepthMask");
3525 checkGLcall("glDepthMask");
3529 case WINED3DRS_ZFUNC :
3531 int glParm = GL_LESS;
3533 switch ((D3DCMPFUNC) Value) {
3534 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3535 case D3DCMP_LESS: glParm=GL_LESS; break;
3536 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3537 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3538 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3539 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3540 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3541 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3543 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3545 glDepthFunc(glParm);
3546 checkGLcall("glDepthFunc");
3550 case WINED3DRS_AMBIENT :
3553 D3DCOLORTOGLFLOAT4(Value, col);
3554 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3555 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3556 checkGLcall("glLightModel for MODEL_AMBIENT");
3561 case WINED3DRS_ALPHABLENDENABLE :
3564 checkGLcall("glEnable GL_BLEND");
3566 glDisable(GL_BLEND);
3567 checkGLcall("glDisable GL_BLEND");
3571 case WINED3DRS_SRCBLEND :
3572 case WINED3DRS_DESTBLEND :
3574 int newVal = GL_ZERO;
3576 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3577 case D3DBLEND_ONE : newVal = GL_ONE; break;
3578 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3579 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3580 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3581 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3582 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3583 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3584 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3585 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3586 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3588 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3589 This->srcBlend = newVal;
3590 This->dstBlend = newVal;
3593 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3594 This->srcBlend = newVal;
3595 This->dstBlend = newVal;
3598 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3601 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3602 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3603 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3604 glBlendFunc(This->srcBlend, This->dstBlend);
3606 checkGLcall("glBlendFunc");
3610 case WINED3DRS_ALPHATESTENABLE :
3611 case WINED3DRS_ALPHAFUNC :
3612 case WINED3DRS_ALPHAREF :
3613 case WINED3DRS_COLORKEYENABLE :
3616 float ref = GL_LESS;
3617 BOOL enable_ckey = FALSE;
3619 IWineD3DSurfaceImpl *surf;
3621 /* Find out if the texture on the first stage has a ckey set */
3622 if(This->stateBlock->textures[0]) {
3623 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3624 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3627 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3628 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3629 glEnable(GL_ALPHA_TEST);
3630 checkGLcall("glEnable GL_ALPHA_TEST");
3632 glDisable(GL_ALPHA_TEST);
3633 checkGLcall("glDisable GL_ALPHA_TEST");
3634 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3640 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3641 glParm = GL_NOTEQUAL;
3644 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3646 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3647 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3648 case D3DCMP_LESS: glParm = GL_LESS; break;
3649 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3650 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3651 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3652 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3653 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3654 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3656 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3659 This->alphafunc = glParm;
3660 glAlphaFunc(glParm, ref);
3661 checkGLcall("glAlphaFunc");
3665 case WINED3DRS_CLIPPLANEENABLE :
3666 case WINED3DRS_CLIPPING :
3668 /* Ensure we only do the changed clip planes */
3669 DWORD enable = 0xFFFFFFFF;
3670 DWORD disable = 0x00000000;
3672 /* If enabling / disabling all */
3673 if (State == WINED3DRS_CLIPPING) {
3675 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3678 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3682 enable = Value & ~OldValue;
3683 disable = ~Value & OldValue;
3686 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3687 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3688 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3689 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3690 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3691 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3693 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3694 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3695 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3696 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3697 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3698 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3700 /** update clipping status */
3702 This->stateBlock->clip_status.ClipUnion = 0;
3703 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3705 This->stateBlock->clip_status.ClipUnion = 0;
3706 This->stateBlock->clip_status.ClipIntersection = 0;
3711 case WINED3DRS_BLENDOP :
3713 int glParm = GL_FUNC_ADD;
3715 switch ((D3DBLENDOP) Value) {
3716 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3717 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3718 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3719 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3720 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3722 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3725 if(GL_SUPPORT(ARB_IMAGING)) {
3726 TRACE("glBlendEquation(%x)\n", glParm);
3727 GL_EXTCALL(glBlendEquation(glParm));
3728 checkGLcall("glBlendEquation");
3730 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3735 case WINED3DRS_TEXTUREFACTOR :
3739 /* Note the texture color applies to all textures whereas
3740 GL_TEXTURE_ENV_COLOR applies to active only */
3742 D3DCOLORTOGLFLOAT4(Value, col);
3743 /* Set the default alpha blend color */
3744 if (GL_SUPPORT(ARB_IMAGING)) {
3745 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3746 checkGLcall("glBlendColor");
3748 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3751 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3752 /* And now the default texture color as well */
3753 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3754 /* Note the D3DRS value applies to all textures, but GL has one
3755 per texture, so apply it now ready to be used! */
3756 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3757 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3758 checkGLcall("glActiveTextureARB");
3760 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3763 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3764 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3770 case WINED3DRS_SPECULARENABLE :
3772 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3773 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3774 specular color. This is wrong:
3775 Separate specular color means the specular colour is maintained separately, whereas
3776 single color means it is merged in. However in both cases they are being used to
3778 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3779 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3783 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3784 * Instead, we need to setup the FinalCombiner properly.
3786 * The default setup for the FinalCombiner is:
3788 * <variable> <input> <mapping> <usage>
3789 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3790 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3791 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3792 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3793 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3794 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3795 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3797 * That's pretty much fine as it is, except for variable B, which needs to take
3798 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3799 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3803 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3804 checkGLcall("glMaterialfv");
3805 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3806 glEnable(GL_COLOR_SUM_EXT);
3808 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3810 checkGLcall("glEnable(GL_COLOR_SUM)");
3812 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3813 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3814 checkGLcall("glFinalCombinerInputNV()");
3817 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3819 /* for the case of enabled lighting: */
3820 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3821 checkGLcall("glMaterialfv");
3823 /* for the case of disabled lighting: */
3824 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3825 glDisable(GL_COLOR_SUM_EXT);
3827 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3829 checkGLcall("glDisable(GL_COLOR_SUM)");
3831 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3832 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3833 checkGLcall("glFinalCombinerInputNV()");
3839 case WINED3DRS_STENCILENABLE :
3840 case WINED3DRS_TWOSIDEDSTENCILMODE :
3841 case WINED3DRS_STENCILFUNC :
3842 case WINED3DRS_CCW_STENCILFUNC :
3843 case WINED3DRS_STENCILREF :
3844 case WINED3DRS_STENCILMASK :
3845 case WINED3DRS_STENCILFAIL :
3846 case WINED3DRS_STENCILZFAIL :
3847 case WINED3DRS_STENCILPASS :
3848 case WINED3DRS_CCW_STENCILFAIL :
3849 case WINED3DRS_CCW_STENCILZFAIL :
3850 case WINED3DRS_CCW_STENCILPASS :
3851 renderstate_stencil(This, State, Value);
3853 case WINED3DRS_STENCILWRITEMASK :
3855 glStencilMask(Value);
3856 TRACE("glStencilMask(%lu)\n", Value);
3857 checkGLcall("glStencilMask");
3861 case WINED3DRS_FOGENABLE :
3865 checkGLcall("glEnable GL_FOG");
3868 checkGLcall("glDisable GL_FOG");
3873 case WINED3DRS_RANGEFOGENABLE :
3876 TRACE("Enabled RANGEFOG");
3878 TRACE("Disabled RANGEFOG");
3883 case WINED3DRS_FOGCOLOR :
3886 D3DCOLORTOGLFLOAT4(Value, col);
3887 /* Set the default alpha blend color */
3888 glFogfv(GL_FOG_COLOR, &col[0]);
3889 checkGLcall("glFog GL_FOG_COLOR");
3893 case WINED3DRS_FOGTABLEMODE :
3894 case WINED3DRS_FOGVERTEXMODE :
3896 /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */
3897 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3898 glHint(GL_FOG_HINT, GL_FASTEST);
3899 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3900 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3901 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3902 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3905 if(!This->last_was_rhw) {
3906 glFogi(GL_FOG_MODE, GL_EXP);
3907 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3908 if(GL_SUPPORT(EXT_FOG_COORD)) {
3909 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3910 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3911 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3912 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3918 if(!This->last_was_rhw) {
3919 glFogi(GL_FOG_MODE, GL_EXP2);
3920 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3921 if(GL_SUPPORT(EXT_FOG_COORD)) {
3922 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3923 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3924 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3925 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3930 case D3DFOG_LINEAR: {
3931 if(!This->last_was_rhw) {
3932 glFogi(GL_FOG_MODE, GL_LINEAR);
3933 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3934 if(GL_SUPPORT(EXT_FOG_COORD)) {
3935 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3936 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3937 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3938 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3944 /* Both are none? According to msdn the alpha channel of the specular
3945 * color contains a fog factor. Set it in drawStridedSlow.
3946 * Same happens with Vertexfog on transformed vertices
3948 if(GL_SUPPORT(EXT_FOG_COORD)) {
3949 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3950 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3951 glFogi(GL_FOG_MODE, GL_LINEAR);
3952 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3953 glFogf(GL_FOG_START, (float) 0xff);
3954 checkGLcall("glFogfv GL_FOG_START");
3955 glFogf(GL_FOG_END, 0.0);
3956 checkGLcall("glFogfv GL_FOG_END");
3958 /* Disable GL fog, handle this in software in drawStridedSlow */
3960 checkGLcall("glDisable(GL_FOG)");
3964 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3967 glHint(GL_FOG_HINT, GL_NICEST);
3968 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3969 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3970 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3971 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3972 if(GL_SUPPORT(EXT_FOG_COORD)) {
3973 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3974 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3975 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3976 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3979 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3980 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3981 if(GL_SUPPORT(EXT_FOG_COORD)) {
3982 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3983 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3984 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3985 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3988 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3989 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3990 if(GL_SUPPORT(EXT_FOG_COORD)) {
3991 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3992 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3993 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3994 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3997 case D3DFOG_NONE: /* Won't happen */
3998 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4001 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4002 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4007 case WINED3DRS_FOGSTART :
4010 glFogfv(GL_FOG_START, &tmpvalue.f);
4011 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4012 TRACE("Fog Start == %f\n", tmpvalue.f);
4016 case WINED3DRS_FOGEND :
4019 glFogfv(GL_FOG_END, &tmpvalue.f);
4020 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4021 TRACE("Fog End == %f\n", tmpvalue.f);
4025 case WINED3DRS_FOGDENSITY :
4028 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4029 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4033 case WINED3DRS_VERTEXBLEND :
4035 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4036 TRACE("Vertex Blending state to %ld\n", Value);
4040 case WINED3DRS_TWEENFACTOR :
4043 This->updateStateBlock->tween_factor = tmpvalue.f;
4044 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4048 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4050 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4054 case WINED3DRS_COLORVERTEX :
4055 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4056 case WINED3DRS_SPECULARMATERIALSOURCE :
4057 case WINED3DRS_AMBIENTMATERIALSOURCE :
4058 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4060 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4062 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4063 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4064 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4065 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4066 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4067 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4069 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4070 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4071 Parm = GL_AMBIENT_AND_DIFFUSE;
4075 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4077 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4079 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4086 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4088 This->tracking_color = NEEDS_TRACKING;
4089 This->tracking_parm = Parm;
4093 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4098 case WINED3DRS_LINEPATTERN :
4104 tmppattern.d = Value;
4106 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4108 if (tmppattern.lp.wRepeatFactor) {
4109 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4110 checkGLcall("glLineStipple(repeat, linepattern)");
4111 glEnable(GL_LINE_STIPPLE);
4112 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4114 glDisable(GL_LINE_STIPPLE);
4115 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4120 case WINED3DRS_ZBIAS : /* D3D8 only */
4124 TRACE("ZBias value %f\n", tmpvalue.f);
4125 glPolygonOffset(0, -tmpvalue.f);
4126 checkGLcall("glPolygonOffset(0, -Value)");
4127 glEnable(GL_POLYGON_OFFSET_FILL);
4128 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4129 glEnable(GL_POLYGON_OFFSET_LINE);
4130 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4131 glEnable(GL_POLYGON_OFFSET_POINT);
4132 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4134 glDisable(GL_POLYGON_OFFSET_FILL);
4135 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4136 glDisable(GL_POLYGON_OFFSET_LINE);
4137 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4138 glDisable(GL_POLYGON_OFFSET_POINT);
4139 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4144 case WINED3DRS_NORMALIZENORMALS :
4146 glEnable(GL_NORMALIZE);
4147 checkGLcall("glEnable(GL_NORMALIZE);");
4149 glDisable(GL_NORMALIZE);
4150 checkGLcall("glDisable(GL_NORMALIZE);");
4154 case WINED3DRS_POINTSIZE :
4155 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4157 TRACE("Set point size to %f\n", tmpvalue.f);
4158 glPointSize(tmpvalue.f);
4159 checkGLcall("glPointSize(...);");
4162 case WINED3DRS_POINTSIZE_MIN :
4163 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4165 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4166 checkGLcall("glPointParameterfEXT(...);");
4168 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4172 case WINED3DRS_POINTSIZE_MAX :
4173 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4175 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4176 checkGLcall("glPointParameterfEXT(...);");
4178 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4182 case WINED3DRS_POINTSCALE_A :
4183 case WINED3DRS_POINTSCALE_B :
4184 case WINED3DRS_POINTSCALE_C :
4185 case WINED3DRS_POINTSCALEENABLE :
4188 * POINTSCALEENABLE controls how point size value is treated. If set to
4189 * true, the point size is scaled with respect to height of viewport.
4190 * When set to false point size is in pixels.
4192 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4195 /* Default values */
4196 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4199 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4200 * This means that OpenGL will clamp really small point sizes to 1.0f.
4201 * To correct for this we need to multiply by the scale factor when sizes
4202 * are less than 1.0f. scale_factor = 1.0f / point_size.
4204 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4205 if(pointSize > 0.0f) {
4206 GLfloat scaleFactor;
4208 if(pointSize < 1.0f) {
4209 scaleFactor = pointSize * pointSize;
4214 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4215 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4216 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4217 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4218 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4219 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4220 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4224 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4225 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4226 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4228 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4229 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4230 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4232 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4236 case WINED3DRS_COLORWRITEENABLE :
4238 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4239 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4240 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4241 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4242 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4243 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4244 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4245 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4246 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4247 checkGLcall("glColorMask(...)");
4251 case WINED3DRS_LOCALVIEWER :
4253 GLint state = (Value) ? 1 : 0;
4254 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4255 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4259 case WINED3DRS_LASTPIXEL :
4262 TRACE("Last Pixel Drawing Enabled\n");
4264 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4269 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4272 TRACE("Software Processing Enabled\n");
4274 TRACE("Software Processing Disabled\n");
4279 /** not supported */
4280 case WINED3DRS_ZVISIBLE :
4283 return WINED3DERR_INVALIDCALL;
4285 case WINED3DRS_POINTSPRITEENABLE :
4287 /* TODO: NV_POINT_SPRITE */
4288 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4289 TRACE("Point sprites not supported\n");
4294 * Point sprites are always enabled. Value controls texture coordinate
4295 * replacement mode. Must be set true for point sprites to use
4298 glEnable(GL_POINT_SPRITE_ARB);
4299 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4302 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4303 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4305 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4306 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4310 case WINED3DRS_EDGEANTIALIAS :
4313 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4315 checkGLcall("glEnable(GL_BLEND)");
4316 glEnable(GL_LINE_SMOOTH);
4317 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4319 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4320 glDisable(GL_BLEND);
4321 checkGLcall("glDisable(GL_BLEND)");
4323 glDisable(GL_LINE_SMOOTH);
4324 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4328 case WINED3DRS_WRAP0 :
4329 case WINED3DRS_WRAP1 :
4330 case WINED3DRS_WRAP2 :
4331 case WINED3DRS_WRAP3 :
4332 case WINED3DRS_WRAP4 :
4333 case WINED3DRS_WRAP5 :
4334 case WINED3DRS_WRAP6 :
4335 case WINED3DRS_WRAP7 :
4336 case WINED3DRS_WRAP8 :
4337 case WINED3DRS_WRAP9 :
4338 case WINED3DRS_WRAP10 :
4339 case WINED3DRS_WRAP11 :
4340 case WINED3DRS_WRAP12 :
4341 case WINED3DRS_WRAP13 :
4342 case WINED3DRS_WRAP14 :
4343 case WINED3DRS_WRAP15 :
4345 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4346 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4347 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4348 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4349 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4351 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4353 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4355 case WINED3DRS_MULTISAMPLEANTIALIAS :
4357 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4358 TRACE("Multisample antialiasing not supported\n");
4363 glEnable(GL_MULTISAMPLE_ARB);
4364 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4366 glDisable(GL_MULTISAMPLE_ARB);
4367 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4371 case WINED3DRS_SCISSORTESTENABLE :
4374 glEnable(GL_SCISSOR_TEST);
4375 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4377 glDisable(GL_SCISSOR_TEST);
4378 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4382 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4386 glEnable(GL_POLYGON_OFFSET_FILL);
4387 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4388 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4389 checkGLcall("glPolygonOffset(...)");
4391 glDisable(GL_POLYGON_OFFSET_FILL);
4392 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4396 case WINED3DRS_ANTIALIASEDLINEENABLE :
4399 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4401 checkGLcall("glEnable(GL_BLEND)");
4402 glEnable(GL_LINE_SMOOTH);
4403 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4405 glDisable(GL_BLEND);
4406 checkGLcall("glDisable(GL_BLEND)");
4407 glDisable(GL_LINE_SMOOTH);
4408 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4412 case WINED3DRS_DEPTHBIAS :
4416 glEnable(GL_POLYGON_OFFSET_FILL);
4417 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4418 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4419 checkGLcall("glPolygonOffset(...)");
4421 glDisable(GL_POLYGON_OFFSET_FILL);
4422 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4427 case WINED3DRS_TEXTUREPERSPECTIVE :
4430 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4432 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4436 case WINED3DRS_STIPPLEDALPHA :
4439 ERR(" Stippled Alpha not supported yet.\n");
4442 case WINED3DRS_ANTIALIAS :
4445 ERR(" Antialias not supported yet.\n");
4449 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4457 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4460 *pValue = This->stateBlock->renderState[State];
4465 * Get / Set Sampler States
4466 * TODO: Verify against dx9 definitions
4469 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 * SetSampler is designed to allow for more than the standard up to 8 textures
4473 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4474 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4476 * http://developer.nvidia.com/object/General_FAQ.html#t6
4478 * There are two new settings for GForce
4480 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4481 * and the texture one:
4482 * GL_MAX_TEXTURE_COORDS_ARB.
4483 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4485 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4486 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4487 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4488 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4489 return WINED3DERR_INVALIDCALL;
4492 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4493 debug_d3dsamplerstate(Type), Type, Value);
4494 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4495 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4496 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4498 /* Handle recording of state blocks */
4499 if (This->isRecordingState) {
4500 TRACE("Recording... not performing anything\n");
4507 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 /** TODO: check that sampler is in range **/
4510 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4511 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4516 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4521 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4522 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4528 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 GLint scissorBox[4];
4533 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4534 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4535 pRect->left = scissorBox[0];
4536 pRect->top = scissorBox[1];
4537 pRect->right = scissorBox[0] + scissorBox[2];
4538 pRect->bottom = scissorBox[1] + scissorBox[3];
4539 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4544 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4546 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4548 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4550 This->updateStateBlock->vertexDecl = pDecl;
4551 This->updateStateBlock->changed.vertexDecl = TRUE;
4552 This->updateStateBlock->set.vertexDecl = TRUE;
4554 if (This->isRecordingState) {
4555 TRACE("Recording... not performing anything\n");
4558 if (NULL != pDecl) {
4559 IWineD3DVertexDeclaration_AddRef(pDecl);
4561 if (NULL != oldDecl) {
4562 IWineD3DVertexDeclaration_Release(oldDecl);
4567 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4570 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4572 *ppDecl = This->stateBlock->vertexDecl;
4573 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4581 This->updateStateBlock->vertexShader = pShader;
4582 This->updateStateBlock->changed.vertexShader = TRUE;
4583 This->updateStateBlock->set.vertexShader = TRUE;
4585 if (This->isRecordingState) {
4586 TRACE("Recording... not performing anything\n");
4589 if (NULL != pShader) {
4590 IWineD3DVertexShader_AddRef(pShader);
4592 if (NULL != oldShader) {
4593 IWineD3DVertexShader_Release(oldShader);
4596 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4598 * TODO: merge HAL shaders context switching from prototype
4603 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4606 if (NULL == ppShader) {
4607 return WINED3DERR_INVALIDCALL;
4609 *ppShader = This->stateBlock->vertexShader;
4610 if( NULL != *ppShader)
4611 IWineD3DVertexShader_AddRef(*ppShader);
4613 TRACE("(%p) : returning %p\n", This, *ppShader);
4617 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4618 IWineD3DDevice *iface,
4620 CONST BOOL *srcData,
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 int i, cnt = min(count, MAX_CONST_B - start);
4626 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4627 iface, srcData, start, count);
4629 if (srcData == NULL || cnt < 0)
4630 return WINED3DERR_INVALIDCALL;
4632 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4633 for (i = 0; i < cnt; i++)
4634 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4636 for (i = start; i < cnt + start; ++i) {
4637 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4638 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4644 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4645 IWineD3DDevice *iface,
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 int cnt = min(count, MAX_CONST_B - start);
4653 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4654 iface, dstData, start, count);
4656 if (dstData == NULL || cnt < 0)
4657 return WINED3DERR_INVALIDCALL;
4659 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4663 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4664 IWineD3DDevice *iface,
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 int i, cnt = min(count, MAX_CONST_I - start);
4672 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4673 iface, srcData, start, count);
4675 if (srcData == NULL || cnt < 0)
4676 return WINED3DERR_INVALIDCALL;
4678 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4679 for (i = 0; i < cnt; i++)
4680 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4681 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4683 for (i = start; i < cnt + start; ++i) {
4684 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4685 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4691 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4692 IWineD3DDevice *iface,
4697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4698 int cnt = min(count, MAX_CONST_I - start);
4700 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4701 iface, dstData, start, count);
4703 if (dstData == NULL || cnt < 0)
4704 return WINED3DERR_INVALIDCALL;
4706 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4710 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4711 IWineD3DDevice *iface,
4713 CONST float *srcData,
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4719 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4720 iface, srcData, start, count);
4722 if (srcData == NULL || cnt < 0)
4723 return WINED3DERR_INVALIDCALL;
4725 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4726 for (i = 0; i < cnt; i++)
4727 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4728 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4730 for (i = start; i < cnt + start; ++i) {
4731 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4732 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4739 IWineD3DDevice *iface,
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4747 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4748 iface, dstData, start, count);
4750 if (dstData == NULL || cnt < 0)
4751 return WINED3DERR_INVALIDCALL;
4753 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4757 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4760 This->updateStateBlock->pixelShader = pShader;
4761 This->updateStateBlock->changed.pixelShader = TRUE;
4762 This->updateStateBlock->set.pixelShader = TRUE;
4764 /* Handle recording of state blocks */
4765 if (This->isRecordingState) {
4766 TRACE("Recording... not performing anything\n");
4769 if (NULL != pShader) {
4770 IWineD3DPixelShader_AddRef(pShader);
4772 if (NULL != oldShader) {
4773 IWineD3DPixelShader_Release(oldShader);
4776 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4778 * TODO: merge HAL shaders context switching from prototype
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 if (NULL == ppShader) {
4787 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4788 return WINED3DERR_INVALIDCALL;
4791 *ppShader = This->stateBlock->pixelShader;
4792 if (NULL != *ppShader) {
4793 IWineD3DPixelShader_AddRef(*ppShader);
4795 TRACE("(%p) : returning %p\n", This, *ppShader);
4799 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4800 IWineD3DDevice *iface,
4802 CONST BOOL *srcData,
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 int i, cnt = min(count, MAX_CONST_B - start);
4808 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4809 iface, srcData, start, count);
4811 if (srcData == NULL || cnt < 0)
4812 return WINED3DERR_INVALIDCALL;
4814 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4815 for (i = 0; i < cnt; i++)
4816 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4818 for (i = start; i < cnt + start; ++i) {
4819 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4820 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4827 IWineD3DDevice *iface,
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 int cnt = min(count, MAX_CONST_B - start);
4835 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4836 iface, dstData, start, count);
4838 if (dstData == NULL || cnt < 0)
4839 return WINED3DERR_INVALIDCALL;
4841 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4845 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4846 IWineD3DDevice *iface,
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 int i, cnt = min(count, MAX_CONST_I - start);
4854 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4855 iface, srcData, start, count);
4857 if (srcData == NULL || cnt < 0)
4858 return WINED3DERR_INVALIDCALL;
4860 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4861 for (i = 0; i < cnt; i++)
4862 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4863 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4865 for (i = start; i < cnt + start; ++i) {
4866 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4867 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4874 IWineD3DDevice *iface,
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 int cnt = min(count, MAX_CONST_I - start);
4882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4883 iface, dstData, start, count);
4885 if (dstData == NULL || cnt < 0)
4886 return WINED3DERR_INVALIDCALL;
4888 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4892 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4893 IWineD3DDevice *iface,
4895 CONST float *srcData,
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4901 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4902 iface, srcData, start, count);
4904 if (srcData == NULL || cnt < 0)
4905 return WINED3DERR_INVALIDCALL;
4907 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4908 for (i = 0; i < cnt; i++)
4909 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4910 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4912 for (i = start; i < cnt + start; ++i) {
4913 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4914 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4921 IWineD3DDevice *iface,
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4929 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4930 iface, dstData, start, count);
4932 if (dstData == NULL || cnt < 0)
4933 return WINED3DERR_INVALIDCALL;
4935 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4939 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4941 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4942 char *dest_ptr, *dest_conv = NULL;
4944 DWORD DestFVF = dest->fvf;
4946 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4950 if (SrcFVF & D3DFVF_NORMAL) {
4951 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4954 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4955 ERR("Source has no position mask\n");
4956 return WINED3DERR_INVALIDCALL;
4959 /* We might access VBOs from this code, so hold the lock */
4962 if (dest->resource.allocatedMemory == NULL) {
4963 /* This may happen if we do direct locking into a vbo. Unlikely,
4964 * but theoretically possible(ddraw processvertices test)
4966 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4967 if(!dest->resource.allocatedMemory) {
4969 ERR("Out of memory\n");
4970 return E_OUTOFMEMORY;
4974 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4975 checkGLcall("glBindBufferARB");
4976 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4978 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4980 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4981 checkGLcall("glUnmapBufferARB");
4985 /* Get a pointer into the destination vbo(create one if none exists) and
4986 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4988 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4993 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4994 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4996 ERR("glMapBuffer failed\n");
4997 /* Continue without storing converted vertices */
5002 * a) D3DRS_CLIPPING is enabled
5003 * b) WINED3DVOP_CLIP is passed
5005 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5006 static BOOL warned = FALSE;
5008 * The clipping code is not quite correct. Some things need
5009 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5010 * so disable clipping for now.
5011 * (The graphics in Half-Life are broken, and my processvertices
5012 * test crashes with IDirect3DDevice3)
5018 FIXME("Clipping is broken and disabled for now\n");
5020 } else doClip = FALSE;
5021 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5023 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5026 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5029 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5032 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5033 D3DTS_WORLDMATRIX(0),
5036 TRACE("View mat:\n");
5037 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); \
5038 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); \
5039 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); \
5040 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); \
5042 TRACE("Proj mat:\n");
5043 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); \
5044 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); \
5045 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); \
5046 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); \
5048 TRACE("World mat:\n");
5049 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); \
5050 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); \
5051 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); \
5052 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); \
5054 /* Get the viewport */
5055 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5056 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5057 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5059 multiply_matrix(&mat,&view_mat,&world_mat);
5060 multiply_matrix(&mat,&proj_mat,&mat);
5062 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5064 for (i = 0; i < dwCount; i+= 1) {
5065 unsigned int tex_index;
5067 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5068 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5069 /* The position first */
5071 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5073 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5075 /* Multiplication with world, view and projection matrix */
5076 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);
5077 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);
5078 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);
5079 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);
5081 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5083 /* WARNING: The following things are taken from d3d7 and were not yet checked
5084 * against d3d8 or d3d9!
5087 /* Clipping conditions: From
5088 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5090 * A vertex is clipped if it does not match the following requirements
5094 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5096 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5097 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5101 if( doClip == FALSE ||
5102 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5103 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5106 /* "Normal" viewport transformation (not clipped)
5107 * 1) The values are divided by rhw
5108 * 2) The y axis is negative, so multiply it with -1
5109 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5110 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5111 * 4) Multiply x with Width/2 and add Width/2
5112 * 5) The same for the height
5113 * 6) Add the viewpoint X and Y to the 2D coordinates and
5114 * The minimum Z value to z
5115 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5117 * Well, basically it's simply a linear transformation into viewport
5129 z *= vp.MaxZ - vp.MinZ;
5131 x += vp.Width / 2 + vp.X;
5132 y += vp.Height / 2 + vp.Y;
5137 /* That vertex got clipped
5138 * Contrary to OpenGL it is not dropped completely, it just
5139 * undergoes a different calculation.
5141 TRACE("Vertex got clipped\n");
5148 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5149 * outside of the main vertex buffer memory. That needs some more
5154 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5157 ( (float *) dest_ptr)[0] = x;
5158 ( (float *) dest_ptr)[1] = y;
5159 ( (float *) dest_ptr)[2] = z;
5160 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5162 dest_ptr += 3 * sizeof(float);
5164 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5165 dest_ptr += sizeof(float);
5170 ( (float *) dest_conv)[0] = x * w;
5171 ( (float *) dest_conv)[1] = y * w;
5172 ( (float *) dest_conv)[2] = z * w;
5173 ( (float *) dest_conv)[3] = w;
5175 dest_conv += 3 * sizeof(float);
5177 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5178 dest_conv += sizeof(float);
5182 if (DestFVF & D3DFVF_PSIZE) {
5183 dest_ptr += sizeof(DWORD);
5184 if(dest_conv) dest_conv += sizeof(DWORD);
5186 if (DestFVF & D3DFVF_NORMAL) {
5188 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5189 /* AFAIK this should go into the lighting information */
5190 FIXME("Didn't expect the destination to have a normal\n");
5191 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5193 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5197 if (DestFVF & D3DFVF_DIFFUSE) {
5199 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5201 static BOOL warned = FALSE;
5203 if(warned == FALSE) {
5204 ERR("No diffuse color in source, but destination has one\n");
5208 *( (DWORD *) dest_ptr) = 0xffffffff;
5209 dest_ptr += sizeof(DWORD);
5212 *( (DWORD *) dest_conv) = 0xffffffff;
5213 dest_conv += sizeof(DWORD);
5217 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5219 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5220 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5221 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5222 dest_conv += sizeof(DWORD);
5227 if (DestFVF & D3DFVF_SPECULAR) {
5228 /* What's the color value in the feedback buffer? */
5230 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5232 static BOOL warned = FALSE;
5234 if(warned == FALSE) {
5235 ERR("No specular color in source, but destination has one\n");
5239 *( (DWORD *) dest_ptr) = 0xFF000000;
5240 dest_ptr += sizeof(DWORD);
5243 *( (DWORD *) dest_conv) = 0xFF000000;
5244 dest_conv += sizeof(DWORD);
5248 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5250 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5251 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5252 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5253 dest_conv += sizeof(DWORD);
5258 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5260 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5261 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5263 ERR("No source texture, but destination requests one\n");
5264 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5265 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5268 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5270 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5277 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5278 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5285 #undef copy_and_next
5287 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5290 WineDirect3DVertexStridedData strided;
5291 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5293 /* We don't need the source vbo because this buffer is only used as
5294 * a source for ProcessVertices. Avoid wasting resources by converting the
5295 * buffer and loading the VBO
5298 TRACE("Releaseing the source vbo, it won't be needed\n");
5300 if(!SrcImpl->resource.allocatedMemory) {
5301 /* Rescue the data from the buffer */
5303 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5304 if(!SrcImpl->resource.allocatedMemory) {
5305 ERR("Out of memory\n");
5306 return E_OUTOFMEMORY;
5310 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5311 checkGLcall("glBindBufferARB");
5313 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5315 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5318 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5319 checkGLcall("glUnmapBufferARB");
5324 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5325 checkGLcall("glBindBufferARB");
5326 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5327 checkGLcall("glDeleteBuffersARB");
5333 memset(&strided, 0, sizeof(strided));
5334 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5336 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5340 * Apply / Get / Set Texture Stage States
5341 * TODO: Verify against dx9 definitions
5344 /* NOTE: It's expected that this function is going to be called lots of times with the same stage active, so make it the callers responsibility to GLACTIVETEXTURE(Stage) for better state management. Set the correct Texture unit active before calling ApplyTextureStageState */
5345 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5347 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5348 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5350 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5352 /* Check that the stage is within limits */
5353 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5354 TRACE("Attempt to access invalid texture rejected\n");
5361 case WINED3DTSS_ALPHAOP :
5362 case WINED3DTSS_COLOROP :
5363 /* nothing to do as moved to drawprim for now */
5365 case WINED3DTSS_ADDRESSW :
5366 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5367 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5368 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5371 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5372 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5373 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5374 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5377 case WINED3DTSS_TEXCOORDINDEX :
5379 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5381 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5382 one flag, you can still specify an index value, which the system uses to
5383 determine the texture wrapping mode.
5384 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5385 means use the vertex position (camera-space) as the input texture coordinates
5386 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5387 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5388 to the TEXCOORDINDEX value */
5391 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5393 switch (Value & 0xFFFF0000) {
5394 case D3DTSS_TCI_PASSTHRU:
5395 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5396 glDisable(GL_TEXTURE_GEN_S);
5397 glDisable(GL_TEXTURE_GEN_T);
5398 glDisable(GL_TEXTURE_GEN_R);
5399 glDisable(GL_TEXTURE_GEN_Q);
5400 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5403 case D3DTSS_TCI_CAMERASPACEPOSITION:
5404 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5405 as the input texture coordinates for this stage's texture transformation. This
5406 equates roughly to EYE_LINEAR */
5408 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5409 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5410 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5411 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5412 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5414 glMatrixMode(GL_MODELVIEW);
5417 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5418 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5419 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5420 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5423 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5424 glEnable(GL_TEXTURE_GEN_S);
5425 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5426 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5427 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5428 glEnable(GL_TEXTURE_GEN_T);
5429 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5430 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5431 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5432 glEnable(GL_TEXTURE_GEN_R);
5433 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5434 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5435 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5439 case D3DTSS_TCI_CAMERASPACENORMAL:
5441 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5442 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5443 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5444 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5445 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5446 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5448 glMatrixMode(GL_MODELVIEW);
5451 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5452 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5453 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5454 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5457 glEnable(GL_TEXTURE_GEN_S);
5458 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5459 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5460 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5461 glEnable(GL_TEXTURE_GEN_T);
5462 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5463 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5464 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5465 glEnable(GL_TEXTURE_GEN_R);
5466 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5467 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5468 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5473 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5475 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5476 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5477 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5478 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5479 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5480 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5482 glMatrixMode(GL_MODELVIEW);
5485 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5486 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5487 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5488 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5491 glEnable(GL_TEXTURE_GEN_S);
5492 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5493 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5494 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5495 glEnable(GL_TEXTURE_GEN_T);
5496 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5497 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5498 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5499 glEnable(GL_TEXTURE_GEN_R);
5500 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5501 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5502 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5507 /* Unhandled types: */
5510 /* ? disable GL_TEXTURE_GEN_n ? */
5511 glDisable(GL_TEXTURE_GEN_S);
5512 glDisable(GL_TEXTURE_GEN_T);
5513 glDisable(GL_TEXTURE_GEN_R);
5514 glDisable(GL_TEXTURE_GEN_Q);
5515 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5522 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5523 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5526 case WINED3DTSS_BUMPENVMAT00 :
5527 case WINED3DTSS_BUMPENVMAT01 :
5528 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5530 case WINED3DTSS_BUMPENVMAT10 :
5531 case WINED3DTSS_BUMPENVMAT11 :
5532 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5535 case WINED3DTSS_BUMPENVLSCALE :
5536 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5539 case WINED3DTSS_BUMPENVLOFFSET :
5540 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5543 case WINED3DTSS_RESULTARG :
5544 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5548 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5549 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5558 * Get / Set Texture Stage States
5559 * TODO: Verify against dx9 definitions
5561 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5564 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5566 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5568 /* Reject invalid texture units */
5569 if (Stage >= GL_LIMITS(texture_stages)) {
5570 TRACE("Attempt to access invalid texture rejected\n");
5571 return WINED3DERR_INVALIDCALL;
5574 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5575 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5576 This->updateStateBlock->textureState[Stage][Type] = Value;
5581 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5584 *pValue = This->updateStateBlock->textureState[Stage][Type];
5591 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 IWineD3DBaseTexture *oldTexture;
5596 oldTexture = This->updateStateBlock->textures[Stage];
5597 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5599 #if 0 /* TODO: check so vertex textures */
5600 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5601 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5606 /* Reject invalid texture units */
5607 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5608 WARN("Attempt to access invalid texture rejected\n");
5609 return WINED3DERR_INVALIDCALL;
5612 if(pTexture != NULL) {
5613 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5615 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5616 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5617 return WINED3DERR_INVALIDCALL;
5621 oldTexture = This->updateStateBlock->textures[Stage];
5622 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5623 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5625 This->updateStateBlock->set.textures[Stage] = TRUE;
5626 This->updateStateBlock->changed.textures[Stage] = TRUE;
5627 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5628 This->updateStateBlock->textures[Stage] = pTexture;
5630 /* Handle recording of state blocks */
5631 if (This->isRecordingState) {
5632 TRACE("Recording... not performing anything\n");
5636 /** NOTE: MSDN says that setTexture increases the reference count,
5637 * and the the application nust set the texture back to null (or have a leaky application),
5638 * This means we should pass the refcount up to the parent
5639 *******************************/
5640 if (NULL != This->updateStateBlock->textures[Stage]) {
5641 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5644 if (NULL != oldTexture) {
5645 IWineD3DBaseTexture_Release(oldTexture);
5648 /* Reset color keying */
5649 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5650 BOOL enable_ckey = FALSE;
5653 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5654 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5658 glAlphaFunc(GL_NOTEQUAL, 0.0);
5659 checkGLcall("glAlphaFunc");
5666 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5670 /* Reject invalid texture units */
5671 if (Stage >= GL_LIMITS(sampler_stages)) {
5672 TRACE("Attempt to access invalid texture rejected\n");
5673 return WINED3DERR_INVALIDCALL;
5675 *ppTexture=This->updateStateBlock->textures[Stage];
5677 IWineD3DBaseTexture_AddRef(*ppTexture);
5679 return WINED3DERR_INVALIDCALL;
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5687 IWineD3DSurface **ppBackBuffer) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 IWineD3DSwapChain *swapChain;
5692 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5694 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5695 if (hr == WINED3D_OK) {
5696 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5697 IWineD3DSwapChain_Release(swapChain);
5699 *ppBackBuffer = NULL;
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 WARN("(%p) : stub, calling idirect3d for now\n", This);
5707 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5710 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 IWineD3DSwapChain *swapChain;
5715 if(iSwapChain > 0) {
5716 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5717 if (hr == WINED3D_OK) {
5718 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5719 IWineD3DSwapChain_Release(swapChain);
5721 FIXME("(%p) Error getting display mode\n", This);
5724 /* Don't read the real display mode,
5725 but return the stored mode instead. X11 can't change the color
5726 depth, and some apps are pretty angry if they SetDisplayMode from
5727 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5729 Also don't relay to the swapchain because with ddraw it's possible
5730 that there isn't a swapchain at all */
5731 pMode->Width = This->ddraw_width;
5732 pMode->Height = This->ddraw_height;
5733 pMode->Format = This->ddraw_format;
5734 pMode->RefreshRate = 0;
5741 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5743 TRACE("(%p)->(%p)\n", This, hWnd);
5745 This->ddraw_window = hWnd;
5749 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5751 TRACE("(%p)->(%p)\n", This, hWnd);
5753 *hWnd = This->ddraw_window;
5758 * Stateblock related functions
5761 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 IWineD3DStateBlockImpl *object;
5764 HRESULT temp_result;
5766 TRACE("(%p)", This);
5768 if (This->isRecordingState) {
5769 return WINED3DERR_INVALIDCALL;
5772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5773 if (NULL == object ) {
5774 FIXME("(%p)Error allocating memory for stateblock\n", This);
5775 return E_OUTOFMEMORY;
5777 TRACE("(%p) created object %p\n", This, object);
5778 object->wineD3DDevice= This;
5779 /** FIXME: object->parent = parent; **/
5780 object->parent = NULL;
5781 object->blockType = WINED3DSBT_ALL;
5783 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5785 temp_result = allocate_shader_constants(object);
5786 if (WINED3D_OK != temp_result)
5789 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5790 This->updateStateBlock = object;
5791 This->isRecordingState = TRUE;
5793 TRACE("(%p) recording stateblock %p\n",This , object);
5797 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 if (!This->isRecordingState) {
5801 FIXME("(%p) not recording! returning error\n", This);
5802 *ppStateBlock = NULL;
5803 return WINED3DERR_INVALIDCALL;
5806 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5807 This->isRecordingState = FALSE;
5808 This->updateStateBlock = This->stateBlock;
5809 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5810 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5811 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5816 * Scene related functions
5818 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5819 /* At the moment we have no need for any functionality at the beginning
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 TRACE("(%p) : stub\n", This);
5826 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5828 TRACE("(%p)\n", This);
5830 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5832 checkGLcall("glFlush");
5834 TRACE("End Scene\n");
5835 if(This->renderTarget != NULL) {
5837 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5838 IUnknown *targetContainer = NULL;
5839 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5840 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5841 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5842 /** always dirtify for now. we must find a better way to see that surface have been modified
5843 (Modifications should will only occur via draw-primitive, but we do need better locking
5844 switching to render-to-texture should remove the overhead though.
5846 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5847 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5848 IWineD3DSurface_PreLoad(This->renderTarget);
5849 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5850 IUnknown_Release(targetContainer);
5853 This->sceneEnded = TRUE;
5858 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5859 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5860 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5862 IWineD3DSwapChain *swapChain = NULL;
5864 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5866 TRACE("(%p) Presenting the frame\n", This);
5868 for(i = 0 ; i < swapchains ; i ++) {
5870 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5871 TRACE("presentinng chain %d, %p\n", i, swapChain);
5872 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5873 IWineD3DSwapChain_Release(swapChain);
5879 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5880 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5884 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5885 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5886 GLbitfield glMask = 0;
5887 GLboolean old_ztest;
5888 GLfloat old_z_clear_value;
5889 GLint old_stencil_clear_value;
5890 GLfloat old_color_clear_value[4];
5892 CONST D3DRECT* curRect;
5894 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5895 Count, pRects, Flags, Z, Stencil);
5899 glEnable(GL_SCISSOR_TEST);
5900 checkGLcall("glEnable GL_SCISSOR_TEST");
5902 if (Count > 0 && pRects) {
5908 /* Only set the values up once, as they are not changing */
5909 if (Flags & D3DCLEAR_STENCIL) {
5910 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5911 glClearStencil(Stencil);
5912 checkGLcall("glClearStencil");
5913 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5914 glStencilMask(0xFFFFFFFF);
5917 if (Flags & D3DCLEAR_ZBUFFER) {
5918 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5919 glDepthMask(GL_TRUE);
5920 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5922 checkGLcall("glClearDepth");
5923 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5926 if (Flags & D3DCLEAR_TARGET) {
5927 TRACE("Clearing screen with glClear to color %lx\n", Color);
5928 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5929 glClearColor(D3DCOLOR_R(Color),
5933 checkGLcall("glClearColor");
5935 /* Clear ALL colors! */
5936 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5937 glMask = glMask | GL_COLOR_BUFFER_BIT;
5940 /* Now process each rect in turn */
5941 for (i = 0; i < Count || i == 0; i++) {
5944 /* Note gl uses lower left, width/height */
5945 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5946 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5947 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5948 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5949 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5950 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5951 checkGLcall("glScissor");
5953 glScissor(This->stateBlock->viewport.X,
5954 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5955 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5956 This->stateBlock->viewport.Width,
5957 This->stateBlock->viewport.Height);
5958 checkGLcall("glScissor");
5961 /* Clear the selected rectangle (or full screen) */
5963 checkGLcall("glClear");
5965 /* Step to the next rectangle */
5966 if (curRect) curRect = curRect + sizeof(D3DRECT);
5969 /* Restore the old values (why..?) */
5970 if (Flags & D3DCLEAR_STENCIL) {
5971 glClearStencil(old_stencil_clear_value);
5972 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5974 if (Flags & D3DCLEAR_ZBUFFER) {
5975 glDepthMask(old_ztest);
5976 glClearDepth(old_z_clear_value);
5978 if (Flags & D3DCLEAR_TARGET) {
5979 glClearColor(old_color_clear_value[0],
5980 old_color_clear_value[1],
5981 old_color_clear_value[2],
5982 old_color_clear_value[3]);
5983 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5984 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5985 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5986 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5989 glDisable(GL_SCISSOR_TEST);
5990 checkGLcall("glDisable");
5999 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6000 UINT PrimitiveCount) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6003 This->stateBlock->streamIsUP = FALSE;
6005 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6006 debug_d3dprimitivetype(PrimitiveType),
6007 StartVertex, PrimitiveCount);
6008 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6009 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6015 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6016 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6017 D3DPRIMITIVETYPE PrimitiveType,
6018 INT baseVIndex, UINT minIndex,
6019 UINT NumVertices, UINT startIndex, UINT primCount) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6023 IWineD3DIndexBuffer *pIB;
6024 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6026 pIB = This->stateBlock->pIndexData;
6027 This->stateBlock->streamIsUP = FALSE;
6029 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6030 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6031 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6033 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6034 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6040 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6041 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6046 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6047 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6048 UINT VertexStreamZeroStride) {
6049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6051 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6052 debug_d3dprimitivetype(PrimitiveType),
6053 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6055 /* release the stream source */
6056 if (This->stateBlock->streamSource[0] != NULL) {
6057 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6060 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6061 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6062 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6063 This->stateBlock->streamIsUP = TRUE;
6065 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6066 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6068 /* MSDN specifies stream zero settings must be set to NULL */
6069 This->stateBlock->streamStride[0] = 0;
6070 This->stateBlock->streamSource[0] = NULL;
6072 /*stream zero settings set to null at end, as per the msdn */
6076 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6077 UINT MinVertexIndex, UINT NumVertices,
6078 UINT PrimitiveCount, CONST void* pIndexData,
6079 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6080 UINT VertexStreamZeroStride) {
6082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6085 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6086 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6087 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6089 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6095 /* release the stream and index data */
6096 if (This->stateBlock->streamSource[0] != NULL) {
6097 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6099 if (This->stateBlock->pIndexData) {
6100 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6103 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6104 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6105 This->stateBlock->streamIsUP = TRUE;
6106 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6108 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6110 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6111 This->stateBlock->streamSource[0] = NULL;
6112 This->stateBlock->streamStride[0] = 0;
6113 This->stateBlock->pIndexData = NULL;
6118 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6120 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6123 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6124 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 HRESULT hr = WINED3D_OK;
6127 WINED3DRESOURCETYPE sourceType;
6128 WINED3DRESOURCETYPE destinationType;
6131 /* TODO: think about moving the code into IWineD3DBaseTexture */
6133 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6135 /* verify that the source and destination textures aren't NULL */
6136 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6137 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6138 This, pSourceTexture, pDestinationTexture);
6139 hr = WINED3DERR_INVALIDCALL;
6142 if (pSourceTexture == pDestinationTexture) {
6143 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6144 This, pSourceTexture, pDestinationTexture);
6145 hr = WINED3DERR_INVALIDCALL;
6147 /* Verify that the source and destination textures are the same type */
6148 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6149 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6151 if (sourceType != destinationType) {
6152 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6154 hr = WINED3DERR_INVALIDCALL;
6157 /* check that both textures have the identical numbers of levels */
6158 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6159 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6160 hr = WINED3DERR_INVALIDCALL;
6163 if (WINED3D_OK == hr) {
6165 /* Make sure that the destination texture is loaded */
6166 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6168 /* Update every surface level of the texture */
6169 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6171 switch (sourceType) {
6172 case WINED3DRTYPE_TEXTURE:
6174 IWineD3DSurface *srcSurface;
6175 IWineD3DSurface *destSurface;
6177 for (i = 0 ; i < levels ; ++i) {
6178 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6179 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6180 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6181 IWineD3DSurface_Release(srcSurface);
6182 IWineD3DSurface_Release(destSurface);
6183 if (WINED3D_OK != hr) {
6184 WARN("(%p) : Call to update surface failed\n", This);
6190 case WINED3DRTYPE_CUBETEXTURE:
6192 IWineD3DSurface *srcSurface;
6193 IWineD3DSurface *destSurface;
6194 WINED3DCUBEMAP_FACES faceType;
6196 for (i = 0 ; i < levels ; ++i) {
6197 /* Update each cube face */
6198 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6199 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6200 if (WINED3D_OK != hr) {
6201 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6203 TRACE("Got srcSurface %p\n", srcSurface);
6205 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6206 if (WINED3D_OK != hr) {
6207 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6209 TRACE("Got desrSurface %p\n", destSurface);
6211 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6212 IWineD3DSurface_Release(srcSurface);
6213 IWineD3DSurface_Release(destSurface);
6214 if (WINED3D_OK != hr) {
6215 WARN("(%p) : Call to update surface failed\n", This);
6222 #if 0 /* TODO: Add support for volume textures */
6223 case WINED3DRTYPE_VOLUMETEXTURE:
6225 IWineD3DVolume srcVolume = NULL;
6226 IWineD3DSurface destVolume = NULL;
6228 for (i = 0 ; i < levels ; ++i) {
6229 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6230 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6231 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6232 IWineD3DVolume_Release(srcSurface);
6233 IWineD3DVolume_Release(destSurface);
6234 if (WINED3D_OK != hr) {
6235 WARN("(%p) : Call to update volume failed\n", This);
6243 FIXME("(%p) : Unsupported source and destination type\n", This);
6244 hr = WINED3DERR_INVALIDCALL;
6251 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6252 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6253 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6256 TRACE("(%p) : stub\n", This);
6259 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6261 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6262 * NOTE It may be best to move the code into surface to occomplish this
6263 ****************************************/
6265 WINED3DSURFACE_DESC surfaceDesc;
6266 unsigned int surfaceWidth, surfaceHeight;
6267 glDescriptor *targetGlDescription = NULL;
6268 glDescriptor *surfaceGlDescription = NULL;
6269 IWineD3DSwapChainImpl *container = NULL;
6271 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6272 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6273 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6275 surfaceDesc.Width = &surfaceWidth;
6276 surfaceDesc.Height = &surfaceHeight;
6277 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6278 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6280 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6281 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6283 /* TODO: opengl Context switching for swapchains etc... */
6284 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6285 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6286 glReadBuffer(GL_BACK);
6287 vcheckGLcall("glReadBuffer(GL_BACK)");
6288 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6289 glReadBuffer(GL_FRONT);
6290 vcheckGLcall("glReadBuffer(GL_FRONT)");
6291 } else if (pRenderTarget == This->depthStencilBuffer) {
6292 FIXME("Reading of depthstencil not yet supported\n");
6295 glReadPixels(surfaceGlDescription->target,
6296 surfaceGlDescription->level,
6299 surfaceGlDescription->glFormat,
6300 surfaceGlDescription->glType,
6301 (void *)IWineD3DSurface_GetData(pSurface));
6302 vcheckGLcall("glReadPixels(...)");
6303 if(NULL != container ){
6304 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6307 IWineD3DBaseTexture *container;
6308 GLenum textureDimensions = GL_TEXTURE_2D;
6310 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6311 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6312 IWineD3DBaseTexture_Release(container);
6314 /* TODO: 2D -> Cube surface coppies etc.. */
6315 if (surfaceGlDescription->target != textureDimensions) {
6316 FIXME("(%p) : Texture dimension mismatch\n", This);
6318 glEnable(textureDimensions);
6319 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6320 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6321 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6322 vcheckGLcall("glBindTexture");
6323 glGetTexImage(surfaceGlDescription->target,
6324 surfaceGlDescription->level,
6325 surfaceGlDescription->glFormat,
6326 surfaceGlDescription->glType,
6327 (void *)IWineD3DSurface_GetData(pSurface));
6328 glDisable(textureDimensions);
6329 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6336 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6337 IWineD3DSwapChain *swapChain;
6339 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6340 if(hr == WINED3D_OK) {
6341 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6342 IWineD3DSwapChain_Release(swapChain);
6347 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6349 /* return a sensible default */
6351 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6352 FIXME("(%p) : stub\n", This);
6356 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6359 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6360 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6361 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6362 return WINED3DERR_INVALIDCALL;
6364 for (j = 0; j < 256; ++j) {
6365 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6366 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6367 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6368 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6370 TRACE("(%p) : returning\n", This);
6374 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6377 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6378 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6379 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6380 return WINED3DERR_INVALIDCALL;
6382 for (j = 0; j < 256; ++j) {
6383 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6384 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6385 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6386 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6388 TRACE("(%p) : returning\n", This);
6392 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6394 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6395 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6396 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6397 return WINED3DERR_INVALIDCALL;
6399 /*TODO: stateblocks */
6400 This->currentPalette = PaletteNumber;
6401 TRACE("(%p) : returning\n", This);
6405 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6407 if (PaletteNumber == NULL) {
6408 WARN("(%p) : returning Invalid Call\n", This);
6409 return WINED3DERR_INVALIDCALL;
6411 /*TODO: stateblocks */
6412 *PaletteNumber = This->currentPalette;
6413 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6417 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6419 static BOOL showFixmes = TRUE;
6421 FIXME("(%p) : stub\n", This);
6425 This->softwareVertexProcessing = bSoftware;
6430 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 static BOOL showFixmes = TRUE;
6434 FIXME("(%p) : stub\n", This);
6437 return This->softwareVertexProcessing;
6441 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6443 IWineD3DSwapChain *swapChain;
6446 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6448 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6449 if(hr == WINED3D_OK){
6450 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6451 IWineD3DSwapChain_Release(swapChain);
6453 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6459 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6461 static BOOL showfixmes = TRUE;
6462 if(nSegments != 0.0f) {
6464 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6471 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 static BOOL showfixmes = TRUE;
6475 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6481 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6483 /** TODO: remove casts to IWineD3DSurfaceImpl
6484 * NOTE: move code to surface to accomplish this
6485 ****************************************/
6486 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6487 int srcWidth, srcHeight;
6488 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6489 WINED3DFORMAT destFormat, srcFormat;
6491 int destLeft, destTop;
6492 WINED3DPOOL srcPool, destPool;
6494 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6495 glDescriptor *glDescription = NULL;
6496 GLenum textureDimensions = GL_TEXTURE_2D;
6497 IWineD3DBaseTexture *baseTexture;
6499 WINED3DSURFACE_DESC winedesc;
6501 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6502 memset(&winedesc, 0, sizeof(winedesc));
6503 winedesc.Width = &srcSurfaceWidth;
6504 winedesc.Height = &srcSurfaceHeight;
6505 winedesc.Pool = &srcPool;
6506 winedesc.Format = &srcFormat;
6508 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6510 winedesc.Width = &destSurfaceWidth;
6511 winedesc.Height = &destSurfaceHeight;
6512 winedesc.Pool = &destPool;
6513 winedesc.Format = &destFormat;
6514 winedesc.Size = &destSize;
6516 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6518 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6519 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6520 return WINED3DERR_INVALIDCALL;
6523 if (destFormat == WINED3DFMT_UNKNOWN) {
6524 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6525 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6527 /* Get the update surface description */
6528 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6531 /* Make sure the surface is loaded and up to date */
6532 IWineD3DSurface_PreLoad(pDestinationSurface);
6534 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6538 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6539 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6540 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6541 destLeft = pDestPoint ? pDestPoint->x : 0;
6542 destTop = pDestPoint ? pDestPoint->y : 0;
6545 /* This function doesn't support compressed textures
6546 the pitch is just bytesPerPixel * width */
6547 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6548 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6549 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6550 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6552 /* TODO DXT formats */
6554 if(pSourceRect != NULL && pSourceRect->top != 0){
6555 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6557 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6559 ,glDescription->level
6564 ,glDescription->glFormat
6565 ,glDescription->glType
6566 ,IWineD3DSurface_GetData(pSourceSurface)
6570 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6572 /* need to lock the surface to get the data */
6573 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6576 /* TODO: Cube and volume support */
6578 /* not a whole row so we have to do it a line at a time */
6581 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6582 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6584 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6586 glTexSubImage2D(glDescription->target
6587 ,glDescription->level
6592 ,glDescription->glFormat
6593 ,glDescription->glType
6594 ,data /* could be quicker using */
6599 } else { /* Full width, so just write out the whole texture */
6601 if (WINED3DFMT_DXT1 == destFormat ||
6602 WINED3DFMT_DXT2 == destFormat ||
6603 WINED3DFMT_DXT3 == destFormat ||
6604 WINED3DFMT_DXT4 == destFormat ||
6605 WINED3DFMT_DXT5 == destFormat) {
6606 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6607 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6608 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6609 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6610 } if (destFormat != srcFormat) {
6611 FIXME("Updating mixed format compressed texture is not curretly support\n");
6613 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6614 glDescription->level,
6615 glDescription->glFormatInternal,
6620 IWineD3DSurface_GetData(pSourceSurface));
6623 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6628 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6630 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6631 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6632 data returned by GetData non-power2 width/height with hardware non-power2
6633 pow2Width/height are set to surface width height, repacking isn't needed so it
6634 doesn't matter which function gets called. */
6635 glTexSubImage2D(glDescription->target
6636 ,glDescription->level
6641 ,glDescription->glFormat
6642 ,glDescription->glType
6643 ,IWineD3DSurface_GetData(pSourceSurface)
6647 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6648 glTexSubImage2D(glDescription->target
6649 ,glDescription->level
6652 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6653 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6654 ,glDescription->glFormat
6655 ,glDescription->glType
6656 ,IWineD3DSurface_GetData(pSourceSurface)
6662 checkGLcall("glTexSubImage2D");
6664 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6665 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6666 * surface bigger than it needs to be hmm.. */
6667 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6668 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6669 IWineD3DBaseTexture_Release(baseTexture);
6672 glDisable(textureDimensions); /* This needs to be managed better.... */
6678 /* Used by DirectX 8 */
6679 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6680 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6681 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6684 HRESULT hr = WINED3D_OK;
6685 WINED3DFORMAT srcFormat, destFormat;
6686 UINT srcWidth, destWidth;
6687 UINT srcHeight, destHeight;
6689 WINED3DSURFACE_DESC winedesc;
6691 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6692 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6695 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6696 memset(&winedesc, 0, sizeof(winedesc));
6698 winedesc.Format = &srcFormat;
6699 winedesc.Width = &srcWidth;
6700 winedesc.Height = &srcHeight;
6701 winedesc.Size = &srcSize;
6702 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6704 winedesc.Format = &destFormat;
6705 winedesc.Width = &destWidth;
6706 winedesc.Height = &destHeight;
6707 winedesc.Size = NULL;
6708 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6710 /* Check that the source and destination formats match */
6711 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6712 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6713 return WINED3DERR_INVALIDCALL;
6714 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6715 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6716 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6717 destFormat = srcFormat;
6720 /* Quick if complete copy ... */
6721 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6723 if (srcWidth == destWidth && srcHeight == destHeight) {
6724 WINED3DLOCKED_RECT lrSrc;
6725 WINED3DLOCKED_RECT lrDst;
6726 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6727 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6728 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6730 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6732 IWineD3DSurface_UnlockRect(pSourceSurface);
6733 IWineD3DSurface_UnlockRect(pDestinationSurface);
6734 TRACE("Unlocked src and dst\n");
6738 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6739 hr = WINED3DERR_INVALIDCALL;
6744 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6746 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6749 /* Copy rect by rect */
6750 for (i = 0; i < cRects; ++i) {
6751 CONST RECT* r = &pSourceRectsArray[i];
6752 CONST POINT* p = &pDestPointsArray[i];
6755 WINED3DLOCKED_RECT lrSrc;
6756 WINED3DLOCKED_RECT lrDst;
6759 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6760 if (srcFormat == WINED3DFMT_DXT1) {
6761 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6763 copyperline = ((r->right - r->left) * bytesPerPixel);
6766 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6767 dest_rect.left = p->x;
6768 dest_rect.top = p->y;
6769 dest_rect.right = p->x + (r->right - r->left);
6770 dest_rect.bottom= p->y + (r->bottom - r->top);
6771 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6772 TRACE("Locked src and dst\n");
6774 /* Find where to start */
6775 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6776 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6778 IWineD3DSurface_UnlockRect(pSourceSurface);
6779 IWineD3DSurface_UnlockRect(pDestinationSurface);
6780 TRACE("Unlocked src and dst\n");
6783 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6784 hr = WINED3DERR_INVALIDCALL;
6791 /* Implementation details at http://developer.nvidia.com/attach/6494
6793 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6794 hmm.. no longer supported use
6795 OpenGL evaluators or tessellate surfaces within your application.
6798 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6799 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6801 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6802 FIXME("(%p) : Stub\n", This);
6807 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6808 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6810 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6811 FIXME("(%p) : Stub\n", This);
6815 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6817 TRACE("(%p) Handle(%d)\n", This, Handle);
6818 FIXME("(%p) : Stub\n", This);
6822 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6824 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6826 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6828 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6829 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6830 return WINED3DERR_INVALIDCALL;
6833 /* Just forward this to the DirectDraw blitting engine */
6834 memset(&BltFx, 0, sizeof(BltFx));
6835 BltFx.dwSize = sizeof(BltFx);
6836 BltFx.u5.dwFillColor = color;
6837 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6840 /* rendertarget and deptth stencil functions */
6841 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6844 /* FIXME: Implelent RenderTargetIndex >0 */
6845 if(RenderTargetIndex > 0)
6846 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6848 *ppRenderTarget = This->renderTarget;
6849 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6850 /* Note inc ref on returned surface */
6851 if(*ppRenderTarget != NULL)
6852 IWineD3DSurface_AddRef(*ppRenderTarget);
6856 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6858 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6859 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6860 IWineD3DSwapChainImpl *Swapchain;
6863 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6865 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6866 if(hr != WINED3D_OK) {
6867 ERR("Can't get the swapchain\n");
6871 /* Make sure to release the swapchain */
6872 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6874 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6875 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6876 return WINED3DERR_INVALIDCALL;
6878 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6879 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6880 return WINED3DERR_INVALIDCALL;
6883 if(Swapchain->frontBuffer != Front) {
6884 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6886 if(Swapchain->frontBuffer)
6887 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6888 Swapchain->frontBuffer = Front;
6890 if(Swapchain->frontBuffer) {
6891 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6895 if(Back && !Swapchain->backBuffer) {
6896 /* We need memory for the back buffer array - only one back buffer this way */
6897 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6898 if(!Swapchain->backBuffer) {
6899 ERR("Out of memory\n");
6900 return E_OUTOFMEMORY;
6904 if(Swapchain->backBuffer[0] != Back) {
6905 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6907 if(!Swapchain->backBuffer[0]) {
6908 /* GL was told to draw to the front buffer at creation,
6911 glDrawBuffer(GL_BACK);
6912 checkGLcall("glDrawBuffer(GL_BACK)");
6913 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6914 Swapchain->presentParms.BackBufferCount = 1;
6916 /* That makes problems - disable for now */
6917 /* glDrawBuffer(GL_FRONT); */
6918 checkGLcall("glDrawBuffer(GL_FRONT)");
6919 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6920 Swapchain->presentParms.BackBufferCount = 0;
6924 if(Swapchain->backBuffer[0])
6925 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6926 Swapchain->backBuffer[0] = Back;
6928 if(Swapchain->backBuffer[0]) {
6929 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6931 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6939 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6941 *ppZStencilSurface = This->depthStencilBuffer;
6942 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6944 if(*ppZStencilSurface != NULL) {
6945 /* Note inc ref on returned surface */
6946 IWineD3DSurface_AddRef(*ppZStencilSurface);
6951 /* internal static helper functions */
6952 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6953 IWineD3DSurface *RenderSurface);
6955 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6957 HRESULT hr = WINED3D_OK;
6958 WINED3DVIEWPORT viewport;
6960 TRACE("(%p) Swapping rendertarget\n",This);
6961 if (RenderTargetIndex > 0) {
6962 FIXME("(%p) Render targets other than the first are not supported\n",This);
6963 RenderTargetIndex = 0;
6966 /* MSDN says that null disables the render target
6967 but a device must always be associated with a render target
6968 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6970 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6973 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6974 FIXME("Trying to set render target 0 to NULL\n");
6975 return WINED3DERR_INVALIDCALL;
6977 /* TODO: replace Impl* usage with interface usage */
6978 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6979 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);
6980 return WINED3DERR_INVALIDCALL;
6982 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
6983 * builds, but I think wine counts as a 'debug' build for now.
6984 ******************************/
6985 /* If we are trying to set what we already have, don't bother */
6986 if (pRenderTarget == This->renderTarget) {
6987 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6989 /* Otherwise, set the render target up */
6991 if (FALSE == This->sceneEnded) {
6992 IWineD3DDevice_EndScene(iface);
6994 TRACE("clearing renderer\n");
6995 /* IWineD3DDeviceImpl_CleanRender(iface); */
6996 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6997 depending on the renter target implementation being used.
6998 A shared context implementation will share all buffers between all rendertargets (including swapchains),
6999 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7000 stencil buffer and incure an extra memory overhead */
7001 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7004 if (SUCCEEDED(hr)) {
7005 /* Finally, reset the viewport as the MSDN states. */
7006 /* TODO: Replace impl usage */
7007 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7008 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7011 viewport.MaxZ = 1.0f;
7012 viewport.MinZ = 0.0f;
7013 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7015 FIXME("Unknown error setting the render target\n");
7017 This->sceneEnded = FALSE;
7021 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7023 HRESULT hr = WINED3D_OK;
7024 IWineD3DSurface *tmp;
7026 TRACE("(%p) Swapping z-buffer\n",This);
7028 if (pNewZStencil == This->stencilBufferTarget) {
7029 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7031 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7032 * depending on the renter target implementation being used.
7033 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7034 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7035 * stencil buffer and incure an extra memory overhead
7036 ******************************************************/
7039 tmp = This->stencilBufferTarget;
7040 This->stencilBufferTarget = pNewZStencil;
7041 /* should we be calling the parent or the wined3d surface? */
7042 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7043 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7045 /** TODO: glEnable/glDisable on depth/stencil depending on
7046 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7047 **********************************************************/
7054 #ifdef GL_VERSION_1_3
7055 /* Internal functions not in DirectX */
7056 /** TODO: move this off to the opengl context manager
7057 *(the swapchain doesn't need to know anything about offscreen rendering!)
7058 ****************************************************/
7060 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7064 TRACE("(%p), %p\n", This, swapchain);
7066 if (swapchain->win != swapchain->drawable) {
7067 /* Set everything back the way it ws */
7068 swapchain->render_ctx = swapchain->glCtx;
7069 swapchain->drawable = swapchain->win;
7074 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7075 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7079 unsigned int height;
7080 WINED3DFORMAT format;
7081 WINED3DSURFACE_DESC surfaceDesc;
7082 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7083 surfaceDesc.Width = &width;
7084 surfaceDesc.Height = &height;
7085 surfaceDesc.Format = &format;
7086 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7088 /* I need a get width/height function (and should do something with the format) */
7089 for (i = 0; i < CONTEXT_CACHE; ++i) {
7090 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7091 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7092 the pSurface can be set to 0 allowing it to be reused from cache **/
7093 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7094 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7095 *context = &This->contextCache[i];
7098 if (This->contextCache[i].Width == 0) {
7099 This->contextCache[i].pSurface = pSurface;
7100 This->contextCache[i].Width = width;
7101 This->contextCache[i].Height = height;
7102 *context = &This->contextCache[i];
7106 if (i == CONTEXT_CACHE) {
7107 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7108 glContext *dropContext = 0;
7109 for (i = 0; i < CONTEXT_CACHE; i++) {
7110 if (This->contextCache[i].usedcount < minUsage) {
7111 dropContext = &This->contextCache[i];
7112 minUsage = This->contextCache[i].usedcount;
7115 /* clean up the context (this doesn't work for ATI at the moment */
7117 glXDestroyContext(swapchain->display, dropContext->context);
7118 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7121 dropContext->Width = 0;
7122 dropContext->pSurface = pSurface;
7123 *context = dropContext;
7125 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7126 for (i = 0; i < CONTEXT_CACHE; i++) {
7127 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7131 if (*context != NULL)
7134 return E_OUTOFMEMORY;
7138 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7139 * the functionality needs splitting up so that we don't do more than we should do.
7140 * this only seems to impact performance a little.
7141 ******************************/
7142 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7143 IWineD3DSurface *RenderSurface) {
7144 HRESULT ret = WINED3DERR_INVALIDCALL;
7146 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7149 * Currently only active for GLX >= 1.3
7150 * for others versions we'll have to use GLXPixmaps
7152 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7153 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7154 * so only check OpenGL version
7155 * ..........................
7156 * I don't believe that it is a problem with NVidia headers,
7157 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7158 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7160 * Your application will report GLX version 1.2 on glXQueryVersion.
7161 * However, it is safe to call the GLX 1.3 functions as described below.
7163 #if defined(GL_VERSION_1_3)
7165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7166 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7167 IWineD3DSurface *tmp;
7168 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7169 GLXFBConfig* cfgs = NULL;
7173 IWineD3DSwapChain *currentSwapchain;
7174 IWineD3DSwapChainImpl *swapchain;
7175 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7176 * but switch them off if the StencilSurface is set to NULL
7177 ** *********************************************************/
7178 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7179 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7182 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7183 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7186 #define PUSH1(att) attribs[nAttribs++] = (att);
7187 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7189 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7191 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7192 IWineD3DSwapChainImpl *impSwapChain;
7193 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7194 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7195 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7200 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7201 PUSH2(GLX_X_RENDERABLE, TRUE);
7202 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7203 TRACE("calling makeglcfg\n");
7204 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7207 TRACE("calling chooseFGConfig\n");
7208 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7211 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7212 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7213 why we failed and only show this message once! */
7214 MESSAGE("Failed to find exact match, finding alternative but you may suffer performance issues, try changing xfree's depth to match the requested depth\n"); /**/
7216 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7217 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7218 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7219 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7220 TRACE("calling makeglcfg\n");
7221 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7223 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7230 for (i = 0; i < nCfgs; ++i) {
7231 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7232 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7233 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7236 if (NULL != This->renderTarget) {
7238 vcheckGLcall("glFlush");
7239 /** This is only useful if the old render target was a swapchain,
7240 * we need to supercede this with a function that displays
7241 * the current buffer on the screen. This is easy to do in glx1.3 but
7242 * we need to do copy-write pixels in glx 1.2.
7243 ************************************************/
7244 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7246 printf("Hit Enter to get next frame ...\n");
7252 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain) != WINED3D_OK) {
7253 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7254 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
7258 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7259 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7260 **********************************************************************/
7261 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7262 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7263 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7264 TRACE("making swapchain active\n");
7265 if (RenderSurface != This->renderTarget) {
7266 BOOL backbuf = FALSE;
7269 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7270 if(RenderSurface == swapchain->backBuffer[i]) {
7278 /* This could be flagged so that some operations work directly with the front buffer */
7279 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7281 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7283 TRACE("Error in setting current context: context %p drawable %ld !\n",
7284 impSwapChain->glCtx, impSwapChain->win);
7287 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7289 checkGLcall("glXMakeContextCurrent");
7291 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7293 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7295 /** ********************************************************************
7296 * This is a quickly hacked out implementation of offscreen textures.
7297 * It will work in most cases but there may be problems if the client
7298 * modifies the texture directly, or expects the contents of the rendertarget
7301 * There are some real speed vs compatibility issues here:
7302 * we should really use a new context for every texture, but that eats ram.
7303 * we should also be restoring the texture to the pbuffer but that eats CPU
7304 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7305 * but if this means reusing the display backbuffer then we need to make sure that
7306 * states are correctly preserved.
7307 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7308 * and gain a good performance increase at the cost of compatibility.
7309 * I would suggest that, when this is the case, a user configurable flag be made
7310 * available, allowing the user to choose the best emulated experience for them.
7311 *********************************************************************/
7313 XVisualInfo *visinfo;
7314 glContext *newContext;
7316 /* Here were using a shared context model */
7317 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7318 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7321 /* If the context doesn't exist then create a new one */
7322 /* TODO: This should really be part of findGlContext */
7323 if (NULL == newContext->context) {
7325 TRACE("making new buffer\n");
7327 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7328 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7331 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7333 /** ****************************************
7334 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7336 * In future releases, we may provide the calls glXCreateNewContext,
7337 * glXQueryDrawable and glXMakeContextCurrent.
7338 * so until then we have to use glXGetVisualFromFBConfig &co..
7339 ********************************************/
7342 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7344 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7346 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7350 if (NULL == newContext || NULL == newContext->context) {
7351 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7353 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7354 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7355 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7358 /* Clean up the old context */
7359 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7360 /* Set the current context of the swapchain to the new context */
7361 impSwapChain->drawable = newContext->drawable;
7362 impSwapChain->render_ctx = newContext->context;
7366 /* Disable recording, and apply the stateblock to the new context
7367 * FIXME: This is a bit of a hack, each context should know it's own state,
7368 * the directX current directX state should then be applied to the context */
7369 oldUpdateStateBlock = This->updateStateBlock;
7370 oldRecording= This->isRecordingState;
7371 This->isRecordingState = FALSE;
7372 This->updateStateBlock = This->stateBlock;
7373 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7375 /* clean up the current rendertargets swapchain (if it belonged to one) */
7376 if (currentSwapchain != NULL) {
7377 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7380 /* Were done with the opengl context management, setup the rendertargets */
7382 tmp = This->renderTarget;
7383 This->renderTarget = RenderSurface;
7384 IWineD3DSurface_AddRef(This->renderTarget);
7385 IWineD3DSurface_Release(tmp);
7390 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7391 /* Check that the container is not a swapchain member */
7393 IWineD3DSwapChain *tmpSwapChain;
7394 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7395 This->renderUpsideDown = TRUE;
7397 This->renderUpsideDown = FALSE;
7398 IWineD3DSwapChain_Release(tmpSwapChain);
7400 /* Force updating the cull mode */
7401 TRACE("setting render state\n");
7402 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7403 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7405 /* Force updating projection matrix */
7406 This->last_was_rhw = FALSE;
7407 This->proj_valid = FALSE;
7410 /* Restore recording state */
7411 This->isRecordingState = oldRecording;
7412 This->updateStateBlock = oldUpdateStateBlock;
7419 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7420 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7425 if ( NULL != impSwapChain) {
7426 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7434 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7435 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7437 /* TODO: the use of Impl is deprecated. */
7438 /* some basic validation checks */
7439 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7441 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7443 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7444 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7445 return WINED3DERR_INVALIDCALL;
7447 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7448 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7449 return WINED3DERR_INVALIDCALL;
7451 /* TODO: make the cursor 'real' */
7453 This->xHotSpot = XHotSpot;
7454 This->yHotSpot = YHotSpot;
7459 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7461 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7463 This->xScreenSpace = XScreenSpace;
7464 This->yScreenSpace = YScreenSpace;
7470 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7472 TRACE("(%p) : visible(%d)\n", This, bShow);
7474 This->bCursorVisible = bShow;
7479 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7481 TRACE("(%p) : state (%lu)\n", This, This->state);
7482 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7483 switch (This->state) {
7486 case WINED3DERR_DEVICELOST:
7488 ResourceList *resourceList = This->resources;
7489 while (NULL != resourceList) {
7490 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7491 return WINED3DERR_DEVICENOTRESET;
7492 resourceList = resourceList->next;
7494 return WINED3DERR_DEVICELOST;
7496 case WINED3DERR_DRIVERINTERNALERROR:
7497 return WINED3DERR_DRIVERINTERNALERROR;
7501 return WINED3DERR_DRIVERINTERNALERROR;
7505 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7507 /** FIXME: Resource tracking needs to be done,
7508 * The closes we can do to this is set the priorities of all managed textures low
7509 * and then reset them.
7510 ***********************************************************/
7511 FIXME("(%p) : stub\n", This);
7515 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7517 /** FIXME: Resource trascking needs to be done.
7518 * in effect this pulls all non only default
7519 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7520 * and should clear down the context and set it up according to pPresentationParameters
7521 ***********************************************************/
7522 FIXME("(%p) : stub\n", This);
7526 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7528 /** FIXME: always true at the moment **/
7529 if(bEnableDialogs == FALSE) {
7530 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7536 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7538 TRACE("(%p) : pParameters %p\n", This, pParameters);
7540 *pParameters = This->createParms;
7544 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7545 IWineD3DSwapChain *swapchain;
7546 HRESULT hrc = WINED3D_OK;
7548 TRACE("Relaying to swapchain\n");
7550 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7551 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7552 IWineD3DSwapChain_Release(swapchain);
7557 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7558 IWineD3DSwapChain *swapchain;
7559 HRESULT hrc = WINED3D_OK;
7561 TRACE("Relaying to swapchain\n");
7563 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7564 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7565 IWineD3DSwapChain_Release(swapchain);
7571 /** ********************************************************
7572 * Notification functions
7573 ** ********************************************************/
7574 /** This function must be called in the release of a resource when ref == 0,
7575 * the contents of resource must still be correct,
7576 * any handels to other resource held by the caller must be closed
7577 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7578 *****************************************************/
7579 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7581 ResourceList* resourceList;
7583 TRACE("(%p) : resource %p\n", This, resource);
7585 EnterCriticalSection(&resourceStoreCriticalSection);
7587 /* add a new texture to the frot of the linked list */
7588 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7589 resourceList->resource = resource;
7591 /* Get the old head */
7592 resourceList->next = This->resources;
7594 This->resources = resourceList;
7595 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7598 LeaveCriticalSection(&resourceStoreCriticalSection);
7603 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7605 ResourceList* resourceList = NULL;
7606 ResourceList* previousResourceList = NULL;
7608 TRACE("(%p) : resource %p\n", This, resource);
7611 EnterCriticalSection(&resourceStoreCriticalSection);
7613 resourceList = This->resources;
7615 while (resourceList != NULL) {
7616 if(resourceList->resource == resource) break;
7617 previousResourceList = resourceList;
7618 resourceList = resourceList->next;
7621 if (resourceList == NULL) {
7622 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7624 LeaveCriticalSection(&resourceStoreCriticalSection);
7628 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7630 /* make sure we don't leave a hole in the list */
7631 if (previousResourceList != NULL) {
7632 previousResourceList->next = resourceList->next;
7634 This->resources = resourceList->next;
7638 LeaveCriticalSection(&resourceStoreCriticalSection);
7644 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7648 TRACE("(%p) : resource %p\n", This, resource);
7649 switch(IWineD3DResource_GetType(resource)){
7650 case WINED3DRTYPE_SURFACE:
7651 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7653 case WINED3DRTYPE_TEXTURE:
7654 case WINED3DRTYPE_CUBETEXTURE:
7655 case WINED3DRTYPE_VOLUMETEXTURE:
7656 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7657 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7658 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7659 This->stateBlock->textures[counter] = NULL;
7661 if (This->updateStateBlock != This->stateBlock ){
7662 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7663 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7664 This->updateStateBlock->textures[counter] = NULL;
7669 case WINED3DRTYPE_VOLUME:
7670 /* TODO: nothing really? */
7672 case WINED3DRTYPE_VERTEXBUFFER:
7673 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7676 TRACE("Cleaning up stream pointers\n");
7678 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7679 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7680 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7682 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7683 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7684 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7685 This->updateStateBlock->streamSource[streamNumber] = 0;
7686 /* Set changed flag? */
7689 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) */
7690 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7691 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7692 This->stateBlock->streamSource[streamNumber] = 0;
7695 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7696 else { /* This shouldn't happen */
7697 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7704 case WINED3DRTYPE_INDEXBUFFER:
7705 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7706 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7707 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7708 This->updateStateBlock->pIndexData = NULL;
7711 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7712 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7713 This->stateBlock->pIndexData = NULL;
7719 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7724 /* Remove the resoruce from the resourceStore */
7725 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7727 TRACE("Resource released\n");
7731 /**********************************************************
7732 * IWineD3DDevice VTbl follows
7733 **********************************************************/
7735 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7737 /*** IUnknown methods ***/
7738 IWineD3DDeviceImpl_QueryInterface,
7739 IWineD3DDeviceImpl_AddRef,
7740 IWineD3DDeviceImpl_Release,
7741 /*** IWineD3DDevice methods ***/
7742 IWineD3DDeviceImpl_GetParent,
7743 /*** Creation methods**/
7744 IWineD3DDeviceImpl_CreateVertexBuffer,
7745 IWineD3DDeviceImpl_CreateIndexBuffer,
7746 IWineD3DDeviceImpl_CreateStateBlock,
7747 IWineD3DDeviceImpl_CreateSurface,
7748 IWineD3DDeviceImpl_CreateTexture,
7749 IWineD3DDeviceImpl_CreateVolumeTexture,
7750 IWineD3DDeviceImpl_CreateVolume,
7751 IWineD3DDeviceImpl_CreateCubeTexture,
7752 IWineD3DDeviceImpl_CreateQuery,
7753 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7754 IWineD3DDeviceImpl_CreateVertexDeclaration,
7755 IWineD3DDeviceImpl_CreateVertexShader,
7756 IWineD3DDeviceImpl_CreatePixelShader,
7757 IWineD3DDeviceImpl_CreatePalette,
7758 /*** Odd functions **/
7759 IWineD3DDeviceImpl_Init3D,
7760 IWineD3DDeviceImpl_Uninit3D,
7761 IWineD3DDeviceImpl_EnumDisplayModes,
7762 IWineD3DDeviceImpl_EvictManagedResources,
7763 IWineD3DDeviceImpl_GetAvailableTextureMem,
7764 IWineD3DDeviceImpl_GetBackBuffer,
7765 IWineD3DDeviceImpl_GetCreationParameters,
7766 IWineD3DDeviceImpl_GetDeviceCaps,
7767 IWineD3DDeviceImpl_GetDirect3D,
7768 IWineD3DDeviceImpl_GetDisplayMode,
7769 IWineD3DDeviceImpl_SetDisplayMode,
7770 IWineD3DDeviceImpl_GetHWND,
7771 IWineD3DDeviceImpl_SetHWND,
7772 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7773 IWineD3DDeviceImpl_GetRasterStatus,
7774 IWineD3DDeviceImpl_GetSwapChain,
7775 IWineD3DDeviceImpl_Reset,
7776 IWineD3DDeviceImpl_SetDialogBoxMode,
7777 IWineD3DDeviceImpl_SetCursorProperties,
7778 IWineD3DDeviceImpl_SetCursorPosition,
7779 IWineD3DDeviceImpl_ShowCursor,
7780 IWineD3DDeviceImpl_TestCooperativeLevel,
7781 /*** Getters and setters **/
7782 IWineD3DDeviceImpl_SetClipPlane,
7783 IWineD3DDeviceImpl_GetClipPlane,
7784 IWineD3DDeviceImpl_SetClipStatus,
7785 IWineD3DDeviceImpl_GetClipStatus,
7786 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7787 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7788 IWineD3DDeviceImpl_SetDepthStencilSurface,
7789 IWineD3DDeviceImpl_GetDepthStencilSurface,
7790 IWineD3DDeviceImpl_SetFVF,
7791 IWineD3DDeviceImpl_GetFVF,
7792 IWineD3DDeviceImpl_SetGammaRamp,
7793 IWineD3DDeviceImpl_GetGammaRamp,
7794 IWineD3DDeviceImpl_SetIndices,
7795 IWineD3DDeviceImpl_GetIndices,
7796 IWineD3DDeviceImpl_SetLight,
7797 IWineD3DDeviceImpl_GetLight,
7798 IWineD3DDeviceImpl_SetLightEnable,
7799 IWineD3DDeviceImpl_GetLightEnable,
7800 IWineD3DDeviceImpl_SetMaterial,
7801 IWineD3DDeviceImpl_GetMaterial,
7802 IWineD3DDeviceImpl_SetNPatchMode,
7803 IWineD3DDeviceImpl_GetNPatchMode,
7804 IWineD3DDeviceImpl_SetPaletteEntries,
7805 IWineD3DDeviceImpl_GetPaletteEntries,
7806 IWineD3DDeviceImpl_SetPixelShader,
7807 IWineD3DDeviceImpl_GetPixelShader,
7808 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7809 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7810 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7811 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7812 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7813 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7814 IWineD3DDeviceImpl_SetRenderState,
7815 IWineD3DDeviceImpl_GetRenderState,
7816 IWineD3DDeviceImpl_SetRenderTarget,
7817 IWineD3DDeviceImpl_GetRenderTarget,
7818 IWineD3DDeviceImpl_SetFrontBackBuffers,
7819 IWineD3DDeviceImpl_SetSamplerState,
7820 IWineD3DDeviceImpl_GetSamplerState,
7821 IWineD3DDeviceImpl_SetScissorRect,
7822 IWineD3DDeviceImpl_GetScissorRect,
7823 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7824 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7825 IWineD3DDeviceImpl_SetStreamSource,
7826 IWineD3DDeviceImpl_GetStreamSource,
7827 IWineD3DDeviceImpl_SetStreamSourceFreq,
7828 IWineD3DDeviceImpl_GetStreamSourceFreq,
7829 IWineD3DDeviceImpl_SetTexture,
7830 IWineD3DDeviceImpl_GetTexture,
7831 IWineD3DDeviceImpl_SetTextureStageState,
7832 IWineD3DDeviceImpl_GetTextureStageState,
7833 IWineD3DDeviceImpl_SetTransform,
7834 IWineD3DDeviceImpl_GetTransform,
7835 IWineD3DDeviceImpl_SetVertexDeclaration,
7836 IWineD3DDeviceImpl_GetVertexDeclaration,
7837 IWineD3DDeviceImpl_SetVertexShader,
7838 IWineD3DDeviceImpl_GetVertexShader,
7839 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7840 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7841 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7842 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7843 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7844 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7845 IWineD3DDeviceImpl_SetViewport,
7846 IWineD3DDeviceImpl_GetViewport,
7847 IWineD3DDeviceImpl_MultiplyTransform,
7848 IWineD3DDeviceImpl_ValidateDevice,
7849 IWineD3DDeviceImpl_ProcessVertices,
7850 /*** State block ***/
7851 IWineD3DDeviceImpl_BeginStateBlock,
7852 IWineD3DDeviceImpl_EndStateBlock,
7853 /*** Scene management ***/
7854 IWineD3DDeviceImpl_BeginScene,
7855 IWineD3DDeviceImpl_EndScene,
7856 IWineD3DDeviceImpl_Present,
7857 IWineD3DDeviceImpl_Clear,
7859 IWineD3DDeviceImpl_DrawPrimitive,
7860 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7861 IWineD3DDeviceImpl_DrawPrimitiveUP,
7862 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7863 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7864 IWineD3DDeviceImpl_DrawRectPatch,
7865 IWineD3DDeviceImpl_DrawTriPatch,
7866 IWineD3DDeviceImpl_DeletePatch,
7867 IWineD3DDeviceImpl_ColorFill,
7868 IWineD3DDeviceImpl_UpdateTexture,
7869 IWineD3DDeviceImpl_UpdateSurface,
7870 IWineD3DDeviceImpl_CopyRects,
7871 IWineD3DDeviceImpl_StretchRect,
7872 IWineD3DDeviceImpl_GetRenderTargetData,
7873 IWineD3DDeviceImpl_GetFrontBufferData,
7874 /*** Internal use IWineD3DDevice methods ***/
7875 IWineD3DDeviceImpl_SetupTextureStates,
7876 /*** object tracking ***/
7877 IWineD3DDeviceImpl_ResourceReleased
7881 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7882 WINED3DRS_ALPHABLENDENABLE ,
7883 WINED3DRS_ALPHAFUNC ,
7884 WINED3DRS_ALPHAREF ,
7885 WINED3DRS_ALPHATESTENABLE ,
7887 WINED3DRS_COLORWRITEENABLE ,
7888 WINED3DRS_DESTBLEND ,
7889 WINED3DRS_DITHERENABLE ,
7890 WINED3DRS_FILLMODE ,
7891 WINED3DRS_FOGDENSITY ,
7893 WINED3DRS_FOGSTART ,
7894 WINED3DRS_LASTPIXEL ,
7895 WINED3DRS_SHADEMODE ,
7896 WINED3DRS_SRCBLEND ,
7897 WINED3DRS_STENCILENABLE ,
7898 WINED3DRS_STENCILFAIL ,
7899 WINED3DRS_STENCILFUNC ,
7900 WINED3DRS_STENCILMASK ,
7901 WINED3DRS_STENCILPASS ,
7902 WINED3DRS_STENCILREF ,
7903 WINED3DRS_STENCILWRITEMASK ,
7904 WINED3DRS_STENCILZFAIL ,
7905 WINED3DRS_TEXTUREFACTOR ,
7916 WINED3DRS_ZWRITEENABLE
7919 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7920 WINED3DTSS_ADDRESSW ,
7921 WINED3DTSS_ALPHAARG0 ,
7922 WINED3DTSS_ALPHAARG1 ,
7923 WINED3DTSS_ALPHAARG2 ,
7924 WINED3DTSS_ALPHAOP ,
7925 WINED3DTSS_BUMPENVLOFFSET ,
7926 WINED3DTSS_BUMPENVLSCALE ,
7927 WINED3DTSS_BUMPENVMAT00 ,
7928 WINED3DTSS_BUMPENVMAT01 ,
7929 WINED3DTSS_BUMPENVMAT10 ,
7930 WINED3DTSS_BUMPENVMAT11 ,
7931 WINED3DTSS_COLORARG0 ,
7932 WINED3DTSS_COLORARG1 ,
7933 WINED3DTSS_COLORARG2 ,
7934 WINED3DTSS_COLOROP ,
7935 WINED3DTSS_RESULTARG ,
7936 WINED3DTSS_TEXCOORDINDEX ,
7937 WINED3DTSS_TEXTURETRANSFORMFLAGS
7940 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7941 WINED3DSAMP_ADDRESSU ,
7942 WINED3DSAMP_ADDRESSV ,
7943 WINED3DSAMP_ADDRESSW ,
7944 WINED3DSAMP_BORDERCOLOR ,
7945 WINED3DSAMP_MAGFILTER ,
7946 WINED3DSAMP_MINFILTER ,
7947 WINED3DSAMP_MIPFILTER ,
7948 WINED3DSAMP_MIPMAPLODBIAS ,
7949 WINED3DSAMP_MAXMIPLEVEL ,
7950 WINED3DSAMP_MAXANISOTROPY ,
7951 WINED3DSAMP_SRGBTEXTURE ,
7952 WINED3DSAMP_ELEMENTINDEX
7955 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7957 WINED3DRS_AMBIENTMATERIALSOURCE ,
7958 WINED3DRS_CLIPPING ,
7959 WINED3DRS_CLIPPLANEENABLE ,
7960 WINED3DRS_COLORVERTEX ,
7961 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7962 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7963 WINED3DRS_FOGDENSITY ,
7965 WINED3DRS_FOGSTART ,
7966 WINED3DRS_FOGTABLEMODE ,
7967 WINED3DRS_FOGVERTEXMODE ,
7968 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7969 WINED3DRS_LIGHTING ,
7970 WINED3DRS_LOCALVIEWER ,
7971 WINED3DRS_MULTISAMPLEANTIALIAS ,
7972 WINED3DRS_MULTISAMPLEMASK ,
7973 WINED3DRS_NORMALIZENORMALS ,
7974 WINED3DRS_PATCHEDGESTYLE ,
7975 WINED3DRS_POINTSCALE_A ,
7976 WINED3DRS_POINTSCALE_B ,
7977 WINED3DRS_POINTSCALE_C ,
7978 WINED3DRS_POINTSCALEENABLE ,
7979 WINED3DRS_POINTSIZE ,
7980 WINED3DRS_POINTSIZE_MAX ,
7981 WINED3DRS_POINTSIZE_MIN ,
7982 WINED3DRS_POINTSPRITEENABLE ,
7983 WINED3DRS_RANGEFOGENABLE ,
7984 WINED3DRS_SPECULARMATERIALSOURCE ,
7985 WINED3DRS_TWEENFACTOR ,
7986 WINED3DRS_VERTEXBLEND
7989 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7990 WINED3DTSS_TEXCOORDINDEX ,
7991 WINED3DTSS_TEXTURETRANSFORMFLAGS
7994 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7995 WINED3DSAMP_DMAPOFFSET