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[WINED3DTS_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))
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)) {
1423 TRACE("(%p) Allocating data for an occlusion query\n", This);
1424 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1425 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1428 case D3DQUERYTYPE_VCACHE:
1429 case D3DQUERYTYPE_RESOURCEMANAGER:
1430 case D3DQUERYTYPE_VERTEXSTATS:
1431 case D3DQUERYTYPE_EVENT:
1432 case D3DQUERYTYPE_TIMESTAMP:
1433 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1434 case D3DQUERYTYPE_TIMESTAMPFREQ:
1435 case D3DQUERYTYPE_PIPELINETIMINGS:
1436 case D3DQUERYTYPE_INTERFACETIMINGS:
1437 case D3DQUERYTYPE_VERTEXTIMINGS:
1438 case D3DQUERYTYPE_PIXELTIMINGS:
1439 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1440 case D3DQUERYTYPE_CACHEUTILIZATION:
1442 object->extendedData = 0;
1443 FIXME("(%p) Unhandled query type %d\n",This , Type);
1445 TRACE("(%p) : Created Query %p\n", This, object);
1449 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1450 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1452 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1453 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1457 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1459 XVisualInfo template;
1460 GLXContext oldContext;
1461 Drawable oldDrawable;
1462 HRESULT hr = WINED3D_OK;
1464 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1466 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1467 * does a device hold a reference to a swap chain giving them a lifetime of the device
1468 * or does the swap chain notify the device of its destruction.
1469 *******************************/
1471 /* Check the params */
1472 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1473 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1474 return WINED3DERR_INVALIDCALL;
1475 } else if (*pPresentationParameters->BackBufferCount > 1) {
1476 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");
1479 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1481 /*********************
1482 * Lookup the window Handle and the relating X window handle
1483 ********************/
1485 /* Setup hwnd we are using, plus which display this equates to */
1486 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1487 if (!object->win_handle) {
1488 object->win_handle = This->createParms.hFocusWindow;
1491 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1492 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1493 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1494 return WINED3DERR_NOTAVAILABLE;
1496 hDc = GetDC(object->win_handle);
1497 object->display = get_display(hDc);
1498 ReleaseDC(object->win_handle, hDc);
1499 TRACE("Using a display of %p %p\n", object->display, hDc);
1501 if (NULL == object->display || NULL == hDc) {
1502 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1503 return WINED3DERR_NOTAVAILABLE;
1506 if (object->win == 0) {
1507 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1508 return WINED3DERR_NOTAVAILABLE;
1511 * Create an opengl context for the display visual
1512 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1513 * use different properties after that point in time. FIXME: How to handle when requested format
1514 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1515 * it chooses is identical to the one already being used!
1516 **********************************/
1518 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1521 /* Create a new context for this swapchain */
1522 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1523 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1524 (or the best possible if none is requested) */
1525 TRACE("Found x visual ID : %ld\n", template.visualid);
1527 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1528 if (NULL == object->visInfo) {
1529 ERR("cannot really get XVisual\n");
1531 return WINED3DERR_NOTAVAILABLE;
1534 /* Write out some debug info about the visual/s */
1535 TRACE("Using x visual ID : %ld\n", template.visualid);
1536 TRACE(" visual info: %p\n", object->visInfo);
1537 TRACE(" num items : %d\n", num);
1538 for (n = 0;n < num; n++) {
1539 TRACE("=====item=====: %d\n", n + 1);
1540 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1541 TRACE(" screen : %d\n", object->visInfo[n].screen);
1542 TRACE(" depth : %u\n", object->visInfo[n].depth);
1543 TRACE(" class : %d\n", object->visInfo[n].class);
1544 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1545 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1546 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1547 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1548 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1549 /* log some extra glx info */
1550 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1551 TRACE(" gl_aux_buffers : %d\n", value);
1552 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1553 TRACE(" gl_buffer_size : %d\n", value);
1554 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1555 TRACE(" gl_red_size : %d\n", value);
1556 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1557 TRACE(" gl_green_size : %d\n", value);
1558 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1559 TRACE(" gl_blue_size : %d\n", value);
1560 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1561 TRACE(" gl_alpha_size : %d\n", value);
1562 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1563 TRACE(" gl_depth_size : %d\n", value);
1564 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1565 TRACE(" gl_stencil_size : %d\n", value);
1567 /* Now choose a simila visual ID*/
1569 #ifdef USE_CONTEXT_MANAGER
1571 /** TODO: use a context mamager **/
1575 IWineD3DSwapChain *implSwapChain;
1576 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1577 /* The first time around we create the context that is shared with all other swapchains and render targets */
1578 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1579 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1582 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1583 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1584 /* and create a new context with the implicit swapchains context as the shared context */
1585 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1586 IWineD3DSwapChain_Release(implSwapChain);
1591 XFree(object->visInfo);
1592 object->visInfo = NULL;
1596 if (!object->glCtx) {
1597 ERR("Failed to create GLX context\n");
1598 return WINED3DERR_NOTAVAILABLE;
1600 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1601 object->win_handle, object->glCtx, object->win, object->visInfo);
1604 /*********************
1605 * Windowed / Fullscreen
1606 *******************/
1609 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1610 * so we should really check to see if there is a fullscreen swapchain already
1611 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1612 **************************************/
1614 if (!*(pPresentationParameters->Windowed)) {
1620 /* Get info on the current display setup */
1621 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1622 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1625 /* Change the display settings */
1626 memset(&devmode, 0, sizeof(DEVMODEW));
1627 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1628 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1629 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1630 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1631 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1632 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1634 /* Make popup window */
1635 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1636 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1637 *(pPresentationParameters->BackBufferWidth),
1638 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1640 /* For GetDisplayMode */
1641 This->ddraw_width = devmode.dmPelsWidth;
1642 This->ddraw_height = devmode.dmPelsHeight;
1643 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1647 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1648 * then the corresponding dimension of the client area of the hDeviceWindow
1649 * (or the focus window, if hDeviceWindow is NULL) is taken.
1650 **********************/
1652 if (*(pPresentationParameters->Windowed) &&
1653 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1654 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1657 GetClientRect(object->win_handle, &Rect);
1659 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1660 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1661 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1663 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1664 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1665 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1669 /*********************
1670 * finish off parameter initialization
1671 *******************/
1673 /* Put the correct figures in the presentation parameters */
1674 TRACE("Coppying accross presentaion paraneters\n");
1675 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1676 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1677 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1678 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1679 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1680 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1681 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1682 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1683 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1684 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1685 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1686 object->presentParms.Flags = *(pPresentationParameters->Flags);
1687 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1688 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1691 /*********************
1692 * Create the back, front and stencil buffers
1693 *******************/
1695 TRACE("calling rendertarget CB\n");
1696 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1697 object->presentParms.BackBufferWidth,
1698 object->presentParms.BackBufferHeight,
1699 object->presentParms.BackBufferFormat,
1700 object->presentParms.MultiSampleType,
1701 object->presentParms.MultiSampleQuality,
1702 TRUE /* Lockable */,
1703 &object->frontBuffer,
1704 NULL /* pShared (always null)*/);
1705 if (object->frontBuffer != NULL)
1706 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1708 if(object->presentParms.BackBufferCount > 0) {
1711 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1712 if(!object->backBuffer) {
1713 ERR("Out of memory\n");
1715 if (object->frontBuffer) {
1716 IUnknown *bufferParent;
1717 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1718 IUnknown_Release(bufferParent); /* once for the get parent */
1719 if (IUnknown_Release(bufferParent) > 0) {
1720 FIXME("(%p) Something's still holding the front buffer\n",This);
1723 HeapFree(GetProcessHeap(), 0, object);
1724 return E_OUTOFMEMORY;
1727 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1728 TRACE("calling rendertarget CB\n");
1729 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1730 object->presentParms.BackBufferWidth,
1731 object->presentParms.BackBufferHeight,
1732 object->presentParms.BackBufferFormat,
1733 object->presentParms.MultiSampleType,
1734 object->presentParms.MultiSampleQuality,
1735 TRUE /* Lockable */,
1736 &object->backBuffer[i],
1737 NULL /* pShared (always null)*/);
1738 if(hr == WINED3D_OK && object->backBuffer[i]) {
1739 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1745 object->backBuffer = NULL;
1748 if (object->backBuffer != NULL) {
1750 glDrawBuffer(GL_BACK);
1751 checkGLcall("glDrawBuffer(GL_BACK)");
1754 /* Single buffering - draw to front buffer */
1756 glDrawBuffer(GL_FRONT);
1757 checkGLcall("glDrawBuffer(GL_FRONT)");
1761 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1762 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1763 TRACE("Creating depth stencil buffer\n");
1764 if (This->depthStencilBuffer == NULL ) {
1765 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1766 object->presentParms.BackBufferWidth,
1767 object->presentParms.BackBufferHeight,
1768 object->presentParms.AutoDepthStencilFormat,
1769 object->presentParms.MultiSampleType,
1770 object->presentParms.MultiSampleQuality,
1771 FALSE /* FIXME: Discard */,
1772 &This->depthStencilBuffer,
1773 NULL /* pShared (always null)*/ );
1774 if (This->depthStencilBuffer != NULL)
1775 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1778 /** TODO: A check on width, height and multisample types
1779 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1780 ****************************/
1781 object->wantsDepthStencilBuffer = TRUE;
1783 object->wantsDepthStencilBuffer = FALSE;
1786 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1789 /*********************
1790 * init the default renderTarget management
1791 *******************/
1792 object->drawable = object->win;
1793 object->render_ctx = object->glCtx;
1795 if (hr == WINED3D_OK) {
1796 /*********************
1797 * Setup some defaults and clear down the buffers
1798 *******************/
1800 /** save current context and drawable **/
1801 oldContext = glXGetCurrentContext();
1802 oldDrawable = glXGetCurrentDrawable();
1804 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1805 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1806 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1808 checkGLcall("glXMakeCurrent");
1810 TRACE("Setting up the screen\n");
1811 /* Clear the screen */
1812 glClearColor(1.0, 0.0, 0.0, 0.0);
1813 checkGLcall("glClearColor");
1816 glClearStencil(0xffff);
1818 checkGLcall("glClear");
1820 glColor3f(1.0, 1.0, 1.0);
1821 checkGLcall("glColor3f");
1823 glEnable(GL_LIGHTING);
1824 checkGLcall("glEnable");
1826 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1827 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1829 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1830 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1832 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1833 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1835 /* switch back to the original context (if there was one)*/
1836 if (This->swapchains) {
1837 /** TODO: restore the context and drawable **/
1838 glXMakeCurrent(object->display, oldDrawable, oldContext);
1843 TRACE("Set swapchain to %p\n", object);
1844 } else { /* something went wrong so clean up */
1845 IUnknown* bufferParent;
1846 if (object->frontBuffer) {
1848 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1849 IUnknown_Release(bufferParent); /* once for the get parent */
1850 if (IUnknown_Release(bufferParent) > 0) {
1851 FIXME("(%p) Something's still holding the front buffer\n",This);
1854 if (object->backBuffer) {
1856 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1857 if(object->backBuffer[i]) {
1858 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1859 IUnknown_Release(bufferParent); /* once for the get parent */
1860 if (IUnknown_Release(bufferParent) > 0) {
1861 FIXME("(%p) Something's still holding the back buffer\n",This);
1865 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1866 object->backBuffer = NULL;
1868 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1869 /* Clean up the context */
1870 /* check that we are the current context first (we shouldn't be though!) */
1871 if (object->glCtx != 0) {
1872 if(glXGetCurrentContext() == object->glCtx) {
1873 glXMakeCurrent(object->display, None, NULL);
1875 glXDestroyContext(object->display, object->glCtx);
1877 HeapFree(GetProcessHeap(), 0, object);
1884 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1885 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 TRACE("(%p)\n", This);
1889 return This->NumberOfSwapChains;
1892 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1894 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1896 if(iSwapChain < This->NumberOfSwapChains) {
1897 *pSwapChain = This->swapchains[iSwapChain];
1898 IWineD3DSwapChain_AddRef(*pSwapChain);
1899 TRACE("(%p) returning %p\n", This, *pSwapChain);
1902 TRACE("Swapchain out of range\n");
1904 return WINED3DERR_INVALIDCALL;
1909 * Vertex Declaration
1911 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1913 IWineD3DVertexDeclarationImpl *object = NULL;
1914 HRESULT hr = WINED3D_OK;
1915 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1916 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1919 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1924 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1928 HRESULT hr = WINED3D_OK;
1929 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1930 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1932 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1934 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1935 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1936 if (pDeclaration != NULL) {
1937 IWineD3DVertexDeclaration *vertexDeclaration;
1938 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1939 if (WINED3D_OK == hr) {
1940 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1941 object->vertexDeclaration = vertexDeclaration;
1943 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1944 IWineD3DVertexShader_Release(*ppVertexShader);
1945 return WINED3DERR_INVALIDCALL;
1949 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1951 if (WINED3D_OK != hr) {
1952 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1953 IWineD3DVertexShader_Release(*ppVertexShader);
1954 return WINED3DERR_INVALIDCALL;
1957 #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. */
1958 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1969 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1972 HRESULT hr = WINED3D_OK;
1974 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1975 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1976 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1977 if (WINED3D_OK == hr) {
1978 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1980 WARN("(%p) : Failed to create pixel shader\n", This);
1986 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1988 IWineD3DPaletteImpl *object;
1990 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1992 /* Create the new object */
1993 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1995 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1996 return E_OUTOFMEMORY;
1999 object->lpVtbl = &IWineD3DPalette_Vtbl;
2001 object->Flags = Flags;
2002 object->parent = Parent;
2003 object->wineD3DDevice = This;
2004 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2006 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2009 HeapFree( GetProcessHeap(), 0, object);
2010 return E_OUTOFMEMORY;
2013 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2015 IWineD3DPalette_Release((IWineD3DPalette *) object);
2019 *Palette = (IWineD3DPalette *) object;
2024 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2026 IWineD3DSwapChainImpl *swapchain;
2028 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2029 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2031 /* TODO: Test if OpenGL is compiled in and loaded */
2033 /* Setup the implicit swapchain */
2034 TRACE("Creating implicit swapchain\n");
2035 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2036 WARN("Failed to create implicit swapchain\n");
2037 return WINED3DERR_INVALIDCALL;
2040 This->NumberOfSwapChains = 1;
2041 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2042 if(!This->swapchains) {
2043 ERR("Out of memory!\n");
2044 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2045 return E_OUTOFMEMORY;
2047 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2049 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2050 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2051 This->renderTarget = swapchain->backBuffer[0];
2054 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2055 This->renderTarget = swapchain->frontBuffer;
2057 IWineD3DSurface_AddRef(This->renderTarget);
2058 /* Depth Stencil support */
2059 This->stencilBufferTarget = This->depthStencilBuffer;
2060 if (NULL != This->stencilBufferTarget) {
2061 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2064 /* Set up some starting GL setup */
2067 * Initialize openGL extension related variables
2068 * with Default values
2071 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2072 /* Setup all the devices defaults */
2073 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2075 IWineD3DImpl_CheckGraphicsMemory();
2079 /* Initialize our list of GLSL programs */
2080 list_init(&This->glsl_shader_progs);
2082 { /* Set a default viewport */
2086 vp.Width = *(pPresentationParameters->BackBufferWidth);
2087 vp.Height = *(pPresentationParameters->BackBufferHeight);
2090 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2093 /* Initialize the current view state */
2094 This->modelview_valid = 1;
2095 This->proj_valid = 0;
2096 This->view_ident = 1;
2097 This->last_was_rhw = 0;
2098 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2099 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2101 /* Clear the screen */
2102 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2104 This->d3d_initialized = TRUE;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2111 IUnknown* stencilBufferParent;
2112 IUnknown* swapChainParent;
2114 TRACE("(%p)\n", This);
2116 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2118 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2119 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2122 /* Release the buffers (with sanity checks)*/
2123 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2124 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2125 if(This->depthStencilBuffer != This->stencilBufferTarget)
2126 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2128 This->stencilBufferTarget = NULL;
2130 TRACE("Releasing the render target at %p\n", This->renderTarget);
2131 if(IWineD3DSurface_Release(This->renderTarget) >0){
2132 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2134 TRACE("Setting rendertarget to NULL\n");
2135 This->renderTarget = NULL;
2137 if (This->depthStencilBuffer) {
2138 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2139 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2140 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2141 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2143 This->depthStencilBuffer = NULL;
2146 for(i=0; i < This->NumberOfSwapChains; i++) {
2147 TRACE("Releasing the implicit swapchain %d\n", i);
2148 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2149 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2150 IUnknown_Release(swapChainParent); /* once for the get parent */
2151 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2152 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2156 HeapFree(GetProcessHeap(), 0, This->swapchains);
2157 This->swapchains = NULL;
2158 This->NumberOfSwapChains = 0;
2160 This->d3d_initialized = FALSE;
2164 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2171 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2173 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2174 /* Ignore some modes if a description was passed */
2175 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2176 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2177 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2179 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2181 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2188 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2192 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2194 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2196 /* Resize the screen even without a window:
2197 * The app could have unset it with SetCooperativeLevel, but not called
2198 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2199 * but we don't have any hwnd
2202 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2203 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2204 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2205 devmode.dmPelsWidth = pMode->Width;
2206 devmode.dmPelsHeight = pMode->Height;
2208 devmode.dmDisplayFrequency = pMode->RefreshRate;
2209 if (pMode->RefreshRate != 0) {
2210 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2213 /* Only change the mode if necessary */
2214 if( (This->ddraw_width == pMode->Width) &&
2215 (This->ddraw_height == pMode->Height) &&
2216 (This->ddraw_format == pMode->Format) &&
2217 (pMode->RefreshRate == 0) ) {
2221 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2222 if (ret != DISP_CHANGE_SUCCESSFUL) {
2223 if(devmode.dmDisplayFrequency != 0) {
2224 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2225 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2226 devmode.dmDisplayFrequency = 0;
2227 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2229 if(ret != DISP_CHANGE_SUCCESSFUL) {
2230 return DDERR_INVALIDMODE;
2234 /* Store the new values */
2235 This->ddraw_width = pMode->Width;
2236 This->ddraw_height = pMode->Height;
2237 This->ddraw_format = pMode->Format;
2239 /* Only do this with a window of course */
2240 if(This->ddraw_window)
2241 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2246 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2248 *ppD3D= This->wineD3D;
2249 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2250 IWineD3D_AddRef(*ppD3D);
2254 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2255 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2256 * Into the video ram as possible and seeing how many fit
2257 * you can also get the correct initial value from via X and ATI's driver
2258 *******************/
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 static BOOL showfixmes = TRUE;
2262 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2263 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2266 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2267 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2268 /* videomemory is simulated videomemory + AGP memory left */
2269 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2277 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2279 HRESULT hr = WINED3D_OK;
2281 /* Update the current state block */
2282 This->updateStateBlock->fvf = fvf;
2283 This->updateStateBlock->changed.fvf = TRUE;
2284 This->updateStateBlock->set.fvf = TRUE;
2286 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2291 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2293 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2294 *pfvf = This->stateBlock->fvf;
2299 * Get / Set Stream Source
2301 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 IWineD3DVertexBuffer *oldSrc;
2305 /**TODO: instance and index data, see
2306 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2308 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2311 /* D3d9 only, but shouldn't hurt d3d8 */
2314 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2316 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2317 FIXME("stream index data not supported\n");
2319 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2320 FIXME("stream instance data not supported\n");
2324 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2326 if (StreamNumber >= MAX_STREAMS) {
2327 WARN("Stream out of range %d\n", StreamNumber);
2328 return WINED3DERR_INVALIDCALL;
2331 oldSrc = This->stateBlock->streamSource[StreamNumber];
2332 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2334 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2335 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2336 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2337 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2338 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2339 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2341 /* Handle recording of state blocks */
2342 if (This->isRecordingState) {
2343 TRACE("Recording... not performing anything\n");
2347 /* Same stream object: no action */
2348 if (oldSrc == pStreamData)
2351 /* Need to do a getParent and pass the reffs up */
2352 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2353 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2354 so for now, just count internally */
2355 if (pStreamData != NULL) {
2356 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2357 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2358 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2360 vbImpl->stream = StreamNumber;
2361 vbImpl->Flags |= VBFLAG_STREAM;
2362 IWineD3DVertexBuffer_AddRef(pStreamData);
2364 if (oldSrc != NULL) {
2365 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2366 IWineD3DVertexBuffer_Release(oldSrc);
2372 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2376 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2377 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2380 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2382 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2383 FIXME("stream index data not supported\n");
2385 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2386 FIXME("stream instance data not supported\n");
2390 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2392 if (StreamNumber >= MAX_STREAMS) {
2393 WARN("Stream out of range %d\n", StreamNumber);
2394 return WINED3DERR_INVALIDCALL;
2396 *pStream = This->stateBlock->streamSource[StreamNumber];
2397 *pStride = This->stateBlock->streamStride[StreamNumber];
2398 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2400 if (*pStream == NULL) {
2401 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2402 return WINED3DERR_INVALIDCALL;
2405 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2409 /*Should be quite easy, just an extension of vertexdata
2411 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2413 The divider is a bit odd though
2415 VertexOffset = StartVertex / Divider * StreamStride +
2416 VertexIndex / Divider * StreamStride + StreamOffset
2419 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2423 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2425 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2426 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2427 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2429 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2430 FIXME("Stream indexing not fully supported\n");
2436 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2439 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2440 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2442 TRACE("(%p) : returning %d\n", This, *Divider);
2448 * Get / Set & Multiply Transform
2450 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 /* Most of this routine, comments included copied from ddraw tree initially: */
2454 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2456 /* Handle recording of state blocks */
2457 if (This->isRecordingState) {
2458 TRACE("Recording... not performing anything\n");
2459 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2460 This->updateStateBlock->set.transform[d3dts] = TRUE;
2461 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2466 * If the new matrix is the same as the current one,
2467 * we cut off any further processing. this seems to be a reasonable
2468 * optimization because as was noticed, some apps (warcraft3 for example)
2469 * tend towards setting the same matrix repeatedly for some reason.
2471 * From here on we assume that the new matrix is different, wherever it matters.
2473 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2474 TRACE("The app is setting the same matrix over again\n");
2477 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2481 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2482 where ViewMat = Camera space, WorldMat = world space.
2484 In OpenGL, camera and world space is combined into GL_MODELVIEW
2485 matrix. The Projection matrix stay projection matrix.
2488 /* Capture the times we can just ignore the change for now */
2489 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2490 This->modelview_valid = FALSE;
2493 } else if (d3dts == WINED3DTS_PROJECTION) {
2494 This->proj_valid = FALSE;
2497 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2498 /* Indexed Vertex Blending Matrices 256 -> 511 */
2499 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2500 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2504 /* Now we really are going to have to change a matrix */
2507 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2508 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2509 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2512 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2513 * NOTE: We have to reset the positions even if the light/plane is not currently
2514 * enabled, since the call to enable it will not reset the position.
2515 * NOTE2: Apparently texture transforms do NOT need reapplying
2518 PLIGHTINFOEL *lightChain = NULL;
2519 This->modelview_valid = FALSE;
2520 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2522 glMatrixMode(GL_MODELVIEW);
2523 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2525 glLoadMatrixf((float *)lpmatrix);
2526 checkGLcall("glLoadMatrixf(...)");
2529 lightChain = This->stateBlock->lights;
2530 while (lightChain && lightChain->glIndex != -1) {
2531 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2532 checkGLcall("glLightfv posn");
2533 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2534 checkGLcall("glLightfv dirn");
2535 lightChain = lightChain->next;
2538 /* Reset Clipping Planes if clipping is enabled */
2539 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2540 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2541 checkGLcall("glClipPlane");
2545 } else { /* What was requested!?? */
2546 WARN("invalid matrix specified: %i\n", d3dts);
2549 /* Release lock, all done */
2554 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2557 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2561 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2562 D3DMATRIX *mat = NULL;
2565 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2566 * below means it will be recorded in a state block change, but it
2567 * works regardless where it is recorded.
2568 * If this is found to be wrong, change to StateBlock.
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2573 if (State < HIGHEST_TRANSFORMSTATE)
2575 mat = &This->updateStateBlock->transforms[State];
2577 FIXME("Unhandled transform state!!\n");
2580 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2582 /* Apply change via set transform - will reapply to eg. lights this way */
2583 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2588 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2590 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2591 you can reference any indexes you want as long as that number max are enabled at any
2592 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2593 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2594 but when recording, just build a chain pretty much of commands to be replayed. */
2596 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2598 PLIGHTINFOEL *object, *temp;
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2603 /* If recording state block, just add to end of lights chain */
2604 if (This->isRecordingState) {
2605 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2606 if (NULL == object) {
2607 return WINED3DERR_OUTOFVIDEOMEMORY;
2609 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2610 object->OriginalIndex = Index;
2611 object->glIndex = -1;
2612 object->changed = TRUE;
2614 /* Add to the END of the chain of lights changes to be replayed */
2615 if (This->updateStateBlock->lights == NULL) {
2616 This->updateStateBlock->lights = object;
2618 temp = This->updateStateBlock->lights;
2619 while (temp->next != NULL) temp=temp->next;
2620 temp->next = object;
2622 TRACE("Recording... not performing anything more\n");
2626 /* Ok, not recording any longer so do real work */
2627 object = This->stateBlock->lights;
2628 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2630 /* If we didn't find it in the list of lights, time to add it */
2631 if (object == NULL) {
2632 PLIGHTINFOEL *insertAt,*prevPos;
2634 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2635 if (NULL == object) {
2636 return WINED3DERR_OUTOFVIDEOMEMORY;
2638 object->OriginalIndex = Index;
2639 object->glIndex = -1;
2641 /* Add it to the front of list with the idea that lights will be changed as needed
2642 BUT after any lights currently assigned GL indexes */
2643 insertAt = This->stateBlock->lights;
2645 while (insertAt != NULL && insertAt->glIndex != -1) {
2647 insertAt = insertAt->next;
2650 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2651 This->stateBlock->lights = object;
2652 } else if (insertAt == NULL) { /* End of list */
2653 prevPos->next = object;
2654 object->prev = prevPos;
2655 } else { /* Middle of chain */
2656 if (prevPos == NULL) {
2657 This->stateBlock->lights = object;
2659 prevPos->next = object;
2661 object->prev = prevPos;
2662 object->next = insertAt;
2663 insertAt->prev = object;
2667 /* Initialize the object */
2668 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,
2669 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2670 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2671 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2672 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2673 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2674 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2676 /* Save away the information */
2677 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2679 switch (pLight->Type) {
2680 case D3DLIGHT_POINT:
2682 object->lightPosn[0] = pLight->Position.x;
2683 object->lightPosn[1] = pLight->Position.y;
2684 object->lightPosn[2] = pLight->Position.z;
2685 object->lightPosn[3] = 1.0f;
2686 object->cutoff = 180.0f;
2690 case D3DLIGHT_DIRECTIONAL:
2692 object->lightPosn[0] = -pLight->Direction.x;
2693 object->lightPosn[1] = -pLight->Direction.y;
2694 object->lightPosn[2] = -pLight->Direction.z;
2695 object->lightPosn[3] = 0.0;
2696 object->exponent = 0.0f;
2697 object->cutoff = 180.0f;
2702 object->lightPosn[0] = pLight->Position.x;
2703 object->lightPosn[1] = pLight->Position.y;
2704 object->lightPosn[2] = pLight->Position.z;
2705 object->lightPosn[3] = 1.0;
2708 object->lightDirn[0] = pLight->Direction.x;
2709 object->lightDirn[1] = pLight->Direction.y;
2710 object->lightDirn[2] = pLight->Direction.z;
2711 object->lightDirn[3] = 1.0;
2714 * opengl-ish and d3d-ish spot lights use too different models for the
2715 * light "intensity" as a function of the angle towards the main light direction,
2716 * so we only can approximate very roughly.
2717 * however spot lights are rather rarely used in games (if ever used at all).
2718 * furthermore if still used, probably nobody pays attention to such details.
2720 if (pLight->Falloff == 0) {
2723 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2725 if (rho < 0.0001) rho = 0.0001f;
2726 object->exponent = -0.3/log(cos(rho/2));
2727 object->cutoff = pLight->Phi*90/M_PI;
2733 FIXME("Unrecognized light type %d\n", pLight->Type);
2736 /* Update the live definitions if the light is currently assigned a glIndex */
2737 if (object->glIndex != -1) {
2738 setup_light(iface, object->glIndex, object);
2743 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2744 PLIGHTINFOEL *lightInfo = NULL;
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2746 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2748 /* Locate the light in the live lights */
2749 lightInfo = This->stateBlock->lights;
2750 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2752 if (lightInfo == NULL) {
2753 TRACE("Light information requested but light not defined\n");
2754 return WINED3DERR_INVALIDCALL;
2757 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2762 * Get / Set Light Enable
2763 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2765 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2766 PLIGHTINFOEL *lightInfo = NULL;
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2770 /* Tests show true = 128...not clear why */
2772 Enable = Enable? 128: 0;
2774 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2775 if (This->isRecordingState) {
2776 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2777 if (NULL == lightInfo) {
2778 return WINED3DERR_OUTOFVIDEOMEMORY;
2780 lightInfo->OriginalIndex = Index;
2781 lightInfo->glIndex = -1;
2782 lightInfo->enabledChanged = TRUE;
2783 lightInfo->lightEnabled = Enable;
2785 /* Add to the END of the chain of lights changes to be replayed */
2786 if (This->updateStateBlock->lights == NULL) {
2787 This->updateStateBlock->lights = lightInfo;
2789 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2790 while (temp->next != NULL) temp=temp->next;
2791 temp->next = lightInfo;
2793 TRACE("Recording... not performing anything more\n");
2797 /* Not recording... So, locate the light in the live lights */
2798 lightInfo = This->stateBlock->lights;
2799 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2801 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2802 if (lightInfo == NULL) {
2804 TRACE("Light enabled requested but light not defined, so defining one!\n");
2805 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2807 /* Search for it again! Should be fairly quick as near head of list */
2808 lightInfo = This->stateBlock->lights;
2809 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2810 if (lightInfo == NULL) {
2811 FIXME("Adding default lights has failed dismally\n");
2812 return WINED3DERR_INVALIDCALL;
2816 /* OK, we now have a light... */
2817 if (Enable == FALSE) {
2819 /* If we are disabling it, check it was enabled, and
2820 still only do something if it has assigned a glIndex (which it should have!) */
2821 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2822 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2824 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2825 checkGLcall("glDisable GL_LIGHT0+Index");
2828 TRACE("Nothing to do as light was not enabled\n");
2830 lightInfo->lightEnabled = Enable;
2833 /* We are enabling it. If it is enabled, it's really simple */
2834 if (lightInfo->lightEnabled) {
2836 TRACE("Nothing to do as light was enabled\n");
2838 /* If it already has a glIndex, it's still simple */
2839 } else if (lightInfo->glIndex != -1) {
2840 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2841 lightInfo->lightEnabled = Enable;
2843 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2844 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2847 /* Otherwise got to find space - lights are ordered gl indexes first */
2849 PLIGHTINFOEL *bsf = NULL;
2850 PLIGHTINFOEL *pos = This->stateBlock->lights;
2851 PLIGHTINFOEL *prev = NULL;
2855 /* Try to minimize changes as much as possible */
2856 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2858 /* Try to remember which index can be replaced if necessary */
2859 if (bsf==NULL && pos->lightEnabled == FALSE) {
2860 /* Found a light we can replace, save as best replacement */
2864 /* Step to next space */
2870 /* If we have too many active lights, fail the call */
2871 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2872 FIXME("Program requests too many concurrent lights\n");
2873 return WINED3DERR_INVALIDCALL;
2875 /* If we have allocated all lights, but not all are enabled,
2876 reuse one which is not enabled */
2877 } else if (Index == This->maxConcurrentLights) {
2878 /* use bsf - Simply swap the new light and the BSF one */
2879 PLIGHTINFOEL *bsfNext = bsf->next;
2880 PLIGHTINFOEL *bsfPrev = bsf->prev;
2883 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2884 if (bsf->prev != NULL) {
2885 bsf->prev->next = lightInfo;
2887 This->stateBlock->lights = lightInfo;
2890 /* If not side by side, lots of chains to update */
2891 if (bsf->next != lightInfo) {
2892 lightInfo->prev->next = bsf;
2893 bsf->next->prev = lightInfo;
2894 bsf->next = lightInfo->next;
2895 bsf->prev = lightInfo->prev;
2896 lightInfo->next = bsfNext;
2897 lightInfo->prev = bsfPrev;
2901 bsf->prev = lightInfo;
2902 bsf->next = lightInfo->next;
2903 lightInfo->next = bsf;
2904 lightInfo->prev = bsfPrev;
2909 glIndex = bsf->glIndex;
2911 lightInfo->glIndex = glIndex;
2912 lightInfo->lightEnabled = Enable;
2914 /* Finally set up the light in gl itself */
2915 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2917 setup_light(iface, glIndex, lightInfo);
2918 glEnable(GL_LIGHT0 + glIndex);
2919 checkGLcall("glEnable GL_LIGHT0 new setup");
2922 /* If we reached the end of the allocated lights, with space in the
2923 gl lights, setup a new light */
2924 } else if (pos->glIndex == -1) {
2926 /* We reached the end of the allocated gl lights, so already
2927 know the index of the next one! */
2929 lightInfo->glIndex = glIndex;
2930 lightInfo->lightEnabled = Enable;
2932 /* In an ideal world, it's already in the right place */
2933 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2934 /* No need to move it */
2936 /* Remove this light from the list */
2937 lightInfo->prev->next = lightInfo->next;
2938 if (lightInfo->next != NULL) {
2939 lightInfo->next->prev = lightInfo->prev;
2942 /* Add in at appropriate place (inbetween prev and pos) */
2943 lightInfo->prev = prev;
2944 lightInfo->next = pos;
2946 This->stateBlock->lights = lightInfo;
2948 prev->next = lightInfo;
2951 pos->prev = lightInfo;
2955 /* Finally set up the light in gl itself */
2956 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2958 setup_light(iface, glIndex, lightInfo);
2959 glEnable(GL_LIGHT0 + glIndex);
2960 checkGLcall("glEnable GL_LIGHT0 new setup");
2969 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2971 PLIGHTINFOEL *lightInfo = NULL;
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 TRACE("(%p) : for idx(%ld)\n", This, Index);
2975 /* Locate the light in the live lights */
2976 lightInfo = This->stateBlock->lights;
2977 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2979 if (lightInfo == NULL) {
2980 TRACE("Light enabled state requested but light not defined\n");
2981 return WINED3DERR_INVALIDCALL;
2983 *pEnable = lightInfo->lightEnabled;
2988 * Get / Set Clip Planes
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2994 /* Validate Index */
2995 if (Index >= GL_LIMITS(clipplanes)) {
2996 TRACE("Application has requested clipplane this device doesn't support\n");
2997 return WINED3DERR_INVALIDCALL;
3000 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3001 This->updateStateBlock->set.clipplane[Index] = TRUE;
3002 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3003 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3004 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3005 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3007 /* Handle recording of state blocks */
3008 if (This->isRecordingState) {
3009 TRACE("Recording... not performing anything\n");
3017 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3018 glMatrixMode(GL_MODELVIEW);
3020 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3022 TRACE("Clipplane [%f,%f,%f,%f]\n",
3023 This->updateStateBlock->clipplane[Index][0],
3024 This->updateStateBlock->clipplane[Index][1],
3025 This->updateStateBlock->clipplane[Index][2],
3026 This->updateStateBlock->clipplane[Index][3]);
3027 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3028 checkGLcall("glClipPlane");
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 TRACE("(%p) : for idx %ld\n", This, Index);
3040 /* Validate Index */
3041 if (Index >= GL_LIMITS(clipplanes)) {
3042 TRACE("Application has requested clipplane this device doesn't support\n");
3043 return WINED3DERR_INVALIDCALL;
3046 pPlane[0] = This->stateBlock->clipplane[Index][0];
3047 pPlane[1] = This->stateBlock->clipplane[Index][1];
3048 pPlane[2] = This->stateBlock->clipplane[Index][2];
3049 pPlane[3] = This->stateBlock->clipplane[Index][3];
3054 * Get / Set Clip Plane Status
3055 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3057 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 FIXME("(%p) : stub\n", This);
3060 if (NULL == pClipStatus) {
3061 return WINED3DERR_INVALIDCALL;
3063 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3064 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3068 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 FIXME("(%p) : stub\n", This);
3071 if (NULL == pClipStatus) {
3072 return WINED3DERR_INVALIDCALL;
3074 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3075 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3080 * Get / Set Material
3081 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3083 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 This->updateStateBlock->changed.material = TRUE;
3087 This->updateStateBlock->set.material = TRUE;
3088 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3090 /* Handle recording of state blocks */
3091 if (This->isRecordingState) {
3092 TRACE("Recording... not performing anything\n");
3097 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3098 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3099 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3100 pMaterial->Ambient.b, pMaterial->Ambient.a);
3101 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3102 pMaterial->Specular.b, pMaterial->Specular.a);
3103 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3104 pMaterial->Emissive.b, pMaterial->Emissive.a);
3105 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3107 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3108 checkGLcall("glMaterialfv(GL_AMBIENT)");
3109 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3110 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3112 /* Only change material color if specular is enabled, otherwise it is set to black */
3113 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3114 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3115 checkGLcall("glMaterialfv(GL_SPECULAR");
3117 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3118 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3119 checkGLcall("glMaterialfv(GL_SPECULAR");
3121 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3122 checkGLcall("glMaterialfv(GL_EMISSION)");
3123 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3124 checkGLcall("glMaterialf(GL_SHININESS");
3130 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3133 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3134 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3135 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3136 pMaterial->Ambient.b, pMaterial->Ambient.a);
3137 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3138 pMaterial->Specular.b, pMaterial->Specular.a);
3139 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3140 pMaterial->Emissive.b, pMaterial->Emissive.a);
3141 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3149 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3150 UINT BaseVertexIndex) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 IWineD3DIndexBuffer *oldIdxs;
3154 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3155 oldIdxs = This->updateStateBlock->pIndexData;
3157 This->updateStateBlock->changed.indices = TRUE;
3158 This->updateStateBlock->set.indices = TRUE;
3159 This->updateStateBlock->pIndexData = pIndexData;
3160 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3162 /* Handle recording of state blocks */
3163 if (This->isRecordingState) {
3164 TRACE("Recording... not performing anything\n");
3168 if (NULL != pIndexData) {
3169 IWineD3DIndexBuffer_AddRef(pIndexData);
3171 if (NULL != oldIdxs) {
3172 IWineD3DIndexBuffer_Release(oldIdxs);
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 *ppIndexData = This->stateBlock->pIndexData;
3182 /* up ref count on ppindexdata */
3184 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3185 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3186 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3188 TRACE("(%p) No index data set\n", This);
3190 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3196 * Get / Set Viewports
3198 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("(%p)\n", This);
3202 This->updateStateBlock->changed.viewport = TRUE;
3203 This->updateStateBlock->set.viewport = TRUE;
3204 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3211 This->viewport_changed = TRUE;
3215 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3216 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3218 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3219 checkGLcall("glDepthRange");
3220 /* Note: GL requires lower left, DirectX supplies upper left */
3221 /* TODO: replace usage of renderTarget with context management */
3222 glViewport(pViewport->X,
3223 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3224 pViewport->Width, pViewport->Height);
3226 checkGLcall("glViewport");
3234 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 TRACE("(%p)\n", This);
3237 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3241 static void renderstate_stencil_twosided(
3242 IWineD3DDeviceImpl *This,
3249 GLint stencilPass ) {
3250 #if 0 /* Don't use OpenGL 2.0 calls for now */
3251 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3252 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3253 checkGLcall("glStencilFuncSeparate(...)");
3254 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3255 checkGLcall("glStencilOpSeparate(...)");
3259 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3260 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3261 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3262 GL_EXTCALL(glActiveStencilFaceEXT(face));
3263 checkGLcall("glActiveStencilFaceEXT(...)");
3264 glStencilFunc(func, ref, mask);
3265 checkGLcall("glStencilFunc(...)");
3266 glStencilOp(stencilFail, depthFail, stencilPass);
3267 checkGLcall("glStencilOp(...)");
3268 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3269 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3270 checkGLcall("glStencilFuncSeparateATI(...)");
3271 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3272 checkGLcall("glStencilOpSeparateATI(...)");
3274 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3278 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3279 DWORD onesided_enable = FALSE;
3280 DWORD twosided_enable = FALSE;
3281 GLint func = GL_ALWAYS;
3282 GLint func_ccw = GL_ALWAYS;
3285 GLint stencilFail = GL_KEEP;
3286 GLint depthFail = GL_KEEP;
3287 GLint stencilPass = GL_KEEP;
3288 GLint stencilFail_ccw = GL_KEEP;
3289 GLint depthFail_ccw = GL_KEEP;
3290 GLint stencilPass_ccw = GL_KEEP;
3292 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3293 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3294 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3295 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3296 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3297 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3298 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3299 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3300 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3301 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3302 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3303 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3304 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3305 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3306 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3307 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3308 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3309 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3310 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3311 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3312 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3313 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3314 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3315 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3318 case WINED3DRS_STENCILENABLE :
3319 onesided_enable = Value;
3321 case WINED3DRS_TWOSIDEDSTENCILMODE :
3322 twosided_enable = Value;
3324 case WINED3DRS_STENCILFUNC :
3325 func = StencilFunc(Value);
3327 case WINED3DRS_CCW_STENCILFUNC :
3328 func_ccw = StencilFunc(Value);
3330 case WINED3DRS_STENCILREF :
3333 case WINED3DRS_STENCILMASK :
3336 case WINED3DRS_STENCILFAIL :
3337 stencilFail = StencilOp(Value);
3339 case WINED3DRS_STENCILZFAIL :
3340 depthFail = StencilOp(Value);
3342 case WINED3DRS_STENCILPASS :
3343 stencilPass = StencilOp(Value);
3345 case WINED3DRS_CCW_STENCILFAIL :
3346 stencilFail_ccw = StencilOp(Value);
3348 case WINED3DRS_CCW_STENCILZFAIL :
3349 depthFail_ccw = StencilOp(Value);
3351 case WINED3DRS_CCW_STENCILPASS :
3352 stencilPass_ccw = StencilOp(Value);
3355 ERR("This should not happen!");
3358 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3359 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3360 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3361 onesided_enable, twosided_enable, ref, mask,
3362 func, stencilFail, depthFail, stencilPass,
3363 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3365 if (twosided_enable) {
3366 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3367 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3369 if (onesided_enable) {
3370 glEnable(GL_STENCIL_TEST);
3371 checkGLcall("glEnable GL_STENCIL_TEST");
3372 glStencilFunc(func, ref, mask);
3373 checkGLcall("glStencilFunc(...)");
3374 glStencilOp(stencilFail, depthFail, stencilPass);
3375 checkGLcall("glStencilOp(...)");
3377 glDisable(GL_STENCIL_TEST);
3378 checkGLcall("glDisable GL_STENCIL_TEST");
3384 * Get / Set Render States
3385 * TODO: Verify against dx9 definitions
3387 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3390 DWORD OldValue = This->stateBlock->renderState[State];
3392 /* Simple way of referring to either a DWORD or a 4 byte float */
3398 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3399 This->updateStateBlock->changed.renderState[State] = TRUE;
3400 This->updateStateBlock->set.renderState[State] = TRUE;
3401 This->updateStateBlock->renderState[State] = Value;
3403 /* Handle recording of state blocks */
3404 if (This->isRecordingState) {
3405 TRACE("Recording... not performing anything\n");
3412 case WINED3DRS_FILLMODE :
3413 switch ((D3DFILLMODE) Value) {
3414 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3415 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3416 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3418 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3420 checkGLcall("glPolygonMode (fillmode)");
3423 case WINED3DRS_LIGHTING :
3425 glEnable(GL_LIGHTING);
3426 checkGLcall("glEnable GL_LIGHTING");
3428 glDisable(GL_LIGHTING);
3429 checkGLcall("glDisable GL_LIGHTING");
3433 case WINED3DRS_ZENABLE :
3434 switch ((D3DZBUFFERTYPE) Value) {
3436 glDisable(GL_DEPTH_TEST);
3437 checkGLcall("glDisable GL_DEPTH_TEST");
3440 glEnable(GL_DEPTH_TEST);
3441 checkGLcall("glEnable GL_DEPTH_TEST");
3444 glEnable(GL_DEPTH_TEST);
3445 checkGLcall("glEnable GL_DEPTH_TEST");
3446 FIXME("W buffer is not well handled\n");
3449 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3453 case WINED3DRS_CULLMODE :
3455 /* If we are culling "back faces with clockwise vertices" then
3456 set front faces to be counter clockwise and enable culling
3458 switch ((D3DCULL) Value) {
3460 glDisable(GL_CULL_FACE);
3461 checkGLcall("glDisable GL_CULL_FACE");
3464 glEnable(GL_CULL_FACE);
3465 checkGLcall("glEnable GL_CULL_FACE");
3466 if (This->renderUpsideDown) {
3468 checkGLcall("glFrontFace GL_CW");
3470 glFrontFace(GL_CCW);
3471 checkGLcall("glFrontFace GL_CCW");
3473 glCullFace(GL_BACK);
3476 glEnable(GL_CULL_FACE);
3477 checkGLcall("glEnable GL_CULL_FACE");
3478 if (This->renderUpsideDown) {
3479 glFrontFace(GL_CCW);
3480 checkGLcall("glFrontFace GL_CCW");
3483 checkGLcall("glFrontFace GL_CW");
3485 glCullFace(GL_BACK);
3488 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3492 case WINED3DRS_SHADEMODE :
3493 switch ((D3DSHADEMODE) Value) {
3495 glShadeModel(GL_FLAT);
3496 checkGLcall("glShadeModel");
3498 case D3DSHADE_GOURAUD:
3499 glShadeModel(GL_SMOOTH);
3500 checkGLcall("glShadeModel");
3502 case D3DSHADE_PHONG:
3503 FIXME("D3DSHADE_PHONG isn't supported\n");
3506 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3510 case WINED3DRS_DITHERENABLE :
3512 glEnable(GL_DITHER);
3513 checkGLcall("glEnable GL_DITHER");
3515 glDisable(GL_DITHER);
3516 checkGLcall("glDisable GL_DITHER");
3520 case WINED3DRS_ZWRITEENABLE :
3523 checkGLcall("glDepthMask");
3526 checkGLcall("glDepthMask");
3530 case WINED3DRS_ZFUNC :
3532 int glParm = GL_LESS;
3534 switch ((D3DCMPFUNC) Value) {
3535 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3536 case D3DCMP_LESS: glParm=GL_LESS; break;
3537 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3538 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3539 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3540 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3541 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3542 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3544 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3546 glDepthFunc(glParm);
3547 checkGLcall("glDepthFunc");
3551 case WINED3DRS_AMBIENT :
3554 D3DCOLORTOGLFLOAT4(Value, col);
3555 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3556 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3557 checkGLcall("glLightModel for MODEL_AMBIENT");
3562 case WINED3DRS_ALPHABLENDENABLE :
3565 checkGLcall("glEnable GL_BLEND");
3567 glDisable(GL_BLEND);
3568 checkGLcall("glDisable GL_BLEND");
3572 case WINED3DRS_SRCBLEND :
3573 case WINED3DRS_DESTBLEND :
3575 int newVal = GL_ZERO;
3577 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3578 case D3DBLEND_ONE : newVal = GL_ONE; break;
3579 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3580 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3581 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3582 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3583 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3584 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3585 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3586 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3587 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3589 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3590 This->srcBlend = newVal;
3591 This->dstBlend = newVal;
3594 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3595 This->srcBlend = newVal;
3596 This->dstBlend = newVal;
3599 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3602 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3603 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3604 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3605 glBlendFunc(This->srcBlend, This->dstBlend);
3607 checkGLcall("glBlendFunc");
3611 case WINED3DRS_ALPHATESTENABLE :
3612 case WINED3DRS_ALPHAFUNC :
3613 case WINED3DRS_ALPHAREF :
3614 case WINED3DRS_COLORKEYENABLE :
3617 float ref = GL_LESS;
3618 BOOL enable_ckey = FALSE;
3620 IWineD3DSurfaceImpl *surf;
3622 /* Find out if the texture on the first stage has a ckey set */
3623 if(This->stateBlock->textures[0]) {
3624 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3625 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3628 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3629 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3630 glEnable(GL_ALPHA_TEST);
3631 checkGLcall("glEnable GL_ALPHA_TEST");
3633 glDisable(GL_ALPHA_TEST);
3634 checkGLcall("glDisable GL_ALPHA_TEST");
3635 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3641 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3642 glParm = GL_NOTEQUAL;
3645 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3647 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3648 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3649 case D3DCMP_LESS: glParm = GL_LESS; break;
3650 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3651 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3652 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3653 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3654 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3655 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3657 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3660 This->alphafunc = glParm;
3661 glAlphaFunc(glParm, ref);
3662 checkGLcall("glAlphaFunc");
3666 case WINED3DRS_CLIPPLANEENABLE :
3667 case WINED3DRS_CLIPPING :
3669 /* Ensure we only do the changed clip planes */
3670 DWORD enable = 0xFFFFFFFF;
3671 DWORD disable = 0x00000000;
3673 /* If enabling / disabling all */
3674 if (State == WINED3DRS_CLIPPING) {
3676 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3679 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3683 enable = Value & ~OldValue;
3684 disable = ~Value & OldValue;
3687 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3688 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3689 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3690 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3691 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3692 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3694 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3695 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3696 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3697 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3698 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3699 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3701 /** update clipping status */
3703 This->stateBlock->clip_status.ClipUnion = 0;
3704 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3706 This->stateBlock->clip_status.ClipUnion = 0;
3707 This->stateBlock->clip_status.ClipIntersection = 0;
3712 case WINED3DRS_BLENDOP :
3714 int glParm = GL_FUNC_ADD;
3716 switch ((D3DBLENDOP) Value) {
3717 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3718 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3719 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3720 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3721 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3723 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3726 if(GL_SUPPORT(ARB_IMAGING)) {
3727 TRACE("glBlendEquation(%x)\n", glParm);
3728 GL_EXTCALL(glBlendEquation(glParm));
3729 checkGLcall("glBlendEquation");
3731 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3736 case WINED3DRS_TEXTUREFACTOR :
3740 /* Note the texture color applies to all textures whereas
3741 GL_TEXTURE_ENV_COLOR applies to active only */
3743 D3DCOLORTOGLFLOAT4(Value, col);
3744 /* Set the default alpha blend color */
3745 if (GL_SUPPORT(ARB_IMAGING)) {
3746 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3747 checkGLcall("glBlendColor");
3749 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3752 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3753 /* And now the default texture color as well */
3754 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3755 /* Note the D3DRS value applies to all textures, but GL has one
3756 per texture, so apply it now ready to be used! */
3757 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3758 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3759 checkGLcall("glActiveTextureARB");
3761 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3764 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3765 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3771 case WINED3DRS_SPECULARENABLE :
3773 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3774 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3775 specular color. This is wrong:
3776 Separate specular color means the specular colour is maintained separately, whereas
3777 single color means it is merged in. However in both cases they are being used to
3779 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3780 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3784 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3785 * Instead, we need to setup the FinalCombiner properly.
3787 * The default setup for the FinalCombiner is:
3789 * <variable> <input> <mapping> <usage>
3790 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3791 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3792 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3793 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3794 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3795 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3796 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3798 * That's pretty much fine as it is, except for variable B, which needs to take
3799 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3800 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3804 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3805 checkGLcall("glMaterialfv");
3806 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3807 glEnable(GL_COLOR_SUM_EXT);
3809 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3811 checkGLcall("glEnable(GL_COLOR_SUM)");
3813 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3814 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3815 checkGLcall("glFinalCombinerInputNV()");
3818 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3820 /* for the case of enabled lighting: */
3821 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3822 checkGLcall("glMaterialfv");
3824 /* for the case of disabled lighting: */
3825 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3826 glDisable(GL_COLOR_SUM_EXT);
3828 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3830 checkGLcall("glDisable(GL_COLOR_SUM)");
3832 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3833 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3834 checkGLcall("glFinalCombinerInputNV()");
3840 case WINED3DRS_STENCILENABLE :
3841 case WINED3DRS_TWOSIDEDSTENCILMODE :
3842 case WINED3DRS_STENCILFUNC :
3843 case WINED3DRS_CCW_STENCILFUNC :
3844 case WINED3DRS_STENCILREF :
3845 case WINED3DRS_STENCILMASK :
3846 case WINED3DRS_STENCILFAIL :
3847 case WINED3DRS_STENCILZFAIL :
3848 case WINED3DRS_STENCILPASS :
3849 case WINED3DRS_CCW_STENCILFAIL :
3850 case WINED3DRS_CCW_STENCILZFAIL :
3851 case WINED3DRS_CCW_STENCILPASS :
3852 renderstate_stencil(This, State, Value);
3854 case WINED3DRS_STENCILWRITEMASK :
3856 glStencilMask(Value);
3857 TRACE("glStencilMask(%lu)\n", Value);
3858 checkGLcall("glStencilMask");
3862 case WINED3DRS_FOGENABLE :
3866 checkGLcall("glEnable GL_FOG");
3869 checkGLcall("glDisable GL_FOG");
3874 case WINED3DRS_RANGEFOGENABLE :
3877 TRACE("Enabled RANGEFOG");
3879 TRACE("Disabled RANGEFOG");
3884 case WINED3DRS_FOGCOLOR :
3887 D3DCOLORTOGLFLOAT4(Value, col);
3888 /* Set the default alpha blend color */
3889 glFogfv(GL_FOG_COLOR, &col[0]);
3890 checkGLcall("glFog GL_FOG_COLOR");
3894 case WINED3DRS_FOGTABLEMODE :
3895 case WINED3DRS_FOGVERTEXMODE :
3897 /* 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." */
3898 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3899 glHint(GL_FOG_HINT, GL_FASTEST);
3900 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3901 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3902 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3903 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3906 if(!This->last_was_rhw) {
3907 glFogi(GL_FOG_MODE, GL_EXP);
3908 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3909 if(GL_SUPPORT(EXT_FOG_COORD)) {
3910 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3911 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3912 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3913 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3919 if(!This->last_was_rhw) {
3920 glFogi(GL_FOG_MODE, GL_EXP2);
3921 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3922 if(GL_SUPPORT(EXT_FOG_COORD)) {
3923 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3924 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3925 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3926 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3931 case D3DFOG_LINEAR: {
3932 if(!This->last_was_rhw) {
3933 glFogi(GL_FOG_MODE, GL_LINEAR);
3934 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3935 if(GL_SUPPORT(EXT_FOG_COORD)) {
3936 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3937 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3938 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3939 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3945 /* Both are none? According to msdn the alpha channel of the specular
3946 * color contains a fog factor. Set it in drawStridedSlow.
3947 * Same happens with Vertexfog on transformed vertices
3949 if(GL_SUPPORT(EXT_FOG_COORD)) {
3950 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3951 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3952 glFogi(GL_FOG_MODE, GL_LINEAR);
3953 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3954 glFogf(GL_FOG_START, (float) 0xff);
3955 checkGLcall("glFogfv GL_FOG_START");
3956 glFogf(GL_FOG_END, 0.0);
3957 checkGLcall("glFogfv GL_FOG_END");
3959 /* Disable GL fog, handle this in software in drawStridedSlow */
3961 checkGLcall("glDisable(GL_FOG)");
3965 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3968 glHint(GL_FOG_HINT, GL_NICEST);
3969 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3970 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3971 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3972 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3973 if(GL_SUPPORT(EXT_FOG_COORD)) {
3974 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3975 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3976 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3977 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3980 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3981 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3982 if(GL_SUPPORT(EXT_FOG_COORD)) {
3983 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3984 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3985 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3986 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3989 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3990 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3991 if(GL_SUPPORT(EXT_FOG_COORD)) {
3992 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3993 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3994 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3995 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3998 case D3DFOG_NONE: /* Won't happen */
3999 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4002 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4003 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4008 case WINED3DRS_FOGSTART :
4011 glFogfv(GL_FOG_START, &tmpvalue.f);
4012 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4013 TRACE("Fog Start == %f\n", tmpvalue.f);
4017 case WINED3DRS_FOGEND :
4020 glFogfv(GL_FOG_END, &tmpvalue.f);
4021 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4022 TRACE("Fog End == %f\n", tmpvalue.f);
4026 case WINED3DRS_FOGDENSITY :
4029 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4030 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4034 case WINED3DRS_VERTEXBLEND :
4036 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4037 TRACE("Vertex Blending state to %ld\n", Value);
4041 case WINED3DRS_TWEENFACTOR :
4044 This->updateStateBlock->tween_factor = tmpvalue.f;
4045 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4049 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4051 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4055 case WINED3DRS_COLORVERTEX :
4056 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4057 case WINED3DRS_SPECULARMATERIALSOURCE :
4058 case WINED3DRS_AMBIENTMATERIALSOURCE :
4059 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4061 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4063 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4064 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4065 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4066 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4067 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4068 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4070 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4071 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4072 Parm = GL_AMBIENT_AND_DIFFUSE;
4076 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4078 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4080 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4087 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4089 This->tracking_color = NEEDS_TRACKING;
4090 This->tracking_parm = Parm;
4094 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4099 case WINED3DRS_LINEPATTERN :
4105 tmppattern.d = Value;
4107 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4109 if (tmppattern.lp.wRepeatFactor) {
4110 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4111 checkGLcall("glLineStipple(repeat, linepattern)");
4112 glEnable(GL_LINE_STIPPLE);
4113 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4115 glDisable(GL_LINE_STIPPLE);
4116 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4121 case WINED3DRS_ZBIAS : /* D3D8 only */
4125 TRACE("ZBias value %f\n", tmpvalue.f);
4126 glPolygonOffset(0, -tmpvalue.f);
4127 checkGLcall("glPolygonOffset(0, -Value)");
4128 glEnable(GL_POLYGON_OFFSET_FILL);
4129 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4130 glEnable(GL_POLYGON_OFFSET_LINE);
4131 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4132 glEnable(GL_POLYGON_OFFSET_POINT);
4133 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4135 glDisable(GL_POLYGON_OFFSET_FILL);
4136 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4137 glDisable(GL_POLYGON_OFFSET_LINE);
4138 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4139 glDisable(GL_POLYGON_OFFSET_POINT);
4140 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4145 case WINED3DRS_NORMALIZENORMALS :
4147 glEnable(GL_NORMALIZE);
4148 checkGLcall("glEnable(GL_NORMALIZE);");
4150 glDisable(GL_NORMALIZE);
4151 checkGLcall("glDisable(GL_NORMALIZE);");
4155 case WINED3DRS_POINTSIZE :
4156 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4158 TRACE("Set point size to %f\n", tmpvalue.f);
4159 glPointSize(tmpvalue.f);
4160 checkGLcall("glPointSize(...);");
4163 case WINED3DRS_POINTSIZE_MIN :
4164 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4166 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4167 checkGLcall("glPointParameterfEXT(...);");
4169 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4173 case WINED3DRS_POINTSIZE_MAX :
4174 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4176 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4177 checkGLcall("glPointParameterfEXT(...);");
4179 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4183 case WINED3DRS_POINTSCALE_A :
4184 case WINED3DRS_POINTSCALE_B :
4185 case WINED3DRS_POINTSCALE_C :
4186 case WINED3DRS_POINTSCALEENABLE :
4189 * POINTSCALEENABLE controls how point size value is treated. If set to
4190 * true, the point size is scaled with respect to height of viewport.
4191 * When set to false point size is in pixels.
4193 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4196 /* Default values */
4197 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4200 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4201 * This means that OpenGL will clamp really small point sizes to 1.0f.
4202 * To correct for this we need to multiply by the scale factor when sizes
4203 * are less than 1.0f. scale_factor = 1.0f / point_size.
4205 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4206 if(pointSize > 0.0f) {
4207 GLfloat scaleFactor;
4209 if(pointSize < 1.0f) {
4210 scaleFactor = pointSize * pointSize;
4215 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4216 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4217 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4218 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4219 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4220 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4221 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4225 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4226 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4227 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4229 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4230 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4231 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4233 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4237 case WINED3DRS_COLORWRITEENABLE :
4239 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4240 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4241 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4242 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4243 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4244 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4245 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4246 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4247 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4248 checkGLcall("glColorMask(...)");
4252 case WINED3DRS_LOCALVIEWER :
4254 GLint state = (Value) ? 1 : 0;
4255 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4256 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4260 case WINED3DRS_LASTPIXEL :
4263 TRACE("Last Pixel Drawing Enabled\n");
4265 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4270 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4273 TRACE("Software Processing Enabled\n");
4275 TRACE("Software Processing Disabled\n");
4280 /** not supported */
4281 case WINED3DRS_ZVISIBLE :
4284 return WINED3DERR_INVALIDCALL;
4286 case WINED3DRS_POINTSPRITEENABLE :
4288 /* TODO: NV_POINT_SPRITE */
4289 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4290 TRACE("Point sprites not supported\n");
4295 * Point sprites are always enabled. Value controls texture coordinate
4296 * replacement mode. Must be set true for point sprites to use
4299 glEnable(GL_POINT_SPRITE_ARB);
4300 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4303 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4304 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4306 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4307 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4311 case WINED3DRS_EDGEANTIALIAS :
4314 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4316 checkGLcall("glEnable(GL_BLEND)");
4317 glEnable(GL_LINE_SMOOTH);
4318 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4320 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4321 glDisable(GL_BLEND);
4322 checkGLcall("glDisable(GL_BLEND)");
4324 glDisable(GL_LINE_SMOOTH);
4325 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4329 case WINED3DRS_WRAP0 :
4330 case WINED3DRS_WRAP1 :
4331 case WINED3DRS_WRAP2 :
4332 case WINED3DRS_WRAP3 :
4333 case WINED3DRS_WRAP4 :
4334 case WINED3DRS_WRAP5 :
4335 case WINED3DRS_WRAP6 :
4336 case WINED3DRS_WRAP7 :
4337 case WINED3DRS_WRAP8 :
4338 case WINED3DRS_WRAP9 :
4339 case WINED3DRS_WRAP10 :
4340 case WINED3DRS_WRAP11 :
4341 case WINED3DRS_WRAP12 :
4342 case WINED3DRS_WRAP13 :
4343 case WINED3DRS_WRAP14 :
4344 case WINED3DRS_WRAP15 :
4346 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4347 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4348 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4349 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4350 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4352 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4354 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4356 case WINED3DRS_MULTISAMPLEANTIALIAS :
4358 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4359 TRACE("Multisample antialiasing not supported\n");
4364 glEnable(GL_MULTISAMPLE_ARB);
4365 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4367 glDisable(GL_MULTISAMPLE_ARB);
4368 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4372 case WINED3DRS_SCISSORTESTENABLE :
4375 glEnable(GL_SCISSOR_TEST);
4376 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4378 glDisable(GL_SCISSOR_TEST);
4379 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4383 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4387 glEnable(GL_POLYGON_OFFSET_FILL);
4388 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4389 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4390 checkGLcall("glPolygonOffset(...)");
4392 glDisable(GL_POLYGON_OFFSET_FILL);
4393 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4397 case WINED3DRS_ANTIALIASEDLINEENABLE :
4400 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4402 checkGLcall("glEnable(GL_BLEND)");
4403 glEnable(GL_LINE_SMOOTH);
4404 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4406 glDisable(GL_BLEND);
4407 checkGLcall("glDisable(GL_BLEND)");
4408 glDisable(GL_LINE_SMOOTH);
4409 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4413 case WINED3DRS_DEPTHBIAS :
4417 glEnable(GL_POLYGON_OFFSET_FILL);
4418 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4419 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4420 checkGLcall("glPolygonOffset(...)");
4422 glDisable(GL_POLYGON_OFFSET_FILL);
4423 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4428 case WINED3DRS_TEXTUREPERSPECTIVE :
4431 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4433 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4437 case WINED3DRS_STIPPLEDALPHA :
4440 ERR(" Stippled Alpha not supported yet.\n");
4443 case WINED3DRS_ANTIALIAS :
4446 ERR(" Antialias not supported yet.\n");
4450 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4458 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4460 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4461 *pValue = This->stateBlock->renderState[State];
4466 * Get / Set Sampler States
4467 * TODO: Verify against dx9 definitions
4470 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 * SetSampler is designed to allow for more than the standard up to 8 textures
4474 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4475 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4477 * http://developer.nvidia.com/object/General_FAQ.html#t6
4479 * There are two new settings for GForce
4481 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4482 * and the texture one:
4483 * GL_MAX_TEXTURE_COORDS_ARB.
4484 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4486 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4487 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4488 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4489 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4490 return WINED3DERR_INVALIDCALL;
4493 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4494 debug_d3dsamplerstate(Type), Type, Value);
4495 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4496 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4497 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4499 /* Handle recording of state blocks */
4500 if (This->isRecordingState) {
4501 TRACE("Recording... not performing anything\n");
4508 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4510 /** TODO: check that sampler is in range **/
4511 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4512 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4517 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4522 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4523 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4529 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 GLint scissorBox[4];
4534 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4535 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4536 pRect->left = scissorBox[0];
4537 pRect->top = scissorBox[1];
4538 pRect->right = scissorBox[0] + scissorBox[2];
4539 pRect->bottom = scissorBox[1] + scissorBox[3];
4540 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4545 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4547 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4549 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4551 This->updateStateBlock->vertexDecl = pDecl;
4552 This->updateStateBlock->changed.vertexDecl = TRUE;
4553 This->updateStateBlock->set.vertexDecl = TRUE;
4555 if (This->isRecordingState) {
4556 TRACE("Recording... not performing anything\n");
4559 if (NULL != pDecl) {
4560 IWineD3DVertexDeclaration_AddRef(pDecl);
4562 if (NULL != oldDecl) {
4563 IWineD3DVertexDeclaration_Release(oldDecl);
4568 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4571 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4573 *ppDecl = This->stateBlock->vertexDecl;
4574 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4578 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4582 This->updateStateBlock->vertexShader = pShader;
4583 This->updateStateBlock->changed.vertexShader = TRUE;
4584 This->updateStateBlock->set.vertexShader = TRUE;
4586 if (This->isRecordingState) {
4587 TRACE("Recording... not performing anything\n");
4590 if (NULL != pShader) {
4591 IWineD3DVertexShader_AddRef(pShader);
4593 if (NULL != oldShader) {
4594 IWineD3DVertexShader_Release(oldShader);
4597 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4599 * TODO: merge HAL shaders context switching from prototype
4604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 if (NULL == ppShader) {
4608 return WINED3DERR_INVALIDCALL;
4610 *ppShader = This->stateBlock->vertexShader;
4611 if( NULL != *ppShader)
4612 IWineD3DVertexShader_AddRef(*ppShader);
4614 TRACE("(%p) : returning %p\n", This, *ppShader);
4618 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4619 IWineD3DDevice *iface,
4621 CONST BOOL *srcData,
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 int i, cnt = min(count, MAX_CONST_B - start);
4627 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4628 iface, srcData, start, count);
4630 if (srcData == NULL || cnt < 0)
4631 return WINED3DERR_INVALIDCALL;
4633 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4634 for (i = 0; i < cnt; i++)
4635 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4637 for (i = start; i < cnt + start; ++i) {
4638 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4639 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4645 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4646 IWineD3DDevice *iface,
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4652 int cnt = min(count, MAX_CONST_B - start);
4654 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4655 iface, dstData, start, count);
4657 if (dstData == NULL || cnt < 0)
4658 return WINED3DERR_INVALIDCALL;
4660 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4664 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4665 IWineD3DDevice *iface,
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 int i, cnt = min(count, MAX_CONST_I - start);
4673 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4674 iface, srcData, start, count);
4676 if (srcData == NULL || cnt < 0)
4677 return WINED3DERR_INVALIDCALL;
4679 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4680 for (i = 0; i < cnt; i++)
4681 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4682 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4684 for (i = start; i < cnt + start; ++i) {
4685 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4686 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4692 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4693 IWineD3DDevice *iface,
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 int cnt = min(count, MAX_CONST_I - start);
4701 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4702 iface, dstData, start, count);
4704 if (dstData == NULL || cnt < 0)
4705 return WINED3DERR_INVALIDCALL;
4707 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4711 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4712 IWineD3DDevice *iface,
4714 CONST float *srcData,
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4720 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4721 iface, srcData, start, count);
4723 if (srcData == NULL || cnt < 0)
4724 return WINED3DERR_INVALIDCALL;
4726 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4727 for (i = 0; i < cnt; i++)
4728 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4729 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4731 for (i = start; i < cnt + start; ++i) {
4732 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4733 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4740 IWineD3DDevice *iface,
4745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4746 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4748 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4749 iface, dstData, start, count);
4751 if (dstData == NULL || cnt < 0)
4752 return WINED3DERR_INVALIDCALL;
4754 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4758 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4761 This->updateStateBlock->pixelShader = pShader;
4762 This->updateStateBlock->changed.pixelShader = TRUE;
4763 This->updateStateBlock->set.pixelShader = TRUE;
4765 /* Handle recording of state blocks */
4766 if (This->isRecordingState) {
4767 TRACE("Recording... not performing anything\n");
4770 if (NULL != pShader) {
4771 IWineD3DPixelShader_AddRef(pShader);
4773 if (NULL != oldShader) {
4774 IWineD3DPixelShader_Release(oldShader);
4777 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4779 * TODO: merge HAL shaders context switching from prototype
4784 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4787 if (NULL == ppShader) {
4788 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4789 return WINED3DERR_INVALIDCALL;
4792 *ppShader = This->stateBlock->pixelShader;
4793 if (NULL != *ppShader) {
4794 IWineD3DPixelShader_AddRef(*ppShader);
4796 TRACE("(%p) : returning %p\n", This, *ppShader);
4800 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4801 IWineD3DDevice *iface,
4803 CONST BOOL *srcData,
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 int i, cnt = min(count, MAX_CONST_B - start);
4809 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4810 iface, srcData, start, count);
4812 if (srcData == NULL || cnt < 0)
4813 return WINED3DERR_INVALIDCALL;
4815 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4816 for (i = 0; i < cnt; i++)
4817 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4819 for (i = start; i < cnt + start; ++i) {
4820 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4821 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4827 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4828 IWineD3DDevice *iface,
4833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4834 int cnt = min(count, MAX_CONST_B - start);
4836 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4837 iface, dstData, start, count);
4839 if (dstData == NULL || cnt < 0)
4840 return WINED3DERR_INVALIDCALL;
4842 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4846 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4847 IWineD3DDevice *iface,
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 int i, cnt = min(count, MAX_CONST_I - start);
4855 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4856 iface, srcData, start, count);
4858 if (srcData == NULL || cnt < 0)
4859 return WINED3DERR_INVALIDCALL;
4861 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4862 for (i = 0; i < cnt; i++)
4863 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4864 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4866 for (i = start; i < cnt + start; ++i) {
4867 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4868 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4875 IWineD3DDevice *iface,
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4881 int cnt = min(count, MAX_CONST_I - start);
4883 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4884 iface, dstData, start, count);
4886 if (dstData == NULL || cnt < 0)
4887 return WINED3DERR_INVALIDCALL;
4889 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4893 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4894 IWineD3DDevice *iface,
4896 CONST float *srcData,
4899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4902 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4903 iface, srcData, start, count);
4905 if (srcData == NULL || cnt < 0)
4906 return WINED3DERR_INVALIDCALL;
4908 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4909 for (i = 0; i < cnt; i++)
4910 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4911 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4913 for (i = start; i < cnt + start; ++i) {
4914 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4915 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4922 IWineD3DDevice *iface,
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4928 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4930 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4931 iface, dstData, start, count);
4933 if (dstData == NULL || cnt < 0)
4934 return WINED3DERR_INVALIDCALL;
4936 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4940 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4942 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4943 char *dest_ptr, *dest_conv = NULL;
4945 DWORD DestFVF = dest->fvf;
4947 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4951 if (SrcFVF & D3DFVF_NORMAL) {
4952 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4955 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4956 ERR("Source has no position mask\n");
4957 return WINED3DERR_INVALIDCALL;
4960 /* We might access VBOs from this code, so hold the lock */
4963 if (dest->resource.allocatedMemory == NULL) {
4964 /* This may happen if we do direct locking into a vbo. Unlikely,
4965 * but theoretically possible(ddraw processvertices test)
4967 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4968 if(!dest->resource.allocatedMemory) {
4970 ERR("Out of memory\n");
4971 return E_OUTOFMEMORY;
4975 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4976 checkGLcall("glBindBufferARB");
4977 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4979 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4981 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4982 checkGLcall("glUnmapBufferARB");
4986 /* Get a pointer into the destination vbo(create one if none exists) and
4987 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4989 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4994 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4995 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4997 ERR("glMapBuffer failed\n");
4998 /* Continue without storing converted vertices */
5003 * a) D3DRS_CLIPPING is enabled
5004 * b) WINED3DVOP_CLIP is passed
5006 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5007 static BOOL warned = FALSE;
5009 * The clipping code is not quite correct. Some things need
5010 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5011 * so disable clipping for now.
5012 * (The graphics in Half-Life are broken, and my processvertices
5013 * test crashes with IDirect3DDevice3)
5019 FIXME("Clipping is broken and disabled for now\n");
5021 } else doClip = FALSE;
5022 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5024 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5027 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5030 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5031 WINED3DTS_PROJECTION,
5033 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5034 WINED3DTS_WORLDMATRIX(0),
5037 TRACE("View mat:\n");
5038 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); \
5039 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); \
5040 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); \
5041 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); \
5043 TRACE("Proj mat:\n");
5044 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); \
5045 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); \
5046 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); \
5047 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); \
5049 TRACE("World mat:\n");
5050 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); \
5051 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); \
5052 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); \
5053 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); \
5055 /* Get the viewport */
5056 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5057 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5058 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5060 multiply_matrix(&mat,&view_mat,&world_mat);
5061 multiply_matrix(&mat,&proj_mat,&mat);
5063 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5065 for (i = 0; i < dwCount; i+= 1) {
5066 unsigned int tex_index;
5068 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5069 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5070 /* The position first */
5072 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5074 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5076 /* Multiplication with world, view and projection matrix */
5077 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);
5078 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);
5079 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);
5080 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);
5082 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5084 /* WARNING: The following things are taken from d3d7 and were not yet checked
5085 * against d3d8 or d3d9!
5088 /* Clipping conditions: From
5089 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5091 * A vertex is clipped if it does not match the following requirements
5095 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5097 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5098 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5102 if( doClip == FALSE ||
5103 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5104 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5107 /* "Normal" viewport transformation (not clipped)
5108 * 1) The values are divided by rhw
5109 * 2) The y axis is negative, so multiply it with -1
5110 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5111 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5112 * 4) Multiply x with Width/2 and add Width/2
5113 * 5) The same for the height
5114 * 6) Add the viewpoint X and Y to the 2D coordinates and
5115 * The minimum Z value to z
5116 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5118 * Well, basically it's simply a linear transformation into viewport
5130 z *= vp.MaxZ - vp.MinZ;
5132 x += vp.Width / 2 + vp.X;
5133 y += vp.Height / 2 + vp.Y;
5138 /* That vertex got clipped
5139 * Contrary to OpenGL it is not dropped completely, it just
5140 * undergoes a different calculation.
5142 TRACE("Vertex got clipped\n");
5149 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5150 * outside of the main vertex buffer memory. That needs some more
5155 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5158 ( (float *) dest_ptr)[0] = x;
5159 ( (float *) dest_ptr)[1] = y;
5160 ( (float *) dest_ptr)[2] = z;
5161 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5163 dest_ptr += 3 * sizeof(float);
5165 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5166 dest_ptr += sizeof(float);
5171 ( (float *) dest_conv)[0] = x * w;
5172 ( (float *) dest_conv)[1] = y * w;
5173 ( (float *) dest_conv)[2] = z * w;
5174 ( (float *) dest_conv)[3] = w;
5176 dest_conv += 3 * sizeof(float);
5178 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5179 dest_conv += sizeof(float);
5183 if (DestFVF & D3DFVF_PSIZE) {
5184 dest_ptr += sizeof(DWORD);
5185 if(dest_conv) dest_conv += sizeof(DWORD);
5187 if (DestFVF & D3DFVF_NORMAL) {
5189 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5190 /* AFAIK this should go into the lighting information */
5191 FIXME("Didn't expect the destination to have a normal\n");
5192 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5194 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5198 if (DestFVF & D3DFVF_DIFFUSE) {
5200 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5202 static BOOL warned = FALSE;
5204 if(warned == FALSE) {
5205 ERR("No diffuse color in source, but destination has one\n");
5209 *( (DWORD *) dest_ptr) = 0xffffffff;
5210 dest_ptr += sizeof(DWORD);
5213 *( (DWORD *) dest_conv) = 0xffffffff;
5214 dest_conv += sizeof(DWORD);
5218 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5220 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5221 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5222 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5223 dest_conv += sizeof(DWORD);
5228 if (DestFVF & D3DFVF_SPECULAR) {
5229 /* What's the color value in the feedback buffer? */
5231 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5233 static BOOL warned = FALSE;
5235 if(warned == FALSE) {
5236 ERR("No specular color in source, but destination has one\n");
5240 *( (DWORD *) dest_ptr) = 0xFF000000;
5241 dest_ptr += sizeof(DWORD);
5244 *( (DWORD *) dest_conv) = 0xFF000000;
5245 dest_conv += sizeof(DWORD);
5249 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5251 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5252 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5253 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5254 dest_conv += sizeof(DWORD);
5259 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5261 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5262 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5264 ERR("No source texture, but destination requests one\n");
5265 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5266 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5269 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5271 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5278 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5279 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5286 #undef copy_and_next
5288 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5290 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5291 WineDirect3DVertexStridedData strided;
5292 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5294 /* We don't need the source vbo because this buffer is only used as
5295 * a source for ProcessVertices. Avoid wasting resources by converting the
5296 * buffer and loading the VBO
5299 TRACE("Releaseing the source vbo, it won't be needed\n");
5301 if(!SrcImpl->resource.allocatedMemory) {
5302 /* Rescue the data from the buffer */
5304 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5305 if(!SrcImpl->resource.allocatedMemory) {
5306 ERR("Out of memory\n");
5307 return E_OUTOFMEMORY;
5311 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5312 checkGLcall("glBindBufferARB");
5314 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5316 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5319 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5320 checkGLcall("glUnmapBufferARB");
5325 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5326 checkGLcall("glBindBufferARB");
5327 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5328 checkGLcall("glDeleteBuffersARB");
5334 memset(&strided, 0, sizeof(strided));
5335 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5337 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5341 * Apply / Get / Set Texture Stage States
5342 * TODO: Verify against dx9 definitions
5345 /* 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 */
5346 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5348 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5349 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5351 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5353 /* Check that the stage is within limits */
5354 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5355 TRACE("Attempt to access invalid texture rejected\n");
5362 case WINED3DTSS_ALPHAOP :
5363 case WINED3DTSS_COLOROP :
5364 /* nothing to do as moved to drawprim for now */
5366 case WINED3DTSS_ADDRESSW :
5367 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5368 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5369 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5372 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5373 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5374 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5375 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5378 case WINED3DTSS_TEXCOORDINDEX :
5380 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5382 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5383 one flag, you can still specify an index value, which the system uses to
5384 determine the texture wrapping mode.
5385 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5386 means use the vertex position (camera-space) as the input texture coordinates
5387 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5388 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5389 to the TEXCOORDINDEX value */
5392 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5394 switch (Value & 0xFFFF0000) {
5395 case D3DTSS_TCI_PASSTHRU:
5396 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5397 glDisable(GL_TEXTURE_GEN_S);
5398 glDisable(GL_TEXTURE_GEN_T);
5399 glDisable(GL_TEXTURE_GEN_R);
5400 glDisable(GL_TEXTURE_GEN_Q);
5401 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5404 case D3DTSS_TCI_CAMERASPACEPOSITION:
5405 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5406 as the input texture coordinates for this stage's texture transformation. This
5407 equates roughly to EYE_LINEAR */
5409 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5410 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5411 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5412 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5413 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5415 glMatrixMode(GL_MODELVIEW);
5418 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5419 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5420 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5421 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5424 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5425 glEnable(GL_TEXTURE_GEN_S);
5426 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5427 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5428 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5429 glEnable(GL_TEXTURE_GEN_T);
5430 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5431 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5432 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5433 glEnable(GL_TEXTURE_GEN_R);
5434 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5435 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5436 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5440 case D3DTSS_TCI_CAMERASPACENORMAL:
5442 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5443 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5444 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5445 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5446 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5447 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5449 glMatrixMode(GL_MODELVIEW);
5452 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5453 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5454 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5455 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5458 glEnable(GL_TEXTURE_GEN_S);
5459 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5460 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5461 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5462 glEnable(GL_TEXTURE_GEN_T);
5463 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5464 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5465 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5466 glEnable(GL_TEXTURE_GEN_R);
5467 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5468 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5469 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5474 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5476 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5477 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5478 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5479 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5480 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5481 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5483 glMatrixMode(GL_MODELVIEW);
5486 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5487 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5488 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5489 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5492 glEnable(GL_TEXTURE_GEN_S);
5493 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5494 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5495 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5496 glEnable(GL_TEXTURE_GEN_T);
5497 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5498 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5499 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5500 glEnable(GL_TEXTURE_GEN_R);
5501 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5502 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5503 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5508 /* Unhandled types: */
5511 /* ? disable GL_TEXTURE_GEN_n ? */
5512 glDisable(GL_TEXTURE_GEN_S);
5513 glDisable(GL_TEXTURE_GEN_T);
5514 glDisable(GL_TEXTURE_GEN_R);
5515 glDisable(GL_TEXTURE_GEN_Q);
5516 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5523 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5524 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5527 case WINED3DTSS_BUMPENVMAT00 :
5528 case WINED3DTSS_BUMPENVMAT01 :
5529 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5531 case WINED3DTSS_BUMPENVMAT10 :
5532 case WINED3DTSS_BUMPENVMAT11 :
5533 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5536 case WINED3DTSS_BUMPENVLSCALE :
5537 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5540 case WINED3DTSS_BUMPENVLOFFSET :
5541 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5544 case WINED3DTSS_RESULTARG :
5545 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5549 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5550 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5559 * Get / Set Texture Stage States
5560 * TODO: Verify against dx9 definitions
5562 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5565 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5567 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5569 /* Reject invalid texture units */
5570 if (Stage >= GL_LIMITS(texture_stages)) {
5571 TRACE("Attempt to access invalid texture rejected\n");
5572 return WINED3DERR_INVALIDCALL;
5575 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5576 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5577 This->updateStateBlock->textureState[Stage][Type] = Value;
5582 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5584 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5585 *pValue = This->updateStateBlock->textureState[Stage][Type];
5592 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 IWineD3DBaseTexture *oldTexture;
5597 oldTexture = This->updateStateBlock->textures[Stage];
5598 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5600 #if 0 /* TODO: check so vertex textures */
5601 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5602 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5607 /* Reject invalid texture units */
5608 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5609 WARN("Attempt to access invalid texture rejected\n");
5610 return WINED3DERR_INVALIDCALL;
5613 if(pTexture != NULL) {
5614 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5616 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5617 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5618 return WINED3DERR_INVALIDCALL;
5622 oldTexture = This->updateStateBlock->textures[Stage];
5623 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5624 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5626 This->updateStateBlock->set.textures[Stage] = TRUE;
5627 This->updateStateBlock->changed.textures[Stage] = TRUE;
5628 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5629 This->updateStateBlock->textures[Stage] = pTexture;
5631 /* Handle recording of state blocks */
5632 if (This->isRecordingState) {
5633 TRACE("Recording... not performing anything\n");
5637 /** NOTE: MSDN says that setTexture increases the reference count,
5638 * and the the application nust set the texture back to null (or have a leaky application),
5639 * This means we should pass the refcount up to the parent
5640 *******************************/
5641 if (NULL != This->updateStateBlock->textures[Stage]) {
5642 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5645 if (NULL != oldTexture) {
5646 IWineD3DBaseTexture_Release(oldTexture);
5649 /* Reset color keying */
5650 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5651 BOOL enable_ckey = FALSE;
5654 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5655 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5659 glAlphaFunc(GL_NOTEQUAL, 0.0);
5660 checkGLcall("glAlphaFunc");
5667 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5671 /* Reject invalid texture units */
5672 if (Stage >= GL_LIMITS(sampler_stages)) {
5673 TRACE("Attempt to access invalid texture rejected\n");
5674 return WINED3DERR_INVALIDCALL;
5676 *ppTexture=This->updateStateBlock->textures[Stage];
5678 IWineD3DBaseTexture_AddRef(*ppTexture);
5680 return WINED3DERR_INVALIDCALL;
5687 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5688 IWineD3DSurface **ppBackBuffer) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 IWineD3DSwapChain *swapChain;
5693 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5695 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5696 if (hr == WINED3D_OK) {
5697 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5698 IWineD3DSwapChain_Release(swapChain);
5700 *ppBackBuffer = NULL;
5705 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 WARN("(%p) : stub, calling idirect3d for now\n", This);
5708 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5711 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 IWineD3DSwapChain *swapChain;
5716 if(iSwapChain > 0) {
5717 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5718 if (hr == WINED3D_OK) {
5719 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5720 IWineD3DSwapChain_Release(swapChain);
5722 FIXME("(%p) Error getting display mode\n", This);
5725 /* Don't read the real display mode,
5726 but return the stored mode instead. X11 can't change the color
5727 depth, and some apps are pretty angry if they SetDisplayMode from
5728 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5730 Also don't relay to the swapchain because with ddraw it's possible
5731 that there isn't a swapchain at all */
5732 pMode->Width = This->ddraw_width;
5733 pMode->Height = This->ddraw_height;
5734 pMode->Format = This->ddraw_format;
5735 pMode->RefreshRate = 0;
5742 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 TRACE("(%p)->(%p)\n", This, hWnd);
5746 This->ddraw_window = hWnd;
5750 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 TRACE("(%p)->(%p)\n", This, hWnd);
5754 *hWnd = This->ddraw_window;
5759 * Stateblock related functions
5762 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 IWineD3DStateBlockImpl *object;
5765 HRESULT temp_result;
5767 TRACE("(%p)", This);
5769 if (This->isRecordingState) {
5770 return WINED3DERR_INVALIDCALL;
5773 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5774 if (NULL == object ) {
5775 FIXME("(%p)Error allocating memory for stateblock\n", This);
5776 return E_OUTOFMEMORY;
5778 TRACE("(%p) created object %p\n", This, object);
5779 object->wineD3DDevice= This;
5780 /** FIXME: object->parent = parent; **/
5781 object->parent = NULL;
5782 object->blockType = WINED3DSBT_ALL;
5784 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5786 temp_result = allocate_shader_constants(object);
5787 if (WINED3D_OK != temp_result)
5790 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5791 This->updateStateBlock = object;
5792 This->isRecordingState = TRUE;
5794 TRACE("(%p) recording stateblock %p\n",This , object);
5798 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 if (!This->isRecordingState) {
5802 FIXME("(%p) not recording! returning error\n", This);
5803 *ppStateBlock = NULL;
5804 return WINED3DERR_INVALIDCALL;
5807 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5808 This->isRecordingState = FALSE;
5809 This->updateStateBlock = This->stateBlock;
5810 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5811 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5812 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5817 * Scene related functions
5819 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5820 /* At the moment we have no need for any functionality at the beginning
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5823 TRACE("(%p) : stub\n", This);
5827 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5829 TRACE("(%p)\n", This);
5831 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5833 checkGLcall("glFlush");
5835 TRACE("End Scene\n");
5836 if(This->renderTarget != NULL) {
5838 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5839 IUnknown *targetContainer = NULL;
5840 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5841 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5842 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5843 /** always dirtify for now. we must find a better way to see that surface have been modified
5844 (Modifications should will only occur via draw-primitive, but we do need better locking
5845 switching to render-to-texture should remove the overhead though.
5847 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5848 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5849 IWineD3DSurface_PreLoad(This->renderTarget);
5850 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5851 IUnknown_Release(targetContainer);
5854 This->sceneEnded = TRUE;
5859 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5860 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5861 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 IWineD3DSwapChain *swapChain = NULL;
5865 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5867 TRACE("(%p) Presenting the frame\n", This);
5869 for(i = 0 ; i < swapchains ; i ++) {
5871 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5872 TRACE("presentinng chain %d, %p\n", i, swapChain);
5873 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5874 IWineD3DSwapChain_Release(swapChain);
5880 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5881 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5884 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5885 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5886 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5887 GLbitfield glMask = 0;
5888 GLboolean old_ztest;
5889 GLfloat old_z_clear_value;
5890 GLint old_stencil_clear_value;
5891 GLfloat old_color_clear_value[4];
5893 CONST D3DRECT* curRect;
5895 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5896 Count, pRects, Flags, Z, Stencil);
5900 glEnable(GL_SCISSOR_TEST);
5901 checkGLcall("glEnable GL_SCISSOR_TEST");
5903 if (Count > 0 && pRects) {
5909 /* Only set the values up once, as they are not changing */
5910 if (Flags & D3DCLEAR_STENCIL) {
5911 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5912 glClearStencil(Stencil);
5913 checkGLcall("glClearStencil");
5914 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5915 glStencilMask(0xFFFFFFFF);
5918 if (Flags & D3DCLEAR_ZBUFFER) {
5919 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5920 glDepthMask(GL_TRUE);
5921 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5923 checkGLcall("glClearDepth");
5924 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5927 if (Flags & D3DCLEAR_TARGET) {
5928 TRACE("Clearing screen with glClear to color %lx\n", Color);
5929 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5930 glClearColor(D3DCOLOR_R(Color),
5934 checkGLcall("glClearColor");
5936 /* Clear ALL colors! */
5937 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5938 glMask = glMask | GL_COLOR_BUFFER_BIT;
5941 /* Now process each rect in turn */
5942 for (i = 0; i < Count || i == 0; i++) {
5945 /* Note gl uses lower left, width/height */
5946 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5947 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5948 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5949 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5950 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5951 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5952 checkGLcall("glScissor");
5954 glScissor(This->stateBlock->viewport.X,
5955 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5956 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5957 This->stateBlock->viewport.Width,
5958 This->stateBlock->viewport.Height);
5959 checkGLcall("glScissor");
5962 /* Clear the selected rectangle (or full screen) */
5964 checkGLcall("glClear");
5966 /* Step to the next rectangle */
5967 if (curRect) curRect = curRect + sizeof(D3DRECT);
5970 /* Restore the old values (why..?) */
5971 if (Flags & D3DCLEAR_STENCIL) {
5972 glClearStencil(old_stencil_clear_value);
5973 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5975 if (Flags & D3DCLEAR_ZBUFFER) {
5976 glDepthMask(old_ztest);
5977 glClearDepth(old_z_clear_value);
5979 if (Flags & D3DCLEAR_TARGET) {
5980 glClearColor(old_color_clear_value[0],
5981 old_color_clear_value[1],
5982 old_color_clear_value[2],
5983 old_color_clear_value[3]);
5984 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5985 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5986 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5987 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5990 glDisable(GL_SCISSOR_TEST);
5991 checkGLcall("glDisable");
6000 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6001 UINT PrimitiveCount) {
6003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6004 This->stateBlock->streamIsUP = FALSE;
6006 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6007 debug_d3dprimitivetype(PrimitiveType),
6008 StartVertex, PrimitiveCount);
6009 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6010 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6016 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6017 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6018 D3DPRIMITIVETYPE PrimitiveType,
6019 INT baseVIndex, UINT minIndex,
6020 UINT NumVertices, UINT startIndex, UINT primCount) {
6022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6024 IWineD3DIndexBuffer *pIB;
6025 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6027 pIB = This->stateBlock->pIndexData;
6028 This->stateBlock->streamIsUP = FALSE;
6030 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6031 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6032 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6034 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6035 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6041 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6042 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6047 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6048 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6049 UINT VertexStreamZeroStride) {
6050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6052 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6053 debug_d3dprimitivetype(PrimitiveType),
6054 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6056 /* release the stream source */
6057 if (This->stateBlock->streamSource[0] != NULL) {
6058 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6061 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6062 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6063 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6064 This->stateBlock->streamIsUP = TRUE;
6066 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6067 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6069 /* MSDN specifies stream zero settings must be set to NULL */
6070 This->stateBlock->streamStride[0] = 0;
6071 This->stateBlock->streamSource[0] = NULL;
6073 /*stream zero settings set to null at end, as per the msdn */
6077 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6078 UINT MinVertexIndex, UINT NumVertices,
6079 UINT PrimitiveCount, CONST void* pIndexData,
6080 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6081 UINT VertexStreamZeroStride) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6085 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6086 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6087 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6088 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6090 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6096 /* release the stream and index data */
6097 if (This->stateBlock->streamSource[0] != NULL) {
6098 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6100 if (This->stateBlock->pIndexData) {
6101 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6104 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6105 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6106 This->stateBlock->streamIsUP = TRUE;
6107 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6109 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6111 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6112 This->stateBlock->streamSource[0] = NULL;
6113 This->stateBlock->streamStride[0] = 0;
6114 This->stateBlock->pIndexData = NULL;
6119 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6121 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6124 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6125 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6127 HRESULT hr = WINED3D_OK;
6128 WINED3DRESOURCETYPE sourceType;
6129 WINED3DRESOURCETYPE destinationType;
6132 /* TODO: think about moving the code into IWineD3DBaseTexture */
6134 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6136 /* verify that the source and destination textures aren't NULL */
6137 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6138 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6139 This, pSourceTexture, pDestinationTexture);
6140 hr = WINED3DERR_INVALIDCALL;
6143 if (pSourceTexture == pDestinationTexture) {
6144 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6145 This, pSourceTexture, pDestinationTexture);
6146 hr = WINED3DERR_INVALIDCALL;
6148 /* Verify that the source and destination textures are the same type */
6149 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6150 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6152 if (sourceType != destinationType) {
6153 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6155 hr = WINED3DERR_INVALIDCALL;
6158 /* check that both textures have the identical numbers of levels */
6159 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6160 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6161 hr = WINED3DERR_INVALIDCALL;
6164 if (WINED3D_OK == hr) {
6166 /* Make sure that the destination texture is loaded */
6167 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6169 /* Update every surface level of the texture */
6170 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6172 switch (sourceType) {
6173 case WINED3DRTYPE_TEXTURE:
6175 IWineD3DSurface *srcSurface;
6176 IWineD3DSurface *destSurface;
6178 for (i = 0 ; i < levels ; ++i) {
6179 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6180 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6181 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6182 IWineD3DSurface_Release(srcSurface);
6183 IWineD3DSurface_Release(destSurface);
6184 if (WINED3D_OK != hr) {
6185 WARN("(%p) : Call to update surface failed\n", This);
6191 case WINED3DRTYPE_CUBETEXTURE:
6193 IWineD3DSurface *srcSurface;
6194 IWineD3DSurface *destSurface;
6195 WINED3DCUBEMAP_FACES faceType;
6197 for (i = 0 ; i < levels ; ++i) {
6198 /* Update each cube face */
6199 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6200 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6201 if (WINED3D_OK != hr) {
6202 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6204 TRACE("Got srcSurface %p\n", srcSurface);
6206 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6207 if (WINED3D_OK != hr) {
6208 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6210 TRACE("Got desrSurface %p\n", destSurface);
6212 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6213 IWineD3DSurface_Release(srcSurface);
6214 IWineD3DSurface_Release(destSurface);
6215 if (WINED3D_OK != hr) {
6216 WARN("(%p) : Call to update surface failed\n", This);
6223 #if 0 /* TODO: Add support for volume textures */
6224 case WINED3DRTYPE_VOLUMETEXTURE:
6226 IWineD3DVolume srcVolume = NULL;
6227 IWineD3DSurface destVolume = NULL;
6229 for (i = 0 ; i < levels ; ++i) {
6230 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6231 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6232 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6233 IWineD3DVolume_Release(srcSurface);
6234 IWineD3DVolume_Release(destSurface);
6235 if (WINED3D_OK != hr) {
6236 WARN("(%p) : Call to update volume failed\n", This);
6244 FIXME("(%p) : Unsupported source and destination type\n", This);
6245 hr = WINED3DERR_INVALIDCALL;
6252 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6253 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6254 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6257 TRACE("(%p) : stub\n", This);
6260 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6262 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6263 * NOTE It may be best to move the code into surface to occomplish this
6264 ****************************************/
6266 WINED3DSURFACE_DESC surfaceDesc;
6267 unsigned int surfaceWidth, surfaceHeight;
6268 glDescriptor *targetGlDescription = NULL;
6269 glDescriptor *surfaceGlDescription = NULL;
6270 IWineD3DSwapChainImpl *container = NULL;
6272 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6273 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6274 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6276 surfaceDesc.Width = &surfaceWidth;
6277 surfaceDesc.Height = &surfaceHeight;
6278 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6279 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6281 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6282 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6284 /* TODO: opengl Context switching for swapchains etc... */
6285 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6286 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6287 glReadBuffer(GL_BACK);
6288 vcheckGLcall("glReadBuffer(GL_BACK)");
6289 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6290 glReadBuffer(GL_FRONT);
6291 vcheckGLcall("glReadBuffer(GL_FRONT)");
6292 } else if (pRenderTarget == This->depthStencilBuffer) {
6293 FIXME("Reading of depthstencil not yet supported\n");
6296 glReadPixels(surfaceGlDescription->target,
6297 surfaceGlDescription->level,
6300 surfaceGlDescription->glFormat,
6301 surfaceGlDescription->glType,
6302 (void *)IWineD3DSurface_GetData(pSurface));
6303 vcheckGLcall("glReadPixels(...)");
6304 if(NULL != container ){
6305 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6308 IWineD3DBaseTexture *container;
6309 GLenum textureDimensions = GL_TEXTURE_2D;
6311 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6312 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6313 IWineD3DBaseTexture_Release(container);
6315 /* TODO: 2D -> Cube surface coppies etc.. */
6316 if (surfaceGlDescription->target != textureDimensions) {
6317 FIXME("(%p) : Texture dimension mismatch\n", This);
6319 glEnable(textureDimensions);
6320 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6321 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6322 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6323 vcheckGLcall("glBindTexture");
6324 glGetTexImage(surfaceGlDescription->target,
6325 surfaceGlDescription->level,
6326 surfaceGlDescription->glFormat,
6327 surfaceGlDescription->glType,
6328 (void *)IWineD3DSurface_GetData(pSurface));
6329 glDisable(textureDimensions);
6330 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6337 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6338 IWineD3DSwapChain *swapChain;
6340 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6341 if(hr == WINED3D_OK) {
6342 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6343 IWineD3DSwapChain_Release(swapChain);
6348 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6350 /* return a sensible default */
6352 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6353 FIXME("(%p) : stub\n", This);
6357 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6360 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6361 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6362 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6363 return WINED3DERR_INVALIDCALL;
6365 for (j = 0; j < 256; ++j) {
6366 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6367 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6368 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6369 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6371 TRACE("(%p) : returning\n", This);
6375 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6378 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6379 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6380 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6381 return WINED3DERR_INVALIDCALL;
6383 for (j = 0; j < 256; ++j) {
6384 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6385 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6386 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6387 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6389 TRACE("(%p) : returning\n", This);
6393 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6395 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6396 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6397 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6398 return WINED3DERR_INVALIDCALL;
6400 /*TODO: stateblocks */
6401 This->currentPalette = PaletteNumber;
6402 TRACE("(%p) : returning\n", This);
6406 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6408 if (PaletteNumber == NULL) {
6409 WARN("(%p) : returning Invalid Call\n", This);
6410 return WINED3DERR_INVALIDCALL;
6412 /*TODO: stateblocks */
6413 *PaletteNumber = This->currentPalette;
6414 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6418 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 static BOOL showFixmes = TRUE;
6422 FIXME("(%p) : stub\n", This);
6426 This->softwareVertexProcessing = bSoftware;
6431 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6433 static BOOL showFixmes = TRUE;
6435 FIXME("(%p) : stub\n", This);
6438 return This->softwareVertexProcessing;
6442 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6444 IWineD3DSwapChain *swapChain;
6447 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6449 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6450 if(hr == WINED3D_OK){
6451 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6452 IWineD3DSwapChain_Release(swapChain);
6454 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6460 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6462 static BOOL showfixmes = TRUE;
6463 if(nSegments != 0.0f) {
6465 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6472 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 static BOOL showfixmes = TRUE;
6476 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6482 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6484 /** TODO: remove casts to IWineD3DSurfaceImpl
6485 * NOTE: move code to surface to accomplish this
6486 ****************************************/
6487 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6488 int srcWidth, srcHeight;
6489 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6490 WINED3DFORMAT destFormat, srcFormat;
6492 int destLeft, destTop;
6493 WINED3DPOOL srcPool, destPool;
6495 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6496 glDescriptor *glDescription = NULL;
6497 GLenum textureDimensions = GL_TEXTURE_2D;
6498 IWineD3DBaseTexture *baseTexture;
6500 WINED3DSURFACE_DESC winedesc;
6502 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6503 memset(&winedesc, 0, sizeof(winedesc));
6504 winedesc.Width = &srcSurfaceWidth;
6505 winedesc.Height = &srcSurfaceHeight;
6506 winedesc.Pool = &srcPool;
6507 winedesc.Format = &srcFormat;
6509 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6511 winedesc.Width = &destSurfaceWidth;
6512 winedesc.Height = &destSurfaceHeight;
6513 winedesc.Pool = &destPool;
6514 winedesc.Format = &destFormat;
6515 winedesc.Size = &destSize;
6517 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6519 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6520 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6521 return WINED3DERR_INVALIDCALL;
6524 if (destFormat == WINED3DFMT_UNKNOWN) {
6525 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6526 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6528 /* Get the update surface description */
6529 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6532 /* Make sure the surface is loaded and up to date */
6533 IWineD3DSurface_PreLoad(pDestinationSurface);
6535 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6539 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6540 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6541 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6542 destLeft = pDestPoint ? pDestPoint->x : 0;
6543 destTop = pDestPoint ? pDestPoint->y : 0;
6546 /* This function doesn't support compressed textures
6547 the pitch is just bytesPerPixel * width */
6548 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6549 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6550 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6551 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6553 /* TODO DXT formats */
6555 if(pSourceRect != NULL && pSourceRect->top != 0){
6556 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6558 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6560 ,glDescription->level
6565 ,glDescription->glFormat
6566 ,glDescription->glType
6567 ,IWineD3DSurface_GetData(pSourceSurface)
6571 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6573 /* need to lock the surface to get the data */
6574 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6577 /* TODO: Cube and volume support */
6579 /* not a whole row so we have to do it a line at a time */
6582 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6583 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6585 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6587 glTexSubImage2D(glDescription->target
6588 ,glDescription->level
6593 ,glDescription->glFormat
6594 ,glDescription->glType
6595 ,data /* could be quicker using */
6600 } else { /* Full width, so just write out the whole texture */
6602 if (WINED3DFMT_DXT1 == destFormat ||
6603 WINED3DFMT_DXT2 == destFormat ||
6604 WINED3DFMT_DXT3 == destFormat ||
6605 WINED3DFMT_DXT4 == destFormat ||
6606 WINED3DFMT_DXT5 == destFormat) {
6607 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6608 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6609 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6610 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6611 } if (destFormat != srcFormat) {
6612 FIXME("Updating mixed format compressed texture is not curretly support\n");
6614 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6615 glDescription->level,
6616 glDescription->glFormatInternal,
6621 IWineD3DSurface_GetData(pSourceSurface));
6624 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6629 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6631 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6632 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6633 data returned by GetData non-power2 width/height with hardware non-power2
6634 pow2Width/height are set to surface width height, repacking isn't needed so it
6635 doesn't matter which function gets called. */
6636 glTexSubImage2D(glDescription->target
6637 ,glDescription->level
6642 ,glDescription->glFormat
6643 ,glDescription->glType
6644 ,IWineD3DSurface_GetData(pSourceSurface)
6648 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6649 glTexSubImage2D(glDescription->target
6650 ,glDescription->level
6653 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6654 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6655 ,glDescription->glFormat
6656 ,glDescription->glType
6657 ,IWineD3DSurface_GetData(pSourceSurface)
6663 checkGLcall("glTexSubImage2D");
6665 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6666 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6667 * surface bigger than it needs to be hmm.. */
6668 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6669 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6670 IWineD3DBaseTexture_Release(baseTexture);
6673 glDisable(textureDimensions); /* This needs to be managed better.... */
6679 /* Used by DirectX 8 */
6680 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6681 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6682 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6685 HRESULT hr = WINED3D_OK;
6686 WINED3DFORMAT srcFormat, destFormat;
6687 UINT srcWidth, destWidth;
6688 UINT srcHeight, destHeight;
6690 WINED3DSURFACE_DESC winedesc;
6692 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6693 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6696 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6697 memset(&winedesc, 0, sizeof(winedesc));
6699 winedesc.Format = &srcFormat;
6700 winedesc.Width = &srcWidth;
6701 winedesc.Height = &srcHeight;
6702 winedesc.Size = &srcSize;
6703 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6705 winedesc.Format = &destFormat;
6706 winedesc.Width = &destWidth;
6707 winedesc.Height = &destHeight;
6708 winedesc.Size = NULL;
6709 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6711 /* Check that the source and destination formats match */
6712 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6713 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6714 return WINED3DERR_INVALIDCALL;
6715 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6716 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6717 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6718 destFormat = srcFormat;
6721 /* Quick if complete copy ... */
6722 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6724 if (srcWidth == destWidth && srcHeight == destHeight) {
6725 WINED3DLOCKED_RECT lrSrc;
6726 WINED3DLOCKED_RECT lrDst;
6727 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6728 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6729 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6731 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6733 IWineD3DSurface_UnlockRect(pSourceSurface);
6734 IWineD3DSurface_UnlockRect(pDestinationSurface);
6735 TRACE("Unlocked src and dst\n");
6739 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6740 hr = WINED3DERR_INVALIDCALL;
6745 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6747 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6750 /* Copy rect by rect */
6751 for (i = 0; i < cRects; ++i) {
6752 CONST RECT* r = &pSourceRectsArray[i];
6753 CONST POINT* p = &pDestPointsArray[i];
6756 WINED3DLOCKED_RECT lrSrc;
6757 WINED3DLOCKED_RECT lrDst;
6760 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6761 if (srcFormat == WINED3DFMT_DXT1) {
6762 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6764 copyperline = ((r->right - r->left) * bytesPerPixel);
6767 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6768 dest_rect.left = p->x;
6769 dest_rect.top = p->y;
6770 dest_rect.right = p->x + (r->right - r->left);
6771 dest_rect.bottom= p->y + (r->bottom - r->top);
6772 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6773 TRACE("Locked src and dst\n");
6775 /* Find where to start */
6776 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6777 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6779 IWineD3DSurface_UnlockRect(pSourceSurface);
6780 IWineD3DSurface_UnlockRect(pDestinationSurface);
6781 TRACE("Unlocked src and dst\n");
6784 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6785 hr = WINED3DERR_INVALIDCALL;
6792 /* Implementation details at http://developer.nvidia.com/attach/6494
6794 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6795 hmm.. no longer supported use
6796 OpenGL evaluators or tessellate surfaces within your application.
6799 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6800 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6802 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6803 FIXME("(%p) : Stub\n", This);
6808 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6809 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6811 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6812 FIXME("(%p) : Stub\n", This);
6816 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6818 TRACE("(%p) Handle(%d)\n", This, Handle);
6819 FIXME("(%p) : Stub\n", This);
6823 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6825 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6827 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6829 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6830 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6831 return WINED3DERR_INVALIDCALL;
6834 /* Just forward this to the DirectDraw blitting engine */
6835 memset(&BltFx, 0, sizeof(BltFx));
6836 BltFx.dwSize = sizeof(BltFx);
6837 BltFx.u5.dwFillColor = color;
6838 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6841 /* rendertarget and deptth stencil functions */
6842 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6845 /* FIXME: Implelent RenderTargetIndex >0 */
6846 if(RenderTargetIndex > 0)
6847 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6849 *ppRenderTarget = This->renderTarget;
6850 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6851 /* Note inc ref on returned surface */
6852 if(*ppRenderTarget != NULL)
6853 IWineD3DSurface_AddRef(*ppRenderTarget);
6857 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6859 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6860 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6861 IWineD3DSwapChainImpl *Swapchain;
6864 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6866 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6867 if(hr != WINED3D_OK) {
6868 ERR("Can't get the swapchain\n");
6872 /* Make sure to release the swapchain */
6873 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6875 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6876 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6877 return WINED3DERR_INVALIDCALL;
6879 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6880 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6881 return WINED3DERR_INVALIDCALL;
6884 if(Swapchain->frontBuffer != Front) {
6885 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6887 if(Swapchain->frontBuffer)
6888 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6889 Swapchain->frontBuffer = Front;
6891 if(Swapchain->frontBuffer) {
6892 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6896 if(Back && !Swapchain->backBuffer) {
6897 /* We need memory for the back buffer array - only one back buffer this way */
6898 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6899 if(!Swapchain->backBuffer) {
6900 ERR("Out of memory\n");
6901 return E_OUTOFMEMORY;
6905 if(Swapchain->backBuffer[0] != Back) {
6906 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6908 if(!Swapchain->backBuffer[0]) {
6909 /* GL was told to draw to the front buffer at creation,
6912 glDrawBuffer(GL_BACK);
6913 checkGLcall("glDrawBuffer(GL_BACK)");
6914 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6915 Swapchain->presentParms.BackBufferCount = 1;
6917 /* That makes problems - disable for now */
6918 /* glDrawBuffer(GL_FRONT); */
6919 checkGLcall("glDrawBuffer(GL_FRONT)");
6920 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6921 Swapchain->presentParms.BackBufferCount = 0;
6925 if(Swapchain->backBuffer[0])
6926 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6927 Swapchain->backBuffer[0] = Back;
6929 if(Swapchain->backBuffer[0]) {
6930 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6932 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6940 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6942 *ppZStencilSurface = This->depthStencilBuffer;
6943 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6945 if(*ppZStencilSurface != NULL) {
6946 /* Note inc ref on returned surface */
6947 IWineD3DSurface_AddRef(*ppZStencilSurface);
6952 /* internal static helper functions */
6953 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6954 IWineD3DSurface *RenderSurface);
6956 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6958 HRESULT hr = WINED3D_OK;
6959 WINED3DVIEWPORT viewport;
6961 TRACE("(%p) Swapping rendertarget\n",This);
6962 if (RenderTargetIndex > 0) {
6963 FIXME("(%p) Render targets other than the first are not supported\n",This);
6964 RenderTargetIndex = 0;
6967 /* MSDN says that null disables the render target
6968 but a device must always be associated with a render target
6969 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6971 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6974 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6975 FIXME("Trying to set render target 0 to NULL\n");
6976 return WINED3DERR_INVALIDCALL;
6978 /* TODO: replace Impl* usage with interface usage */
6979 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6980 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);
6981 return WINED3DERR_INVALIDCALL;
6983 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
6984 * builds, but I think wine counts as a 'debug' build for now.
6985 ******************************/
6986 /* If we are trying to set what we already have, don't bother */
6987 if (pRenderTarget == This->renderTarget) {
6988 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6990 /* Otherwise, set the render target up */
6992 if (FALSE == This->sceneEnded) {
6993 IWineD3DDevice_EndScene(iface);
6995 TRACE("clearing renderer\n");
6996 /* IWineD3DDeviceImpl_CleanRender(iface); */
6997 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6998 depending on the renter target implementation being used.
6999 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7000 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7001 stencil buffer and incure an extra memory overhead */
7002 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7005 if (SUCCEEDED(hr)) {
7006 /* Finally, reset the viewport as the MSDN states. */
7007 /* TODO: Replace impl usage */
7008 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7009 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7012 viewport.MaxZ = 1.0f;
7013 viewport.MinZ = 0.0f;
7014 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7016 FIXME("Unknown error setting the render target\n");
7018 This->sceneEnded = FALSE;
7022 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7024 HRESULT hr = WINED3D_OK;
7025 IWineD3DSurface *tmp;
7027 TRACE("(%p) Swapping z-buffer\n",This);
7029 if (pNewZStencil == This->stencilBufferTarget) {
7030 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7032 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7033 * depending on the renter target implementation being used.
7034 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7035 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7036 * stencil buffer and incure an extra memory overhead
7037 ******************************************************/
7040 tmp = This->stencilBufferTarget;
7041 This->stencilBufferTarget = pNewZStencil;
7042 /* should we be calling the parent or the wined3d surface? */
7043 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7044 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7046 /** TODO: glEnable/glDisable on depth/stencil depending on
7047 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7048 **********************************************************/
7055 #ifdef GL_VERSION_1_3
7056 /* Internal functions not in DirectX */
7057 /** TODO: move this off to the opengl context manager
7058 *(the swapchain doesn't need to know anything about offscreen rendering!)
7059 ****************************************************/
7061 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7065 TRACE("(%p), %p\n", This, swapchain);
7067 if (swapchain->win != swapchain->drawable) {
7068 /* Set everything back the way it ws */
7069 swapchain->render_ctx = swapchain->glCtx;
7070 swapchain->drawable = swapchain->win;
7075 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7076 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7080 unsigned int height;
7081 WINED3DFORMAT format;
7082 WINED3DSURFACE_DESC surfaceDesc;
7083 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7084 surfaceDesc.Width = &width;
7085 surfaceDesc.Height = &height;
7086 surfaceDesc.Format = &format;
7087 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7089 /* I need a get width/height function (and should do something with the format) */
7090 for (i = 0; i < CONTEXT_CACHE; ++i) {
7091 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7092 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7093 the pSurface can be set to 0 allowing it to be reused from cache **/
7094 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7095 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7096 *context = &This->contextCache[i];
7099 if (This->contextCache[i].Width == 0) {
7100 This->contextCache[i].pSurface = pSurface;
7101 This->contextCache[i].Width = width;
7102 This->contextCache[i].Height = height;
7103 *context = &This->contextCache[i];
7107 if (i == CONTEXT_CACHE) {
7108 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7109 glContext *dropContext = 0;
7110 for (i = 0; i < CONTEXT_CACHE; i++) {
7111 if (This->contextCache[i].usedcount < minUsage) {
7112 dropContext = &This->contextCache[i];
7113 minUsage = This->contextCache[i].usedcount;
7116 /* clean up the context (this doesn't work for ATI at the moment */
7118 glXDestroyContext(swapchain->display, dropContext->context);
7119 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7122 dropContext->Width = 0;
7123 dropContext->pSurface = pSurface;
7124 *context = dropContext;
7126 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7127 for (i = 0; i < CONTEXT_CACHE; i++) {
7128 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7132 if (*context != NULL)
7135 return E_OUTOFMEMORY;
7139 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7140 * the functionality needs splitting up so that we don't do more than we should do.
7141 * this only seems to impact performance a little.
7142 ******************************/
7143 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7144 IWineD3DSurface *RenderSurface) {
7145 HRESULT ret = WINED3DERR_INVALIDCALL;
7147 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7150 * Currently only active for GLX >= 1.3
7151 * for others versions we'll have to use GLXPixmaps
7153 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7154 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7155 * so only check OpenGL version
7156 * ..........................
7157 * I don't believe that it is a problem with NVidia headers,
7158 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7159 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7161 * Your application will report GLX version 1.2 on glXQueryVersion.
7162 * However, it is safe to call the GLX 1.3 functions as described below.
7164 #if defined(GL_VERSION_1_3)
7166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7167 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7168 IWineD3DSurface *tmp;
7169 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7170 GLXFBConfig* cfgs = NULL;
7174 IWineD3DSwapChain *currentSwapchain;
7175 IWineD3DSwapChainImpl *swapchain;
7176 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7177 * but switch them off if the StencilSurface is set to NULL
7178 ** *********************************************************/
7179 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7180 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7183 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7184 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7187 #define PUSH1(att) attribs[nAttribs++] = (att);
7188 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7190 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7192 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7193 IWineD3DSwapChainImpl *impSwapChain;
7194 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7195 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7196 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7201 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7202 PUSH2(GLX_X_RENDERABLE, TRUE);
7203 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7204 TRACE("calling makeglcfg\n");
7205 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7208 TRACE("calling chooseFGConfig\n");
7209 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7212 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7213 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7214 why we failed and only show this message once! */
7215 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"); /**/
7217 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7218 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7219 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7220 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7221 TRACE("calling makeglcfg\n");
7222 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7224 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7231 for (i = 0; i < nCfgs; ++i) {
7232 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7233 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7234 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7237 if (NULL != This->renderTarget) {
7239 vcheckGLcall("glFlush");
7240 /** This is only useful if the old render target was a swapchain,
7241 * we need to supercede this with a function that displays
7242 * the current buffer on the screen. This is easy to do in glx1.3 but
7243 * we need to do copy-write pixels in glx 1.2.
7244 ************************************************/
7245 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7247 printf("Hit Enter to get next frame ...\n");
7253 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain) != WINED3D_OK) {
7254 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7255 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
7259 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7260 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7261 **********************************************************************/
7262 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7263 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7264 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7265 TRACE("making swapchain active\n");
7266 if (RenderSurface != This->renderTarget) {
7267 BOOL backbuf = FALSE;
7270 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7271 if(RenderSurface == swapchain->backBuffer[i]) {
7279 /* This could be flagged so that some operations work directly with the front buffer */
7280 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7282 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7284 TRACE("Error in setting current context: context %p drawable %ld !\n",
7285 impSwapChain->glCtx, impSwapChain->win);
7288 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7290 checkGLcall("glXMakeContextCurrent");
7292 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7294 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7296 /** ********************************************************************
7297 * This is a quickly hacked out implementation of offscreen textures.
7298 * It will work in most cases but there may be problems if the client
7299 * modifies the texture directly, or expects the contents of the rendertarget
7302 * There are some real speed vs compatibility issues here:
7303 * we should really use a new context for every texture, but that eats ram.
7304 * we should also be restoring the texture to the pbuffer but that eats CPU
7305 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7306 * but if this means reusing the display backbuffer then we need to make sure that
7307 * states are correctly preserved.
7308 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7309 * and gain a good performance increase at the cost of compatibility.
7310 * I would suggest that, when this is the case, a user configurable flag be made
7311 * available, allowing the user to choose the best emulated experience for them.
7312 *********************************************************************/
7314 XVisualInfo *visinfo;
7315 glContext *newContext;
7317 /* Here were using a shared context model */
7318 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7319 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7322 /* If the context doesn't exist then create a new one */
7323 /* TODO: This should really be part of findGlContext */
7324 if (NULL == newContext->context) {
7326 TRACE("making new buffer\n");
7328 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7329 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7332 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7334 /** ****************************************
7335 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7337 * In future releases, we may provide the calls glXCreateNewContext,
7338 * glXQueryDrawable and glXMakeContextCurrent.
7339 * so until then we have to use glXGetVisualFromFBConfig &co..
7340 ********************************************/
7343 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7345 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7347 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7351 if (NULL == newContext || NULL == newContext->context) {
7352 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7354 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7355 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7356 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7359 /* Clean up the old context */
7360 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7361 /* Set the current context of the swapchain to the new context */
7362 impSwapChain->drawable = newContext->drawable;
7363 impSwapChain->render_ctx = newContext->context;
7367 /* Disable recording, and apply the stateblock to the new context
7368 * FIXME: This is a bit of a hack, each context should know it's own state,
7369 * the directX current directX state should then be applied to the context */
7370 oldUpdateStateBlock = This->updateStateBlock;
7371 oldRecording= This->isRecordingState;
7372 This->isRecordingState = FALSE;
7373 This->updateStateBlock = This->stateBlock;
7374 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7376 /* clean up the current rendertargets swapchain (if it belonged to one) */
7377 if (currentSwapchain != NULL) {
7378 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7381 /* Were done with the opengl context management, setup the rendertargets */
7383 tmp = This->renderTarget;
7384 This->renderTarget = RenderSurface;
7385 IWineD3DSurface_AddRef(This->renderTarget);
7386 IWineD3DSurface_Release(tmp);
7391 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7392 /* Check that the container is not a swapchain member */
7394 IWineD3DSwapChain *tmpSwapChain;
7395 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7396 This->renderUpsideDown = TRUE;
7398 This->renderUpsideDown = FALSE;
7399 IWineD3DSwapChain_Release(tmpSwapChain);
7401 /* Force updating the cull mode */
7402 TRACE("setting render state\n");
7403 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7404 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7406 /* Force updating projection matrix */
7407 This->last_was_rhw = FALSE;
7408 This->proj_valid = FALSE;
7411 /* Restore recording state */
7412 This->isRecordingState = oldRecording;
7413 This->updateStateBlock = oldUpdateStateBlock;
7420 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7421 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7426 if ( NULL != impSwapChain) {
7427 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7435 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7436 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7438 /* TODO: the use of Impl is deprecated. */
7439 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7441 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7443 /* some basic validation checks */
7445 /* MSDN: Cursor must be A8R8G8B8 */
7446 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7447 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7448 return WINED3DERR_INVALIDCALL;
7451 /* MSDN: Cursor must be smaller than the display mode */
7452 if(pSur->currentDesc.Width > This->ddraw_width ||
7453 pSur->currentDesc.Height > This->ddraw_height) {
7454 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %ldx%ld\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7455 return WINED3DERR_INVALIDCALL;
7458 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7459 if(This->mouseCursor) {
7460 ((IWineD3DSurfaceImpl *) This->mouseCursor)->Flags &= ~SFLAG_FORCELOAD;
7462 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7463 * Texture and Blitting code to draw the cursor
7465 pSur->Flags |= SFLAG_FORCELOAD;
7468 This->xHotSpot = XHotSpot;
7469 This->yHotSpot = YHotSpot;
7471 This->mouseCursor = pCursorBitmap;
7475 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7477 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7479 This->xScreenSpace = XScreenSpace;
7480 This->yScreenSpace = YScreenSpace;
7486 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7488 TRACE("(%p) : visible(%d)\n", This, bShow);
7490 This->bCursorVisible = bShow;
7495 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7497 TRACE("(%p) : state (%lu)\n", This, This->state);
7498 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7499 switch (This->state) {
7502 case WINED3DERR_DEVICELOST:
7504 ResourceList *resourceList = This->resources;
7505 while (NULL != resourceList) {
7506 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7507 return WINED3DERR_DEVICENOTRESET;
7508 resourceList = resourceList->next;
7510 return WINED3DERR_DEVICELOST;
7512 case WINED3DERR_DRIVERINTERNALERROR:
7513 return WINED3DERR_DRIVERINTERNALERROR;
7517 return WINED3DERR_DRIVERINTERNALERROR;
7521 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7523 /** FIXME: Resource tracking needs to be done,
7524 * The closes we can do to this is set the priorities of all managed textures low
7525 * and then reset them.
7526 ***********************************************************/
7527 FIXME("(%p) : stub\n", This);
7531 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7533 /** FIXME: Resource trascking needs to be done.
7534 * in effect this pulls all non only default
7535 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7536 * and should clear down the context and set it up according to pPresentationParameters
7537 ***********************************************************/
7538 FIXME("(%p) : stub\n", This);
7542 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7544 /** FIXME: always true at the moment **/
7545 if(bEnableDialogs == FALSE) {
7546 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7552 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7554 TRACE("(%p) : pParameters %p\n", This, pParameters);
7556 *pParameters = This->createParms;
7560 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7561 IWineD3DSwapChain *swapchain;
7562 HRESULT hrc = WINED3D_OK;
7564 TRACE("Relaying to swapchain\n");
7566 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7567 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7568 IWineD3DSwapChain_Release(swapchain);
7573 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7574 IWineD3DSwapChain *swapchain;
7575 HRESULT hrc = WINED3D_OK;
7577 TRACE("Relaying to swapchain\n");
7579 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7580 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7581 IWineD3DSwapChain_Release(swapchain);
7587 /** ********************************************************
7588 * Notification functions
7589 ** ********************************************************/
7590 /** This function must be called in the release of a resource when ref == 0,
7591 * the contents of resource must still be correct,
7592 * any handels to other resource held by the caller must be closed
7593 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7594 *****************************************************/
7595 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7597 ResourceList* resourceList;
7599 TRACE("(%p) : resource %p\n", This, resource);
7601 EnterCriticalSection(&resourceStoreCriticalSection);
7603 /* add a new texture to the frot of the linked list */
7604 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7605 resourceList->resource = resource;
7607 /* Get the old head */
7608 resourceList->next = This->resources;
7610 This->resources = resourceList;
7611 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7614 LeaveCriticalSection(&resourceStoreCriticalSection);
7619 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7621 ResourceList* resourceList = NULL;
7622 ResourceList* previousResourceList = NULL;
7624 TRACE("(%p) : resource %p\n", This, resource);
7627 EnterCriticalSection(&resourceStoreCriticalSection);
7629 resourceList = This->resources;
7631 while (resourceList != NULL) {
7632 if(resourceList->resource == resource) break;
7633 previousResourceList = resourceList;
7634 resourceList = resourceList->next;
7637 if (resourceList == NULL) {
7638 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7640 LeaveCriticalSection(&resourceStoreCriticalSection);
7644 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7646 /* make sure we don't leave a hole in the list */
7647 if (previousResourceList != NULL) {
7648 previousResourceList->next = resourceList->next;
7650 This->resources = resourceList->next;
7654 LeaveCriticalSection(&resourceStoreCriticalSection);
7660 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7664 TRACE("(%p) : resource %p\n", This, resource);
7665 switch(IWineD3DResource_GetType(resource)){
7666 case WINED3DRTYPE_SURFACE:
7667 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7669 case WINED3DRTYPE_TEXTURE:
7670 case WINED3DRTYPE_CUBETEXTURE:
7671 case WINED3DRTYPE_VOLUMETEXTURE:
7672 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7673 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7674 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7675 This->stateBlock->textures[counter] = NULL;
7677 if (This->updateStateBlock != This->stateBlock ){
7678 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7679 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7680 This->updateStateBlock->textures[counter] = NULL;
7685 case WINED3DRTYPE_VOLUME:
7686 /* TODO: nothing really? */
7688 case WINED3DRTYPE_VERTEXBUFFER:
7689 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7692 TRACE("Cleaning up stream pointers\n");
7694 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7695 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7696 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7698 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7699 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7700 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7701 This->updateStateBlock->streamSource[streamNumber] = 0;
7702 /* Set changed flag? */
7705 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) */
7706 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7707 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7708 This->stateBlock->streamSource[streamNumber] = 0;
7711 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7712 else { /* This shouldn't happen */
7713 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7720 case WINED3DRTYPE_INDEXBUFFER:
7721 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7722 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7723 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7724 This->updateStateBlock->pIndexData = NULL;
7727 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7728 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7729 This->stateBlock->pIndexData = NULL;
7735 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7740 /* Remove the resoruce from the resourceStore */
7741 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7743 TRACE("Resource released\n");
7747 /**********************************************************
7748 * IWineD3DDevice VTbl follows
7749 **********************************************************/
7751 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7753 /*** IUnknown methods ***/
7754 IWineD3DDeviceImpl_QueryInterface,
7755 IWineD3DDeviceImpl_AddRef,
7756 IWineD3DDeviceImpl_Release,
7757 /*** IWineD3DDevice methods ***/
7758 IWineD3DDeviceImpl_GetParent,
7759 /*** Creation methods**/
7760 IWineD3DDeviceImpl_CreateVertexBuffer,
7761 IWineD3DDeviceImpl_CreateIndexBuffer,
7762 IWineD3DDeviceImpl_CreateStateBlock,
7763 IWineD3DDeviceImpl_CreateSurface,
7764 IWineD3DDeviceImpl_CreateTexture,
7765 IWineD3DDeviceImpl_CreateVolumeTexture,
7766 IWineD3DDeviceImpl_CreateVolume,
7767 IWineD3DDeviceImpl_CreateCubeTexture,
7768 IWineD3DDeviceImpl_CreateQuery,
7769 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7770 IWineD3DDeviceImpl_CreateVertexDeclaration,
7771 IWineD3DDeviceImpl_CreateVertexShader,
7772 IWineD3DDeviceImpl_CreatePixelShader,
7773 IWineD3DDeviceImpl_CreatePalette,
7774 /*** Odd functions **/
7775 IWineD3DDeviceImpl_Init3D,
7776 IWineD3DDeviceImpl_Uninit3D,
7777 IWineD3DDeviceImpl_EnumDisplayModes,
7778 IWineD3DDeviceImpl_EvictManagedResources,
7779 IWineD3DDeviceImpl_GetAvailableTextureMem,
7780 IWineD3DDeviceImpl_GetBackBuffer,
7781 IWineD3DDeviceImpl_GetCreationParameters,
7782 IWineD3DDeviceImpl_GetDeviceCaps,
7783 IWineD3DDeviceImpl_GetDirect3D,
7784 IWineD3DDeviceImpl_GetDisplayMode,
7785 IWineD3DDeviceImpl_SetDisplayMode,
7786 IWineD3DDeviceImpl_GetHWND,
7787 IWineD3DDeviceImpl_SetHWND,
7788 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7789 IWineD3DDeviceImpl_GetRasterStatus,
7790 IWineD3DDeviceImpl_GetSwapChain,
7791 IWineD3DDeviceImpl_Reset,
7792 IWineD3DDeviceImpl_SetDialogBoxMode,
7793 IWineD3DDeviceImpl_SetCursorProperties,
7794 IWineD3DDeviceImpl_SetCursorPosition,
7795 IWineD3DDeviceImpl_ShowCursor,
7796 IWineD3DDeviceImpl_TestCooperativeLevel,
7797 /*** Getters and setters **/
7798 IWineD3DDeviceImpl_SetClipPlane,
7799 IWineD3DDeviceImpl_GetClipPlane,
7800 IWineD3DDeviceImpl_SetClipStatus,
7801 IWineD3DDeviceImpl_GetClipStatus,
7802 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7803 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7804 IWineD3DDeviceImpl_SetDepthStencilSurface,
7805 IWineD3DDeviceImpl_GetDepthStencilSurface,
7806 IWineD3DDeviceImpl_SetFVF,
7807 IWineD3DDeviceImpl_GetFVF,
7808 IWineD3DDeviceImpl_SetGammaRamp,
7809 IWineD3DDeviceImpl_GetGammaRamp,
7810 IWineD3DDeviceImpl_SetIndices,
7811 IWineD3DDeviceImpl_GetIndices,
7812 IWineD3DDeviceImpl_SetLight,
7813 IWineD3DDeviceImpl_GetLight,
7814 IWineD3DDeviceImpl_SetLightEnable,
7815 IWineD3DDeviceImpl_GetLightEnable,
7816 IWineD3DDeviceImpl_SetMaterial,
7817 IWineD3DDeviceImpl_GetMaterial,
7818 IWineD3DDeviceImpl_SetNPatchMode,
7819 IWineD3DDeviceImpl_GetNPatchMode,
7820 IWineD3DDeviceImpl_SetPaletteEntries,
7821 IWineD3DDeviceImpl_GetPaletteEntries,
7822 IWineD3DDeviceImpl_SetPixelShader,
7823 IWineD3DDeviceImpl_GetPixelShader,
7824 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7825 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7826 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7827 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7828 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7829 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7830 IWineD3DDeviceImpl_SetRenderState,
7831 IWineD3DDeviceImpl_GetRenderState,
7832 IWineD3DDeviceImpl_SetRenderTarget,
7833 IWineD3DDeviceImpl_GetRenderTarget,
7834 IWineD3DDeviceImpl_SetFrontBackBuffers,
7835 IWineD3DDeviceImpl_SetSamplerState,
7836 IWineD3DDeviceImpl_GetSamplerState,
7837 IWineD3DDeviceImpl_SetScissorRect,
7838 IWineD3DDeviceImpl_GetScissorRect,
7839 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7840 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7841 IWineD3DDeviceImpl_SetStreamSource,
7842 IWineD3DDeviceImpl_GetStreamSource,
7843 IWineD3DDeviceImpl_SetStreamSourceFreq,
7844 IWineD3DDeviceImpl_GetStreamSourceFreq,
7845 IWineD3DDeviceImpl_SetTexture,
7846 IWineD3DDeviceImpl_GetTexture,
7847 IWineD3DDeviceImpl_SetTextureStageState,
7848 IWineD3DDeviceImpl_GetTextureStageState,
7849 IWineD3DDeviceImpl_SetTransform,
7850 IWineD3DDeviceImpl_GetTransform,
7851 IWineD3DDeviceImpl_SetVertexDeclaration,
7852 IWineD3DDeviceImpl_GetVertexDeclaration,
7853 IWineD3DDeviceImpl_SetVertexShader,
7854 IWineD3DDeviceImpl_GetVertexShader,
7855 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7856 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7857 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7858 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7859 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7860 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7861 IWineD3DDeviceImpl_SetViewport,
7862 IWineD3DDeviceImpl_GetViewport,
7863 IWineD3DDeviceImpl_MultiplyTransform,
7864 IWineD3DDeviceImpl_ValidateDevice,
7865 IWineD3DDeviceImpl_ProcessVertices,
7866 /*** State block ***/
7867 IWineD3DDeviceImpl_BeginStateBlock,
7868 IWineD3DDeviceImpl_EndStateBlock,
7869 /*** Scene management ***/
7870 IWineD3DDeviceImpl_BeginScene,
7871 IWineD3DDeviceImpl_EndScene,
7872 IWineD3DDeviceImpl_Present,
7873 IWineD3DDeviceImpl_Clear,
7875 IWineD3DDeviceImpl_DrawPrimitive,
7876 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7877 IWineD3DDeviceImpl_DrawPrimitiveUP,
7878 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7879 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7880 IWineD3DDeviceImpl_DrawRectPatch,
7881 IWineD3DDeviceImpl_DrawTriPatch,
7882 IWineD3DDeviceImpl_DeletePatch,
7883 IWineD3DDeviceImpl_ColorFill,
7884 IWineD3DDeviceImpl_UpdateTexture,
7885 IWineD3DDeviceImpl_UpdateSurface,
7886 IWineD3DDeviceImpl_CopyRects,
7887 IWineD3DDeviceImpl_StretchRect,
7888 IWineD3DDeviceImpl_GetRenderTargetData,
7889 IWineD3DDeviceImpl_GetFrontBufferData,
7890 /*** Internal use IWineD3DDevice methods ***/
7891 IWineD3DDeviceImpl_SetupTextureStates,
7892 /*** object tracking ***/
7893 IWineD3DDeviceImpl_ResourceReleased
7897 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7898 WINED3DRS_ALPHABLENDENABLE ,
7899 WINED3DRS_ALPHAFUNC ,
7900 WINED3DRS_ALPHAREF ,
7901 WINED3DRS_ALPHATESTENABLE ,
7903 WINED3DRS_COLORWRITEENABLE ,
7904 WINED3DRS_DESTBLEND ,
7905 WINED3DRS_DITHERENABLE ,
7906 WINED3DRS_FILLMODE ,
7907 WINED3DRS_FOGDENSITY ,
7909 WINED3DRS_FOGSTART ,
7910 WINED3DRS_LASTPIXEL ,
7911 WINED3DRS_SHADEMODE ,
7912 WINED3DRS_SRCBLEND ,
7913 WINED3DRS_STENCILENABLE ,
7914 WINED3DRS_STENCILFAIL ,
7915 WINED3DRS_STENCILFUNC ,
7916 WINED3DRS_STENCILMASK ,
7917 WINED3DRS_STENCILPASS ,
7918 WINED3DRS_STENCILREF ,
7919 WINED3DRS_STENCILWRITEMASK ,
7920 WINED3DRS_STENCILZFAIL ,
7921 WINED3DRS_TEXTUREFACTOR ,
7932 WINED3DRS_ZWRITEENABLE
7935 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7936 WINED3DTSS_ADDRESSW ,
7937 WINED3DTSS_ALPHAARG0 ,
7938 WINED3DTSS_ALPHAARG1 ,
7939 WINED3DTSS_ALPHAARG2 ,
7940 WINED3DTSS_ALPHAOP ,
7941 WINED3DTSS_BUMPENVLOFFSET ,
7942 WINED3DTSS_BUMPENVLSCALE ,
7943 WINED3DTSS_BUMPENVMAT00 ,
7944 WINED3DTSS_BUMPENVMAT01 ,
7945 WINED3DTSS_BUMPENVMAT10 ,
7946 WINED3DTSS_BUMPENVMAT11 ,
7947 WINED3DTSS_COLORARG0 ,
7948 WINED3DTSS_COLORARG1 ,
7949 WINED3DTSS_COLORARG2 ,
7950 WINED3DTSS_COLOROP ,
7951 WINED3DTSS_RESULTARG ,
7952 WINED3DTSS_TEXCOORDINDEX ,
7953 WINED3DTSS_TEXTURETRANSFORMFLAGS
7956 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7957 WINED3DSAMP_ADDRESSU ,
7958 WINED3DSAMP_ADDRESSV ,
7959 WINED3DSAMP_ADDRESSW ,
7960 WINED3DSAMP_BORDERCOLOR ,
7961 WINED3DSAMP_MAGFILTER ,
7962 WINED3DSAMP_MINFILTER ,
7963 WINED3DSAMP_MIPFILTER ,
7964 WINED3DSAMP_MIPMAPLODBIAS ,
7965 WINED3DSAMP_MAXMIPLEVEL ,
7966 WINED3DSAMP_MAXANISOTROPY ,
7967 WINED3DSAMP_SRGBTEXTURE ,
7968 WINED3DSAMP_ELEMENTINDEX
7971 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7973 WINED3DRS_AMBIENTMATERIALSOURCE ,
7974 WINED3DRS_CLIPPING ,
7975 WINED3DRS_CLIPPLANEENABLE ,
7976 WINED3DRS_COLORVERTEX ,
7977 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7978 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7979 WINED3DRS_FOGDENSITY ,
7981 WINED3DRS_FOGSTART ,
7982 WINED3DRS_FOGTABLEMODE ,
7983 WINED3DRS_FOGVERTEXMODE ,
7984 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7985 WINED3DRS_LIGHTING ,
7986 WINED3DRS_LOCALVIEWER ,
7987 WINED3DRS_MULTISAMPLEANTIALIAS ,
7988 WINED3DRS_MULTISAMPLEMASK ,
7989 WINED3DRS_NORMALIZENORMALS ,
7990 WINED3DRS_PATCHEDGESTYLE ,
7991 WINED3DRS_POINTSCALE_A ,
7992 WINED3DRS_POINTSCALE_B ,
7993 WINED3DRS_POINTSCALE_C ,
7994 WINED3DRS_POINTSCALEENABLE ,
7995 WINED3DRS_POINTSIZE ,
7996 WINED3DRS_POINTSIZE_MAX ,
7997 WINED3DRS_POINTSIZE_MIN ,
7998 WINED3DRS_POINTSPRITEENABLE ,
7999 WINED3DRS_RANGEFOGENABLE ,
8000 WINED3DRS_SPECULARMATERIALSOURCE ,
8001 WINED3DRS_TWEENFACTOR ,
8002 WINED3DRS_VERTEXBLEND
8005 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8006 WINED3DTSS_TEXCOORDINDEX ,
8007 WINED3DTSS_TEXTURETRANSFORMFLAGS
8010 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8011 WINED3DSAMP_DMAPOFFSET