2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
225 case D3DLIGHT_DIRECTIONAL:
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 if (NULL == vshader && NULL == pshader) {
286 /* No pixel or vertex shader specified */
287 This->stateBlock->shaderPrgId = 0;
291 ptr = list_head( &This->glsl_shader_progs );
293 /* At least one program exists - see if it matches our ps/vs combination */
294 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
295 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
296 /* Existing Program found, use it */
297 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
299 This->stateBlock->shaderPrgId = curLink->programId;
302 /* This isn't the entry we need - try the next one */
303 ptr = list_next( &This->glsl_shader_progs, ptr );
306 /* If we get to this point, then no matching program exists, so we create one */
307 programId = GL_EXTCALL(glCreateProgramObjectARB());
308 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
309 This->stateBlock->shaderPrgId = programId;
311 if (NULL != vshader) {
313 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
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");
334 if (NULL != pshader) {
335 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
338 /* Link the program */
339 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
340 GL_EXTCALL(glLinkProgramARB(programId));
341 print_glsl_info_log(&GLINFO_LOCATION, programId);
343 /* Now, we add a list item to associate this program with the vertex and
344 * pixel shaders that it is attached to.
346 * These list items will be deleted when the device is released.
348 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
349 newLink->programId = programId;
350 newLink->pixelShader = pshader;
351 newLink->vertexShader = vshader;
352 list_add_head( &This->glsl_shader_progs, &newLink->entry);
357 /** Detach the GLSL pixel or vertex shader object from the shader program */
358 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
362 if (shaderObj != 0 && programId != 0) {
363 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
364 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
365 checkGLcall("glDetachObjectARB");
369 /** Delete a GLSL shader program */
370 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
375 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
376 GL_EXTCALL(glDeleteObjectARB(obj));
377 checkGLcall("glDeleteObjectARB");
381 /** Delete the list of linked programs this shader is associated with.
382 * Also at this point, check to see if there are any objects left attached
383 * to each GLSL program. If not, delete the GLSL program object.
384 * This will be run when a device is released. */
385 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
387 struct list *ptr = NULL;
388 struct glsl_shader_prog_link *curLink = NULL;
389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
394 (one pixel shader and one vertex shader at most) */
396 ptr = list_head( &This->glsl_shader_progs );
398 /* First, get the current item,
399 * save the link to the next pointer,
400 * detach and delete shader objects,
401 * then de-allocate the list item's memory */
402 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
403 ptr = list_next( &This->glsl_shader_progs, ptr );
405 /* See if this object is still attached to the program - it may have been detached already */
406 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
407 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
408 for (i = 0; i < numAttached; i++) {
409 detach_glsl_shader(iface, objList[i], curLink->programId);
412 delete_glsl_shader_program(iface, curLink->programId);
414 /* Free the memory for this list item */
415 HeapFree(GetProcessHeap(), 0, curLink);
420 /* Apply the current values to the specified texture stage */
421 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
430 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
431 clamping, MIPLOD, etc. This will work for up to 16 samplers.
434 if (Sampler >= GL_LIMITS(sampler_stages)) {
435 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
438 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
439 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
441 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
442 checkGLcall("glActiveTextureARB");
444 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
445 } else if (Sampler > 0) {
446 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
450 /* TODO: change this to a lookup table
451 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
452 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
453 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
454 especially when there are a number of groups of states. */
456 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
458 /* 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 */
459 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
460 /* these are the only two supported states that need to be applied */
461 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
462 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
463 #if 0 /* not supported at the moment */
464 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
465 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
466 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
467 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
468 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
469 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
470 APPLY_STATE(WINED3DTSS_RESULTARG);
471 APPLY_STATE(WINED3DTSS_CONSTANT);
473 /* a quick sanity check in case someone forgot to update this function */
474 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
475 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
479 /* apply any sampler states that always need applying */
480 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
481 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
482 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
483 GL_TEXTURE_LOD_BIAS_EXT,
485 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
488 /* Note the D3DRS value applies to all textures, but GL has one
489 * per texture, so apply it now ready to be used!
491 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
492 /* Set the default alpha blend color */
493 if (GL_SUPPORT(ARB_IMAGING)) {
494 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
495 checkGLcall("glBlendColor");
497 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
500 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
501 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
502 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
504 /* TODO: NV_POINT_SPRITE */
505 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
506 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
507 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
508 glDisable(GL_POINT_SMOOTH);
510 /* Centre the texture on the vertex */
511 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
512 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
514 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
515 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
516 checkGLcall("glTexEnvf(...)");
517 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
518 glEnable( GL_POINT_SPRITE_ARB );
519 checkGLcall("glEnable(...)");
521 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
522 glDisable( GL_POINT_SPRITE_ARB );
523 checkGLcall("glEnable(...)");
527 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
530 /**********************************************************
531 * IUnknown parts follows
532 **********************************************************/
534 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
538 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
539 if (IsEqualGUID(riid, &IID_IUnknown)
540 || IsEqualGUID(riid, &IID_IWineD3DBase)
541 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
542 IUnknown_AddRef(iface);
547 return E_NOINTERFACE;
550 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
552 ULONG refCount = InterlockedIncrement(&This->ref);
554 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
558 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
560 ULONG refCount = InterlockedDecrement(&This->ref);
562 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
565 /* TODO: Clean up all the surfaces and textures! */
566 /* NOTE: You must release the parent if the object was created via a callback
567 ** ***************************/
569 /* Delete any GLSL shader programs that may exist */
570 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
571 wined3d_settings.ps_selected_mode == SHADER_GLSL)
572 delete_glsl_shader_list(iface);
574 /* Release the update stateblock */
575 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
576 if(This->updateStateBlock != This->stateBlock)
577 FIXME("(%p) Something's still holding the Update stateblock\n",This);
579 This->updateStateBlock = NULL;
580 { /* because were not doing proper internal refcounts releasing the primary state block
581 causes recursion with the extra checks in ResourceReleased, to avoid this we have
582 to set this->stateBlock = NULL; first */
583 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
584 This->stateBlock = NULL;
586 /* Release the stateblock */
587 if(IWineD3DStateBlock_Release(stateBlock) > 0){
588 FIXME("(%p) Something's still holding the Update stateblock\n",This);
592 if (This->resources != NULL ) {
593 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
594 dumpResources(This->resources);
598 IWineD3D_Release(This->wineD3D);
599 This->wineD3D = NULL;
600 HeapFree(GetProcessHeap(), 0, This);
601 TRACE("Freed device %p\n", This);
607 /**********************************************************
608 * IWineD3DDevice implementation follows
609 **********************************************************/
610 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
612 *pParent = This->parent;
613 IUnknown_AddRef(This->parent);
617 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
618 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
619 GLenum error, glUsage;
620 DWORD vboUsage = object->resource.usage;
621 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
624 /* Make sure that the gl error is cleared. Do not use checkGLcall
625 * here because checkGLcall just prints a fixme and continues. However,
626 * if an error during VBO creation occurs we can fall back to non-vbo operation
627 * with full functionality(but performance loss)
629 while(glGetError() != GL_NO_ERROR);
631 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
632 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
633 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
634 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
635 * to check if the rhw and color values are in the correct format.
638 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
639 error = glGetError();
640 if(object->vbo == 0 || error != GL_NO_ERROR) {
641 WARN("Failed to create a VBO with error %d\n", error);
645 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
646 error = glGetError();
647 if(error != GL_NO_ERROR) {
648 WARN("Failed to bind the VBO, error %d\n", error);
652 /* Transformed vertices are horribly inflexible. If the app specifies an
653 * vertex buffer with transformed vertices in default pool without DYNAMIC
654 * usage assume DYNAMIC usage and print a warning. The app will have to update
655 * the vertices regularily for them to be useful
657 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
658 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
659 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
660 vboUsage |= WINED3DUSAGE_DYNAMIC;
663 /* Don't use static, because dx apps tend to update the buffer
664 * quite often even if they specify 0 usage
666 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
667 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
668 TRACE("Gl usage = GL_STREAM_DRAW\n");
669 glUsage = GL_STREAM_DRAW_ARB;
671 case D3DUSAGE_WRITEONLY:
672 TRACE("Gl usage = GL_STATIC_DRAW\n");
673 glUsage = GL_DYNAMIC_DRAW_ARB;
675 case D3DUSAGE_DYNAMIC:
676 TRACE("Gl usage = GL_STREAM_COPY\n");
677 glUsage = GL_STREAM_COPY_ARB;
680 TRACE("Gl usage = GL_STATIC_COPY\n");
681 glUsage = GL_DYNAMIC_COPY_ARB;
685 /* Reserve memory for the buffer. The amount of data won't change
686 * so we are safe with calling glBufferData once with a NULL ptr and
687 * calling glBufferSubData on updates
689 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
690 error = glGetError();
691 if(error != GL_NO_ERROR) {
692 WARN("glBufferDataARB failed with error %d\n", error);
700 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
701 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
702 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
709 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
712 IWineD3DVertexBufferImpl *object;
713 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
714 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
716 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
718 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
719 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
721 if(Size == 0) return WINED3DERR_INVALIDCALL;
723 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
724 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
728 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
729 * drawStridedFast (half-life 2).
731 * Basically converting the vertices in the buffer is quite expensive, and observations
732 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
733 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
735 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
736 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
737 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
738 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
740 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
741 * more. In this call we can convert dx7 buffers too.
743 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
744 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
745 (dxVersion > 7 || !conv) ) {
748 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
749 if(dxVersion == 7 && object->vbo) {
750 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
751 object->resource.allocatedMemory = NULL;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
759 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
760 HANDLE *sharedHandle, IUnknown *parent) {
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 IWineD3DIndexBufferImpl *object;
763 TRACE("(%p) Creating index buffer\n", This);
765 /* Allocate the storage for the device */
766 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
769 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
770 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
773 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
774 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
775 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
780 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
783 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 /* Otherwise, might as well set the whole state block to the appropriate values */
798 if ( This->stateBlock != NULL) {
799 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
801 memset(object->streamFreq, 1, sizeof(object->streamFreq));
804 /* Reset the ref and type after kludging it */
805 object->wineD3DDevice = This;
807 object->blockType = Type;
809 TRACE("Updating changed flags appropriate for type %d\n", Type);
811 if (Type == WINED3DSBT_ALL) {
813 TRACE("ALL => Pretend everything has changed\n");
814 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
815 } else if (Type == WINED3DSBT_PIXELSTATE) {
817 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
818 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
820 object->changed.pixelShader = TRUE;
822 /* Pixel Shader Constants */
823 for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
824 object->changed.pixelShaderConstantsF[i] = TRUE;
825 object->changed.pixelShaderConstantsB[i] = TRUE;
826 object->changed.pixelShaderConstantsI[i] = TRUE;
828 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
829 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
831 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
832 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
833 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
836 for (j = 0 ; j < 16; j++) {
837 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
839 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
843 } else if (Type == WINED3DSBT_VERTEXSTATE) {
845 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
846 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
848 object->changed.vertexShader = TRUE;
850 /* Vertex Shader Constants */
851 for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
852 object->changed.vertexShaderConstantsF[i] = TRUE;
853 object->changed.vertexShaderConstantsB[i] = TRUE;
854 object->changed.vertexShaderConstantsI[i] = TRUE;
856 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
857 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
859 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
860 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
861 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
864 for (j = 0 ; j < 16; j++){
865 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
866 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
870 /* Duplicate light chain */
872 PLIGHTINFOEL *src = NULL;
873 PLIGHTINFOEL *dst = NULL;
874 PLIGHTINFOEL *newEl = NULL;
875 src = This->stateBlock->lights;
876 object->lights = NULL;
880 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
881 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
882 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
884 newEl->changed = TRUE;
885 newEl->enabledChanged = TRUE;
887 object->lights = newEl;
898 FIXME("Unrecognized state block type %d\n", Type);
901 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
906 /* ************************************
908 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
911 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
913 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.
915 ******************************** */
917 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) {
918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
919 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
920 unsigned int pow2Width, pow2Height;
921 unsigned int Size = 1;
922 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
923 TRACE("(%p) Create surface\n",This);
925 /** FIXME: Check ranges on the inputs are valid
928 * [in] Quality level. The valid range is between zero and one less than the level
929 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
930 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
931 * values of paired render targets, depth stencil surfaces, and the MultiSample type
933 *******************************/
938 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
940 * If this flag is set, the contents of the depth stencil buffer will be
941 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
942 * with a different depth surface.
944 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
945 ***************************/
947 if(MultisampleQuality < 0) {
948 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
949 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
952 if(MultisampleQuality > 0) {
953 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
954 MultisampleQuality=0;
957 /** FIXME: Check that the format is supported
959 *******************************/
961 /* Non-power2 support */
963 /* Find the nearest pow2 match */
964 pow2Width = pow2Height = 1;
965 while (pow2Width < Width) pow2Width <<= 1;
966 while (pow2Height < Height) pow2Height <<= 1;
968 if (pow2Width > Width || pow2Height > Height) {
969 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
970 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
971 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
972 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
973 This, Width, Height);
974 return WINED3DERR_NOTAVAILABLE;
978 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
979 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
981 *********************************/
982 if (WINED3DFMT_UNKNOWN == Format) {
984 } else if (Format == WINED3DFMT_DXT1) {
985 /* DXT1 is half byte per pixel */
986 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
988 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
989 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
990 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
992 Size = (pow2Width * tableEntry->bpp) * pow2Height;
995 /** Create and initialise the surface resource **/
996 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
997 /* "Standalone" surface */
998 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1000 object->currentDesc.Width = Width;
1001 object->currentDesc.Height = Height;
1002 object->currentDesc.MultiSampleType = MultiSample;
1003 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1005 /* Setup some glformat defaults */
1006 object->glDescription.glFormat = tableEntry->glFormat;
1007 object->glDescription.glFormatInternal = tableEntry->glInternal;
1008 object->glDescription.glType = tableEntry->glType;
1010 object->glDescription.textureName = 0;
1011 object->glDescription.level = Level;
1012 object->glDescription.target = GL_TEXTURE_2D;
1015 object->pow2Width = pow2Width;
1016 object->pow2Height = pow2Height;
1019 object->Flags = 0; /* We start without flags set */
1020 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1021 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1022 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1023 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1026 if (WINED3DFMT_UNKNOWN != Format) {
1027 object->bytesPerPixel = tableEntry->bpp;
1028 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1030 object->bytesPerPixel = 0;
1031 object->pow2Size = 0;
1034 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1036 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1038 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1039 * this function is too deap to need to care about things like this.
1040 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1041 * ****************************************/
1043 case WINED3DPOOL_SCRATCH:
1044 if(Lockable == FALSE)
1045 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1046 which are mutually exclusive, setting lockable to true\n");
1049 case WINED3DPOOL_SYSTEMMEM:
1050 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1051 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1052 case WINED3DPOOL_MANAGED:
1053 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1054 Usage of DYNAMIC which are mutually exclusive, not doing \
1055 anything just telling you.\n");
1057 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1058 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1059 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1060 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1063 FIXME("(%p) Unknown pool %d\n", This, Pool);
1067 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1068 FIXME("Trying to create a render target that isn't in the default pool\n");
1071 /* mark the texture as dirty so that it get's loaded first time around*/
1072 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1073 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1074 This, Width, Height, Format, debug_d3dformat(Format),
1075 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1077 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1078 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1079 This->ddraw_primary = (IWineD3DSurface *) object;
1081 /* Look at the implementation and set the correct Vtable */
1083 case SURFACE_OPENGL:
1084 /* Nothing to do, it's set already */
1088 object->lpVtbl = &IWineGDISurface_Vtbl;
1092 /* To be sure to catch this */
1093 ERR("Unknown requested surface implementation %d!\n", Impl);
1094 IWineD3DSurface_Release((IWineD3DSurface *) object);
1095 return WINED3DERR_INVALIDCALL;
1098 /* Call the private setup routine */
1099 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1103 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1104 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1106 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1114 unsigned int pow2Width = Width;
1115 unsigned int pow2Height = Height;
1118 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1120 /* TODO: It should only be possible to create textures for formats
1121 that are reported as supported */
1122 if (WINED3DFMT_UNKNOWN >= Format) {
1123 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1124 return WINED3DERR_INVALIDCALL;
1127 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1128 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1129 object->width = Width;
1130 object->height = Height;
1132 /** Non-power2 support **/
1133 /* Find the nearest pow2 match */
1134 pow2Width = pow2Height = 1;
1135 while (pow2Width < Width) pow2Width <<= 1;
1136 while (pow2Height < Height) pow2Height <<= 1;
1138 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1139 /* Precalculated scaling for 'faked' non power of two texture coords */
1140 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1141 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1142 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1144 /* Calculate levels for mip mapping */
1146 TRACE("calculating levels %d\n", object->baseTexture.levels);
1147 object->baseTexture.levels++;
1150 while (tmpW > 1 || tmpH > 1) {
1151 tmpW = max(1, tmpW >> 1);
1152 tmpH = max(1, tmpH >> 1);
1153 object->baseTexture.levels++;
1155 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1158 /* Generate all the surfaces */
1161 for (i = 0; i < object->baseTexture.levels; i++)
1163 /* use the callback to create the texture surface */
1164 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1165 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1166 FIXME("Failed to create surface %p\n", object);
1168 object->surfaces[i] = NULL;
1169 IWineD3DTexture_Release((IWineD3DTexture *)object);
1175 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1176 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1177 /* calculate the next mipmap level */
1178 tmpW = max(1, tmpW >> 1);
1179 tmpH = max(1, tmpH >> 1);
1182 TRACE("(%p) : Created texture %p\n", This, object);
1186 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1187 UINT Width, UINT Height, UINT Depth,
1188 UINT Levels, DWORD Usage,
1189 WINED3DFORMAT Format, WINED3DPOOL Pool,
1190 IWineD3DVolumeTexture **ppVolumeTexture,
1191 HANDLE *pSharedHandle, IUnknown *parent,
1192 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1195 IWineD3DVolumeTextureImpl *object;
1201 /* TODO: It should only be possible to create textures for formats
1202 that are reported as supported */
1203 if (WINED3DFMT_UNKNOWN >= Format) {
1204 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1205 return WINED3DERR_INVALIDCALL;
1208 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1209 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1211 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1212 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1214 object->width = Width;
1215 object->height = Height;
1216 object->depth = Depth;
1218 /* Calculate levels for mip mapping */
1220 object->baseTexture.levels++;
1224 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1225 tmpW = max(1, tmpW >> 1);
1226 tmpH = max(1, tmpH >> 1);
1227 tmpD = max(1, tmpD >> 1);
1228 object->baseTexture.levels++;
1230 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1233 /* Generate all the surfaces */
1238 for (i = 0; i < object->baseTexture.levels; i++)
1240 /* Create the volume */
1241 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1242 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1244 /* Set it's container to this object */
1245 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1247 /* calcualte the next mipmap level */
1248 tmpW = max(1, tmpW >> 1);
1249 tmpH = max(1, tmpH >> 1);
1250 tmpD = max(1, tmpD >> 1);
1253 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1254 TRACE("(%p) : Created volume texture %p\n", This, object);
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1259 UINT Width, UINT Height, UINT Depth,
1261 WINED3DFORMAT Format, WINED3DPOOL Pool,
1262 IWineD3DVolume** ppVolume,
1263 HANDLE* pSharedHandle, IUnknown *parent) {
1265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1266 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1267 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1269 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1271 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1272 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1274 object->currentDesc.Width = Width;
1275 object->currentDesc.Height = Height;
1276 object->currentDesc.Depth = Depth;
1277 object->bytesPerPixel = formatDesc->bpp;
1279 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1280 object->lockable = TRUE;
1281 object->locked = FALSE;
1282 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1283 object->dirty = TRUE;
1285 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1288 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1289 UINT Levels, DWORD Usage,
1290 WINED3DFORMAT Format, WINED3DPOOL Pool,
1291 IWineD3DCubeTexture **ppCubeTexture,
1292 HANDLE *pSharedHandle, IUnknown *parent,
1293 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1300 unsigned int pow2EdgeLength = EdgeLength;
1302 /* TODO: It should only be possible to create textures for formats
1303 that are reported as supported */
1304 if (WINED3DFMT_UNKNOWN >= Format) {
1305 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1306 return WINED3DERR_INVALIDCALL;
1309 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1310 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1312 TRACE("(%p) Create Cube Texture\n", This);
1314 /** Non-power2 support **/
1316 /* Find the nearest pow2 match */
1318 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1320 object->edgeLength = EdgeLength;
1321 /* TODO: support for native non-power 2 */
1322 /* Precalculated scaling for 'faked' non power of two texture coords */
1323 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1325 /* Calculate levels for mip mapping */
1327 object->baseTexture.levels++;
1330 tmpW = max(1, tmpW >> 1);
1331 object->baseTexture.levels++;
1333 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1336 /* Generate all the surfaces */
1338 for (i = 0; i < object->baseTexture.levels; i++) {
1340 /* Create the 6 faces */
1341 for (j = 0; j < 6; j++) {
1343 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1344 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1346 if(hr!= WINED3D_OK) {
1350 for (l = 0; l < j; l++) {
1351 IWineD3DSurface_Release(object->surfaces[j][i]);
1353 for (k = 0; k < i; k++) {
1354 for (l = 0; l < 6; l++) {
1355 IWineD3DSurface_Release(object->surfaces[l][j]);
1359 FIXME("(%p) Failed to create surface\n",object);
1360 HeapFree(GetProcessHeap(),0,object);
1361 *ppCubeTexture = NULL;
1364 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1365 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1367 tmpW = max(1, tmpW >> 1);
1370 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1371 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1375 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1377 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1379 if (NULL == ppQuery) {
1380 /* Just a check to see if we support this type of query */
1381 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1383 case WINED3DQUERYTYPE_OCCLUSION:
1384 TRACE("(%p) occlusion query\n", This);
1385 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1388 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1390 case WINED3DQUERYTYPE_VCACHE:
1391 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1392 case WINED3DQUERYTYPE_VERTEXSTATS:
1393 case WINED3DQUERYTYPE_EVENT:
1394 case WINED3DQUERYTYPE_TIMESTAMP:
1395 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1396 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1397 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1398 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1399 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1400 case WINED3DQUERYTYPE_PIXELTIMINGS:
1401 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1402 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1404 FIXME("(%p) Unhandled query type %d\n", This, Type);
1409 D3DCREATEOBJECTINSTANCE(object, Query)
1410 object->type = Type;
1411 /* allocated the 'extended' data based on the type of query requested */
1413 case D3DQUERYTYPE_OCCLUSION:
1414 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1415 TRACE("(%p) Allocating data for an occlusion query\n", This);
1416 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1419 case D3DQUERYTYPE_VCACHE:
1420 case D3DQUERYTYPE_RESOURCEMANAGER:
1421 case D3DQUERYTYPE_VERTEXSTATS:
1422 case D3DQUERYTYPE_EVENT:
1423 case D3DQUERYTYPE_TIMESTAMP:
1424 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1425 case D3DQUERYTYPE_TIMESTAMPFREQ:
1426 case D3DQUERYTYPE_PIPELINETIMINGS:
1427 case D3DQUERYTYPE_INTERFACETIMINGS:
1428 case D3DQUERYTYPE_VERTEXTIMINGS:
1429 case D3DQUERYTYPE_PIXELTIMINGS:
1430 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1431 case D3DQUERYTYPE_CACHEUTILIZATION:
1433 object->extendedData = 0;
1434 FIXME("(%p) Unhandled query type %d\n",This , Type);
1436 TRACE("(%p) : Created Query %p\n", This, object);
1440 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1441 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1443 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1444 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1448 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1450 XVisualInfo template;
1451 GLXContext oldContext;
1452 Drawable oldDrawable;
1453 HRESULT hr = WINED3D_OK;
1455 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1457 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1458 * does a device hold a reference to a swap chain giving them a lifetime of the device
1459 * or does the swap chain notify the device of its destruction.
1460 *******************************/
1462 /* Check the params */
1463 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1464 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1465 return WINED3DERR_INVALIDCALL;
1466 } else if (*pPresentationParameters->BackBufferCount > 1) {
1467 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");
1470 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1472 /*********************
1473 * Lookup the window Handle and the relating X window handle
1474 ********************/
1476 /* Setup hwnd we are using, plus which display this equates to */
1477 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1478 if (!object->win_handle) {
1479 object->win_handle = This->createParms.hFocusWindow;
1482 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1483 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1484 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1485 return WINED3DERR_NOTAVAILABLE;
1487 hDc = GetDC(object->win_handle);
1488 object->display = get_display(hDc);
1489 ReleaseDC(object->win_handle, hDc);
1490 TRACE("Using a display of %p %p\n", object->display, hDc);
1492 if (NULL == object->display || NULL == hDc) {
1493 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1494 return WINED3DERR_NOTAVAILABLE;
1497 if (object->win == 0) {
1498 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1499 return WINED3DERR_NOTAVAILABLE;
1502 * Create an opengl context for the display visual
1503 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1504 * use different properties after that point in time. FIXME: How to handle when requested format
1505 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1506 * it chooses is identical to the one already being used!
1507 **********************************/
1509 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1512 /* Create a new context for this swapchain */
1513 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1514 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1515 (or the best possible if none is requested) */
1516 TRACE("Found x visual ID : %ld\n", template.visualid);
1518 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1519 if (NULL == object->visInfo) {
1520 ERR("cannot really get XVisual\n");
1522 return WINED3DERR_NOTAVAILABLE;
1525 /* Write out some debug info about the visual/s */
1526 TRACE("Using x visual ID : %ld\n", template.visualid);
1527 TRACE(" visual info: %p\n", object->visInfo);
1528 TRACE(" num items : %d\n", num);
1529 for (n = 0;n < num; n++) {
1530 TRACE("=====item=====: %d\n", n + 1);
1531 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1532 TRACE(" screen : %d\n", object->visInfo[n].screen);
1533 TRACE(" depth : %u\n", object->visInfo[n].depth);
1534 TRACE(" class : %d\n", object->visInfo[n].class);
1535 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1536 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1537 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1538 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1539 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1540 /* log some extra glx info */
1541 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1542 TRACE(" gl_aux_buffers : %d\n", value);
1543 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1544 TRACE(" gl_buffer_size : %d\n", value);
1545 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1546 TRACE(" gl_red_size : %d\n", value);
1547 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1548 TRACE(" gl_green_size : %d\n", value);
1549 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1550 TRACE(" gl_blue_size : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1552 TRACE(" gl_alpha_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1554 TRACE(" gl_depth_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1556 TRACE(" gl_stencil_size : %d\n", value);
1558 /* Now choose a simila visual ID*/
1560 #ifdef USE_CONTEXT_MANAGER
1562 /** TODO: use a context mamager **/
1566 IWineD3DSwapChain *implSwapChain;
1567 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1568 /* The first time around we create the context that is shared with all other swapchains and render targets */
1569 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1570 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1573 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1574 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1575 /* and create a new context with the implicit swapchains context as the shared context */
1576 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1577 IWineD3DSwapChain_Release(implSwapChain);
1582 XFree(object->visInfo);
1583 object->visInfo = NULL;
1587 if (!object->glCtx) {
1588 ERR("Failed to create GLX context\n");
1589 return WINED3DERR_NOTAVAILABLE;
1591 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1592 object->win_handle, object->glCtx, object->win, object->visInfo);
1595 /*********************
1596 * Windowed / Fullscreen
1597 *******************/
1600 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1601 * so we should really check to see if there is a fullscreen swapchain already
1602 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1603 **************************************/
1605 if (!*(pPresentationParameters->Windowed)) {
1611 /* Get info on the current display setup */
1612 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1613 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1616 /* Change the display settings */
1617 memset(&devmode, 0, sizeof(DEVMODEW));
1618 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1619 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1620 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1621 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1622 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1623 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1625 /* Make popup window */
1626 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1627 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1628 *(pPresentationParameters->BackBufferWidth),
1629 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1631 /* For GetDisplayMode */
1632 This->ddraw_width = devmode.dmPelsWidth;
1633 This->ddraw_height = devmode.dmPelsHeight;
1634 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1638 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1639 * then the corresponding dimension of the client area of the hDeviceWindow
1640 * (or the focus window, if hDeviceWindow is NULL) is taken.
1641 **********************/
1643 if (*(pPresentationParameters->Windowed) &&
1644 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1645 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1648 GetClientRect(object->win_handle, &Rect);
1650 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1651 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1652 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1654 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1655 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1656 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1660 /*********************
1661 * finish off parameter initialization
1662 *******************/
1664 /* Put the correct figures in the presentation parameters */
1665 TRACE("Coppying accross presentaion paraneters\n");
1666 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1667 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1668 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1669 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1670 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1671 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1672 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1673 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1674 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1675 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1676 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1677 object->presentParms.Flags = *(pPresentationParameters->Flags);
1678 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1679 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1682 /*********************
1683 * Create the back, front and stencil buffers
1684 *******************/
1686 TRACE("calling rendertarget CB\n");
1687 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1688 object->presentParms.BackBufferWidth,
1689 object->presentParms.BackBufferHeight,
1690 object->presentParms.BackBufferFormat,
1691 object->presentParms.MultiSampleType,
1692 object->presentParms.MultiSampleQuality,
1693 TRUE /* Lockable */,
1694 &object->frontBuffer,
1695 NULL /* pShared (always null)*/);
1696 if (object->frontBuffer != NULL)
1697 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1699 if(object->presentParms.BackBufferCount > 0) {
1702 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1703 if(!object->backBuffer) {
1704 ERR("Out of memory\n");
1706 if (object->frontBuffer) {
1707 IUnknown *bufferParent;
1708 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1709 IUnknown_Release(bufferParent); /* once for the get parent */
1710 if (IUnknown_Release(bufferParent) > 0) {
1711 FIXME("(%p) Something's still holding the front buffer\n",This);
1714 HeapFree(GetProcessHeap(), 0, object);
1715 return E_OUTOFMEMORY;
1718 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1719 TRACE("calling rendertarget CB\n");
1720 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1721 object->presentParms.BackBufferWidth,
1722 object->presentParms.BackBufferHeight,
1723 object->presentParms.BackBufferFormat,
1724 object->presentParms.MultiSampleType,
1725 object->presentParms.MultiSampleQuality,
1726 TRUE /* Lockable */,
1727 &object->backBuffer[i],
1728 NULL /* pShared (always null)*/);
1729 if(hr == WINED3D_OK && object->backBuffer[i]) {
1730 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1736 object->backBuffer = NULL;
1739 if (object->backBuffer != NULL) {
1741 glDrawBuffer(GL_BACK);
1742 checkGLcall("glDrawBuffer(GL_BACK)");
1745 /* Single buffering - draw to front buffer */
1747 glDrawBuffer(GL_FRONT);
1748 checkGLcall("glDrawBuffer(GL_FRONT)");
1752 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1753 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1754 TRACE("Creating depth stencil buffer\n");
1755 if (This->depthStencilBuffer == NULL ) {
1756 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1757 object->presentParms.BackBufferWidth,
1758 object->presentParms.BackBufferHeight,
1759 object->presentParms.AutoDepthStencilFormat,
1760 object->presentParms.MultiSampleType,
1761 object->presentParms.MultiSampleQuality,
1762 FALSE /* FIXME: Discard */,
1763 &This->depthStencilBuffer,
1764 NULL /* pShared (always null)*/ );
1765 if (This->depthStencilBuffer != NULL)
1766 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1769 /** TODO: A check on width, height and multisample types
1770 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1771 ****************************/
1772 object->wantsDepthStencilBuffer = TRUE;
1774 object->wantsDepthStencilBuffer = FALSE;
1777 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1780 /*********************
1781 * init the default renderTarget management
1782 *******************/
1783 object->drawable = object->win;
1784 object->render_ctx = object->glCtx;
1786 if (hr == WINED3D_OK) {
1787 /*********************
1788 * Setup some defaults and clear down the buffers
1789 *******************/
1791 /** save current context and drawable **/
1792 oldContext = glXGetCurrentContext();
1793 oldDrawable = glXGetCurrentDrawable();
1795 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1796 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1797 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1799 checkGLcall("glXMakeCurrent");
1801 TRACE("Setting up the screen\n");
1802 /* Clear the screen */
1803 glClearColor(1.0, 0.0, 0.0, 0.0);
1804 checkGLcall("glClearColor");
1807 glClearStencil(0xffff);
1809 checkGLcall("glClear");
1811 glColor3f(1.0, 1.0, 1.0);
1812 checkGLcall("glColor3f");
1814 glEnable(GL_LIGHTING);
1815 checkGLcall("glEnable");
1817 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1818 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1820 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1821 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1823 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1824 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1826 /* switch back to the original context (if there was one)*/
1827 if (This->swapchains) {
1828 /** TODO: restore the context and drawable **/
1829 glXMakeCurrent(object->display, oldDrawable, oldContext);
1834 TRACE("Set swapchain to %p\n", object);
1835 } else { /* something went wrong so clean up */
1836 IUnknown* bufferParent;
1837 if (object->frontBuffer) {
1839 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1840 IUnknown_Release(bufferParent); /* once for the get parent */
1841 if (IUnknown_Release(bufferParent) > 0) {
1842 FIXME("(%p) Something's still holding the front buffer\n",This);
1845 if (object->backBuffer) {
1847 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1848 if(object->backBuffer[i]) {
1849 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1850 IUnknown_Release(bufferParent); /* once for the get parent */
1851 if (IUnknown_Release(bufferParent) > 0) {
1852 FIXME("(%p) Something's still holding the back buffer\n",This);
1856 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1857 object->backBuffer = NULL;
1859 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1860 /* Clean up the context */
1861 /* check that we are the current context first (we shouldn't be though!) */
1862 if (object->glCtx != 0) {
1863 if(glXGetCurrentContext() == object->glCtx) {
1864 glXMakeCurrent(object->display, None, NULL);
1866 glXDestroyContext(object->display, object->glCtx);
1868 HeapFree(GetProcessHeap(), 0, object);
1875 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1876 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1878 TRACE("(%p)\n", This);
1880 return This->NumberOfSwapChains;
1883 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1885 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1887 if(iSwapChain < This->NumberOfSwapChains) {
1888 *pSwapChain = This->swapchains[iSwapChain];
1889 IWineD3DSwapChain_AddRef(*pSwapChain);
1890 TRACE("(%p) returning %p\n", This, *pSwapChain);
1893 TRACE("Swapchain out of range\n");
1895 return WINED3DERR_INVALIDCALL;
1900 * Vertex Declaration
1902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1904 IWineD3DVertexDeclarationImpl *object = NULL;
1905 HRESULT hr = WINED3D_OK;
1906 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1907 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1910 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1915 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1916 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1918 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1919 HRESULT hr = WINED3D_OK;
1920 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1921 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1923 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1925 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1926 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1927 if (pDeclaration != NULL) {
1928 IWineD3DVertexDeclaration *vertexDeclaration;
1929 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1930 if (WINED3D_OK == hr) {
1931 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1932 object->vertexDeclaration = vertexDeclaration;
1934 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1935 IWineD3DVertexShader_Release(*ppVertexShader);
1936 return WINED3DERR_INVALIDCALL;
1940 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1942 if (WINED3D_OK != hr) {
1943 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1944 IWineD3DVertexShader_Release(*ppVertexShader);
1945 return WINED3DERR_INVALIDCALL;
1948 #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. */
1949 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1960 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1962 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1963 HRESULT hr = WINED3D_OK;
1965 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1966 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1967 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1968 if (WINED3D_OK == hr) {
1969 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1971 WARN("(%p) : Failed to create pixel shader\n", This);
1977 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1979 IWineD3DPaletteImpl *object;
1981 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1983 /* Create the new object */
1984 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1986 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1987 return E_OUTOFMEMORY;
1990 object->lpVtbl = &IWineD3DPalette_Vtbl;
1992 object->Flags = Flags;
1993 object->parent = Parent;
1994 object->wineD3DDevice = This;
1995 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1997 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2000 HeapFree( GetProcessHeap(), 0, object);
2001 return E_OUTOFMEMORY;
2004 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2006 IWineD3DPalette_Release((IWineD3DPalette *) object);
2010 *Palette = (IWineD3DPalette *) object;
2015 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 IWineD3DSwapChainImpl *swapchain;
2019 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2020 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2022 /* TODO: Test if OpenGL is compiled in and loaded */
2024 /* Setup the implicit swapchain */
2025 TRACE("Creating implicit swapchain\n");
2026 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2027 WARN("Failed to create implicit swapchain\n");
2028 return WINED3DERR_INVALIDCALL;
2031 This->NumberOfSwapChains = 1;
2032 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2033 if(!This->swapchains) {
2034 ERR("Out of memory!\n");
2035 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2036 return E_OUTOFMEMORY;
2038 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2040 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2041 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2042 This->renderTarget = swapchain->backBuffer[0];
2045 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2046 This->renderTarget = swapchain->frontBuffer;
2048 IWineD3DSurface_AddRef(This->renderTarget);
2049 /* Depth Stencil support */
2050 This->stencilBufferTarget = This->depthStencilBuffer;
2051 if (NULL != This->stencilBufferTarget) {
2052 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2055 /* Set up some starting GL setup */
2058 * Initialize openGL extension related variables
2059 * with Default values
2062 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( &((IWineD3DImpl *) This->wineD3D)->gl_info, swapchain->display);
2063 /* Setup all the devices defaults */
2064 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2066 IWineD3DImpl_CheckGraphicsMemory();
2070 /* Initialize our list of GLSL programs */
2071 list_init(&This->glsl_shader_progs);
2073 { /* Set a default viewport */
2077 vp.Width = *(pPresentationParameters->BackBufferWidth);
2078 vp.Height = *(pPresentationParameters->BackBufferHeight);
2081 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2084 /* Initialize the current view state */
2085 This->modelview_valid = 1;
2086 This->proj_valid = 0;
2087 This->view_ident = 1;
2088 This->last_was_rhw = 0;
2089 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2090 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2092 /* Clear the screen */
2093 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2095 This->d3d_initialized = TRUE;
2099 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2102 IUnknown* stencilBufferParent;
2103 IUnknown* swapChainParent;
2105 TRACE("(%p)\n", This);
2107 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2109 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2110 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2113 /* Release the buffers (with sanity checks)*/
2114 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2115 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2116 if(This->depthStencilBuffer != This->stencilBufferTarget)
2117 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2119 This->stencilBufferTarget = NULL;
2121 TRACE("Releasing the render target at %p\n", This->renderTarget);
2122 if(IWineD3DSurface_Release(This->renderTarget) >0){
2123 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2125 TRACE("Setting rendertarget to NULL\n");
2126 This->renderTarget = NULL;
2128 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2129 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2130 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2131 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2133 This->depthStencilBuffer = NULL;
2135 for(i=0; i < This->NumberOfSwapChains; i++) {
2136 TRACE("Releasing the implicit swapchain %d\n", i);
2137 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2138 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2139 IUnknown_Release(swapChainParent); /* once for the get parent */
2140 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2141 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2145 HeapFree(GetProcessHeap(), 0, This->swapchains);
2146 This->swapchains = NULL;
2147 This->NumberOfSwapChains = 0;
2149 This->d3d_initialized = FALSE;
2153 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2158 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2160 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2162 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2163 /* Ignore some modes if a description was passed */
2164 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2165 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2166 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2168 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2170 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2177 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2181 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2183 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2185 /* Resize the screen even without a window:
2186 * The app could have unset it with SetCooperativeLevel, but not called
2187 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2188 * but we don't have any hwnd
2191 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2192 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2193 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2194 devmode.dmPelsWidth = pMode->Width;
2195 devmode.dmPelsHeight = pMode->Height;
2197 devmode.dmDisplayFrequency = pMode->RefreshRate;
2198 if (pMode->RefreshRate != 0) {
2199 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2202 /* Only change the mode if necessary */
2203 if( (This->ddraw_width == pMode->Width) &&
2204 (This->ddraw_height == pMode->Height) &&
2205 (This->ddraw_format == pMode->Format) &&
2206 (pMode->RefreshRate == 0) ) {
2210 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2211 if (ret != DISP_CHANGE_SUCCESSFUL) {
2212 if(devmode.dmDisplayFrequency != 0) {
2213 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2214 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2215 devmode.dmDisplayFrequency = 0;
2216 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2218 if(ret != DISP_CHANGE_SUCCESSFUL) {
2219 return DDERR_INVALIDMODE;
2223 /* Store the new values */
2224 This->ddraw_width = pMode->Width;
2225 This->ddraw_height = pMode->Height;
2226 This->ddraw_format = pMode->Format;
2228 /* Only do this with a window of course */
2229 if(This->ddraw_window)
2230 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2235 static HRESULT WINAPI IWineD3DDeviceImpl_EnumZBufferFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2239 WINED3DFORMAT FormatList[] = {
2246 WINED3DFMT_UNKNOWN /* Terminate the list */
2249 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2251 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2252 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2253 ret = Callback((IUnknown *) This, FormatList[i], Context);
2254 if(ret != DDENUMRET_OK) {
2255 TRACE("Enumeration cancelled by Application\n");
2261 TRACE("End of Enumeration\n");
2266 static HRESULT WINAPI IWineD3DDeviceImpl_EnumTextureFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2272 * WINED3DFMT_A1R5G5B5 needs to be the first 16 bit format, as some dumb apps depend on this
2274 * Do not enumerate RGBA pixel formats: "some games choose the first 16 bit texture format
2275 * with alpha they find enumerated, others the last one. And both want to have the ARGB one."
2276 * But WineD3D doesn't support RGBA formats anyway...
2279 WINED3DFORMAT FormatList[] = {
2281 WINED3DFMT_A8R8G8B8,
2282 WINED3DFMT_X8R8G8B8,
2286 WINED3DFMT_A1R5G5B5,
2287 WINED3DFMT_A4R4G4B4,
2289 WINED3DFMT_X1R5G5B5,
2297 /* Terminate the list */
2301 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2303 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2304 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2305 ret = Callback((IUnknown *) This, FormatList[i], Context);
2306 if(ret != DDENUMRET_OK) {
2307 TRACE("Enumeration cancelled by Application\n");
2313 TRACE("End of Enumeration\n");
2318 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 *ppD3D= This->wineD3D;
2321 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2322 IWineD3D_AddRef(*ppD3D);
2326 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2327 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2328 * Into the video ram as possible and seeing how many fit
2329 * you can also get the correct initial value from via X and ATI's driver
2330 *******************/
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2332 static BOOL showfixmes = TRUE;
2334 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2335 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2338 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2339 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2340 /* videomemory is simulated videomemory + AGP memory left */
2341 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2349 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2351 HRESULT hr = WINED3D_OK;
2353 /* Update the current state block */
2354 This->updateStateBlock->fvf = fvf;
2355 This->updateStateBlock->changed.fvf = TRUE;
2356 This->updateStateBlock->set.fvf = TRUE;
2358 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2361 /* clear down the vertex declaration
2362 NOTE: Axis and Allies doesn't work properly otherwise
2363 (may be a stateblock problem though!)
2365 hr = IWineD3DDevice_SetVertexDeclaration(iface, NULL);
2372 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2375 *pfvf = This->stateBlock->fvf;
2380 * Get / Set Stream Source
2382 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 IWineD3DVertexBuffer *oldSrc;
2386 /**TODO: instance and index data, see
2387 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2389 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2392 /* D3d9 only, but shouldn't hurt d3d8 */
2395 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2397 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2398 FIXME("stream index data not supported\n");
2400 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2401 FIXME("stream instance data not supported\n");
2405 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2407 if (StreamNumber >= MAX_STREAMS) {
2408 WARN("Stream out of range %d\n", StreamNumber);
2409 return WINED3DERR_INVALIDCALL;
2412 oldSrc = This->stateBlock->streamSource[StreamNumber];
2413 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2415 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2416 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2417 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2418 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2419 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2420 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2422 /* Handle recording of state blocks */
2423 if (This->isRecordingState) {
2424 TRACE("Recording... not performing anything\n");
2428 /* Not recording... */
2429 /* Need to do a getParent and pass the reffs up */
2430 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2431 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2432 so for now, just count internally */
2433 if (pStreamData != NULL) {
2434 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2435 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2436 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2438 vbImpl->stream = StreamNumber;
2439 vbImpl->Flags |= VBFLAG_STREAM;
2440 IWineD3DVertexBuffer_AddRef(pStreamData);
2442 if (oldSrc != NULL) {
2443 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2444 IWineD3DVertexBuffer_Release(oldSrc);
2450 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2454 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2455 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2458 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2460 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2461 FIXME("stream index data not supported\n");
2463 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2464 FIXME("stream instance data not supported\n");
2468 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2470 if (StreamNumber >= MAX_STREAMS) {
2471 WARN("Stream out of range %d\n", StreamNumber);
2472 return WINED3DERR_INVALIDCALL;
2474 *pStream = This->stateBlock->streamSource[StreamNumber];
2475 *pStride = This->stateBlock->streamStride[StreamNumber];
2476 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2478 if (*pStream == NULL) {
2479 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2480 return WINED3DERR_INVALIDCALL;
2483 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2487 /*Should be quite easy, just an extension of vertexdata
2489 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2491 The divider is a bit odd though
2493 VertexOffset = StartVertex / Divider * StreamStride +
2494 VertexIndex / Divider * StreamStride + StreamOffset
2497 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2501 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2503 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2504 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2505 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2507 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2508 FIXME("Stream indexing not fully supported\n");
2514 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2518 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2520 TRACE("(%p) : returning %d\n", This, *Divider);
2526 * Get / Set & Multiply Transform
2528 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 /* Most of this routine, comments included copied from ddraw tree initially: */
2532 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2534 /* Handle recording of state blocks */
2535 if (This->isRecordingState) {
2536 TRACE("Recording... not performing anything\n");
2537 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2538 This->updateStateBlock->set.transform[d3dts] = TRUE;
2539 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2544 * If the new matrix is the same as the current one,
2545 * we cut off any further processing. this seems to be a reasonable
2546 * optimization because as was noticed, some apps (warcraft3 for example)
2547 * tend towards setting the same matrix repeatedly for some reason.
2549 * From here on we assume that the new matrix is different, wherever it matters.
2551 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2552 TRACE("The app is setting the same matrix over again\n");
2555 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2559 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2560 where ViewMat = Camera space, WorldMat = world space.
2562 In OpenGL, camera and world space is combined into GL_MODELVIEW
2563 matrix. The Projection matrix stay projection matrix.
2566 /* Capture the times we can just ignore the change for now */
2567 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2568 This->modelview_valid = FALSE;
2571 } else if (d3dts == D3DTS_PROJECTION) {
2572 This->proj_valid = FALSE;
2575 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2576 /* Indexed Vertex Blending Matrices 256 -> 511 */
2577 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2578 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2582 /* Now we really are going to have to change a matrix */
2585 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2586 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2587 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2590 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2591 * NOTE: We have to reset the positions even if the light/plane is not currently
2592 * enabled, since the call to enable it will not reset the position.
2593 * NOTE2: Apparently texture transforms do NOT need reapplying
2596 PLIGHTINFOEL *lightChain = NULL;
2597 This->modelview_valid = FALSE;
2598 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2600 glMatrixMode(GL_MODELVIEW);
2601 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2603 glLoadMatrixf((float *)lpmatrix);
2604 checkGLcall("glLoadMatrixf(...)");
2607 lightChain = This->stateBlock->lights;
2608 while (lightChain && lightChain->glIndex != -1) {
2609 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2610 checkGLcall("glLightfv posn");
2611 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2612 checkGLcall("glLightfv dirn");
2613 lightChain = lightChain->next;
2616 /* Reset Clipping Planes if clipping is enabled */
2617 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2618 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2619 checkGLcall("glClipPlane");
2623 } else { /* What was requested!?? */
2624 WARN("invalid matrix specified: %i\n", d3dts);
2627 /* Release lock, all done */
2632 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2634 TRACE("(%p) : for Transform State %d\n", This, State);
2635 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2639 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2640 D3DMATRIX *mat = NULL;
2643 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2644 * below means it will be recorded in a state block change, but it
2645 * works regardless where it is recorded.
2646 * If this is found to be wrong, change to StateBlock.
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 TRACE("(%p) : For state %u\n", This, State);
2651 if (State < HIGHEST_TRANSFORMSTATE)
2653 mat = &This->updateStateBlock->transforms[State];
2655 FIXME("Unhandled transform state!!\n");
2658 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2660 /* Apply change via set transform - will reapply to eg. lights this way */
2661 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2666 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2668 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2669 you can reference any indexes you want as long as that number max are enabled at any
2670 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2671 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2672 but when recording, just build a chain pretty much of commands to be replayed. */
2674 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2676 PLIGHTINFOEL *object, *temp;
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2681 /* If recording state block, just add to end of lights chain */
2682 if (This->isRecordingState) {
2683 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2684 if (NULL == object) {
2685 return WINED3DERR_OUTOFVIDEOMEMORY;
2687 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2688 object->OriginalIndex = Index;
2689 object->glIndex = -1;
2690 object->changed = TRUE;
2692 /* Add to the END of the chain of lights changes to be replayed */
2693 if (This->updateStateBlock->lights == NULL) {
2694 This->updateStateBlock->lights = object;
2696 temp = This->updateStateBlock->lights;
2697 while (temp->next != NULL) temp=temp->next;
2698 temp->next = object;
2700 TRACE("Recording... not performing anything more\n");
2704 /* Ok, not recording any longer so do real work */
2705 object = This->stateBlock->lights;
2706 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2708 /* If we didn't find it in the list of lights, time to add it */
2709 if (object == NULL) {
2710 PLIGHTINFOEL *insertAt,*prevPos;
2712 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2713 if (NULL == object) {
2714 return WINED3DERR_OUTOFVIDEOMEMORY;
2716 object->OriginalIndex = Index;
2717 object->glIndex = -1;
2719 /* Add it to the front of list with the idea that lights will be changed as needed
2720 BUT after any lights currently assigned GL indexes */
2721 insertAt = This->stateBlock->lights;
2723 while (insertAt != NULL && insertAt->glIndex != -1) {
2725 insertAt = insertAt->next;
2728 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2729 This->stateBlock->lights = object;
2730 } else if (insertAt == NULL) { /* End of list */
2731 prevPos->next = object;
2732 object->prev = prevPos;
2733 } else { /* Middle of chain */
2734 if (prevPos == NULL) {
2735 This->stateBlock->lights = object;
2737 prevPos->next = object;
2739 object->prev = prevPos;
2740 object->next = insertAt;
2741 insertAt->prev = object;
2745 /* Initialize the object */
2746 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,
2747 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2748 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2749 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2750 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2751 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2752 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2754 /* Save away the information */
2755 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2757 switch (pLight->Type) {
2758 case D3DLIGHT_POINT:
2760 object->lightPosn[0] = pLight->Position.x;
2761 object->lightPosn[1] = pLight->Position.y;
2762 object->lightPosn[2] = pLight->Position.z;
2763 object->lightPosn[3] = 1.0f;
2764 object->cutoff = 180.0f;
2768 case D3DLIGHT_DIRECTIONAL:
2770 object->lightPosn[0] = -pLight->Direction.x;
2771 object->lightPosn[1] = -pLight->Direction.y;
2772 object->lightPosn[2] = -pLight->Direction.z;
2773 object->lightPosn[3] = 0.0;
2774 object->exponent = 0.0f;
2775 object->cutoff = 180.0f;
2780 object->lightPosn[0] = pLight->Position.x;
2781 object->lightPosn[1] = pLight->Position.y;
2782 object->lightPosn[2] = pLight->Position.z;
2783 object->lightPosn[3] = 1.0;
2786 object->lightDirn[0] = pLight->Direction.x;
2787 object->lightDirn[1] = pLight->Direction.y;
2788 object->lightDirn[2] = pLight->Direction.z;
2789 object->lightDirn[3] = 1.0;
2792 * opengl-ish and d3d-ish spot lights use too different models for the
2793 * light "intensity" as a function of the angle towards the main light direction,
2794 * so we only can approximate very roughly.
2795 * however spot lights are rather rarely used in games (if ever used at all).
2796 * furthermore if still used, probably nobody pays attention to such details.
2798 if (pLight->Falloff == 0) {
2801 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2803 if (rho < 0.0001) rho = 0.0001f;
2804 object->exponent = -0.3/log(cos(rho/2));
2805 object->cutoff = pLight->Phi*90/M_PI;
2811 FIXME("Unrecognized light type %d\n", pLight->Type);
2814 /* Update the live definitions if the light is currently assigned a glIndex */
2815 if (object->glIndex != -1) {
2816 setup_light(iface, object->glIndex, object);
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2822 PLIGHTINFOEL *lightInfo = NULL;
2823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2826 /* Locate the light in the live lights */
2827 lightInfo = This->stateBlock->lights;
2828 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2830 if (lightInfo == NULL) {
2831 TRACE("Light information requested but light not defined\n");
2832 return WINED3DERR_INVALIDCALL;
2835 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2840 * Get / Set Light Enable
2841 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2843 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2844 PLIGHTINFOEL *lightInfo = NULL;
2845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2846 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2848 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2849 if (This->isRecordingState) {
2850 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2851 if (NULL == lightInfo) {
2852 return WINED3DERR_OUTOFVIDEOMEMORY;
2854 lightInfo->OriginalIndex = Index;
2855 lightInfo->glIndex = -1;
2856 lightInfo->enabledChanged = TRUE;
2858 /* Add to the END of the chain of lights changes to be replayed */
2859 if (This->updateStateBlock->lights == NULL) {
2860 This->updateStateBlock->lights = lightInfo;
2862 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2863 while (temp->next != NULL) temp=temp->next;
2864 temp->next = lightInfo;
2866 TRACE("Recording... not performing anything more\n");
2870 /* Not recording... So, locate the light in the live lights */
2871 lightInfo = This->stateBlock->lights;
2872 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2874 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2875 if (lightInfo == NULL) {
2877 TRACE("Light enabled requested but light not defined, so defining one!\n");
2878 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2880 /* Search for it again! Should be fairly quick as near head of list */
2881 lightInfo = This->stateBlock->lights;
2882 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2883 if (lightInfo == NULL) {
2884 FIXME("Adding default lights has failed dismally\n");
2885 return WINED3DERR_INVALIDCALL;
2889 /* OK, we now have a light... */
2890 if (Enable == FALSE) {
2892 /* If we are disabling it, check it was enabled, and
2893 still only do something if it has assigned a glIndex (which it should have!) */
2894 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2895 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2897 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2898 checkGLcall("glDisable GL_LIGHT0+Index");
2901 TRACE("Nothing to do as light was not enabled\n");
2903 lightInfo->lightEnabled = FALSE;
2906 /* We are enabling it. If it is enabled, it's really simple */
2907 if (lightInfo->lightEnabled) {
2909 TRACE("Nothing to do as light was enabled\n");
2911 /* If it already has a glIndex, it's still simple */
2912 } else if (lightInfo->glIndex != -1) {
2913 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2914 lightInfo->lightEnabled = TRUE;
2916 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2917 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2920 /* Otherwise got to find space - lights are ordered gl indexes first */
2922 PLIGHTINFOEL *bsf = NULL;
2923 PLIGHTINFOEL *pos = This->stateBlock->lights;
2924 PLIGHTINFOEL *prev = NULL;
2928 /* Try to minimize changes as much as possible */
2929 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2931 /* Try to remember which index can be replaced if necessary */
2932 if (bsf==NULL && pos->lightEnabled == FALSE) {
2933 /* Found a light we can replace, save as best replacement */
2937 /* Step to next space */
2943 /* If we have too many active lights, fail the call */
2944 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2945 FIXME("Program requests too many concurrent lights\n");
2946 return WINED3DERR_INVALIDCALL;
2948 /* If we have allocated all lights, but not all are enabled,
2949 reuse one which is not enabled */
2950 } else if (Index == This->maxConcurrentLights) {
2951 /* use bsf - Simply swap the new light and the BSF one */
2952 PLIGHTINFOEL *bsfNext = bsf->next;
2953 PLIGHTINFOEL *bsfPrev = bsf->prev;
2956 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2957 if (bsf->prev != NULL) {
2958 bsf->prev->next = lightInfo;
2960 This->stateBlock->lights = lightInfo;
2963 /* If not side by side, lots of chains to update */
2964 if (bsf->next != lightInfo) {
2965 lightInfo->prev->next = bsf;
2966 bsf->next->prev = lightInfo;
2967 bsf->next = lightInfo->next;
2968 bsf->prev = lightInfo->prev;
2969 lightInfo->next = bsfNext;
2970 lightInfo->prev = bsfPrev;
2974 bsf->prev = lightInfo;
2975 bsf->next = lightInfo->next;
2976 lightInfo->next = bsf;
2977 lightInfo->prev = bsfPrev;
2982 glIndex = bsf->glIndex;
2984 lightInfo->glIndex = glIndex;
2985 lightInfo->lightEnabled = TRUE;
2987 /* Finally set up the light in gl itself */
2988 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2990 setup_light(iface, glIndex, lightInfo);
2991 glEnable(GL_LIGHT0 + glIndex);
2992 checkGLcall("glEnable GL_LIGHT0 new setup");
2995 /* If we reached the end of the allocated lights, with space in the
2996 gl lights, setup a new light */
2997 } else if (pos->glIndex == -1) {
2999 /* We reached the end of the allocated gl lights, so already
3000 know the index of the next one! */
3002 lightInfo->glIndex = glIndex;
3003 lightInfo->lightEnabled = TRUE;
3005 /* In an ideal world, it's already in the right place */
3006 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
3007 /* No need to move it */
3009 /* Remove this light from the list */
3010 lightInfo->prev->next = lightInfo->next;
3011 if (lightInfo->next != NULL) {
3012 lightInfo->next->prev = lightInfo->prev;
3015 /* Add in at appropriate place (inbetween prev and pos) */
3016 lightInfo->prev = prev;
3017 lightInfo->next = pos;
3019 This->stateBlock->lights = lightInfo;
3021 prev->next = lightInfo;
3024 pos->prev = lightInfo;
3028 /* Finally set up the light in gl itself */
3029 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
3031 setup_light(iface, glIndex, lightInfo);
3032 glEnable(GL_LIGHT0 + glIndex);
3033 checkGLcall("glEnable GL_LIGHT0 new setup");
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3044 PLIGHTINFOEL *lightInfo = NULL;
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p) : for idx(%ld)\n", This, Index);
3048 /* Locate the light in the live lights */
3049 lightInfo = This->stateBlock->lights;
3050 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3052 if (lightInfo == NULL) {
3053 TRACE("Light enabled state requested but light not defined\n");
3054 return WINED3DERR_INVALIDCALL;
3056 *pEnable = lightInfo->lightEnabled;
3061 * Get / Set Clip Planes
3063 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3067 /* Validate Index */
3068 if (Index >= GL_LIMITS(clipplanes)) {
3069 TRACE("Application has requested clipplane this device doesn't support\n");
3070 return WINED3DERR_INVALIDCALL;
3073 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3074 This->updateStateBlock->set.clipplane[Index] = TRUE;
3075 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3076 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3077 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3078 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3080 /* Handle recording of state blocks */
3081 if (This->isRecordingState) {
3082 TRACE("Recording... not performing anything\n");
3090 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3091 glMatrixMode(GL_MODELVIEW);
3093 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3095 TRACE("Clipplane [%f,%f,%f,%f]\n",
3096 This->updateStateBlock->clipplane[Index][0],
3097 This->updateStateBlock->clipplane[Index][1],
3098 This->updateStateBlock->clipplane[Index][2],
3099 This->updateStateBlock->clipplane[Index][3]);
3100 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3101 checkGLcall("glClipPlane");
3109 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3111 TRACE("(%p) : for idx %ld\n", This, Index);
3113 /* Validate Index */
3114 if (Index >= GL_LIMITS(clipplanes)) {
3115 TRACE("Application has requested clipplane this device doesn't support\n");
3116 return WINED3DERR_INVALIDCALL;
3119 pPlane[0] = This->stateBlock->clipplane[Index][0];
3120 pPlane[1] = This->stateBlock->clipplane[Index][1];
3121 pPlane[2] = This->stateBlock->clipplane[Index][2];
3122 pPlane[3] = This->stateBlock->clipplane[Index][3];
3127 * Get / Set Clip Plane Status
3128 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3130 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 FIXME("(%p) : stub\n", This);
3133 if (NULL == pClipStatus) {
3134 return WINED3DERR_INVALIDCALL;
3136 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3137 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 FIXME("(%p) : stub\n", This);
3144 if (NULL == pClipStatus) {
3145 return WINED3DERR_INVALIDCALL;
3147 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3148 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3153 * Get / Set Material
3154 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3156 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 This->updateStateBlock->changed.material = TRUE;
3160 This->updateStateBlock->set.material = TRUE;
3161 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3163 /* Handle recording of state blocks */
3164 if (This->isRecordingState) {
3165 TRACE("Recording... not performing anything\n");
3170 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3171 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3172 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3173 pMaterial->Ambient.b, pMaterial->Ambient.a);
3174 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3175 pMaterial->Specular.b, pMaterial->Specular.a);
3176 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3177 pMaterial->Emissive.b, pMaterial->Emissive.a);
3178 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3180 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3181 checkGLcall("glMaterialfv(GL_AMBIENT)");
3182 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3183 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3185 /* Only change material color if specular is enabled, otherwise it is set to black */
3186 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3187 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3188 checkGLcall("glMaterialfv(GL_SPECULAR");
3190 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3191 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3192 checkGLcall("glMaterialfv(GL_SPECULAR");
3194 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3195 checkGLcall("glMaterialfv(GL_EMISSION)");
3196 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3197 checkGLcall("glMaterialf(GL_SHININESS");
3203 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3206 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3207 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3208 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3209 pMaterial->Ambient.b, pMaterial->Ambient.a);
3210 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3211 pMaterial->Specular.b, pMaterial->Specular.a);
3212 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3213 pMaterial->Emissive.b, pMaterial->Emissive.a);
3214 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3223 UINT BaseVertexIndex) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 IWineD3DIndexBuffer *oldIdxs;
3227 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3228 oldIdxs = This->updateStateBlock->pIndexData;
3230 This->updateStateBlock->changed.indices = TRUE;
3231 This->updateStateBlock->set.indices = TRUE;
3232 This->updateStateBlock->pIndexData = pIndexData;
3233 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3235 /* Handle recording of state blocks */
3236 if (This->isRecordingState) {
3237 TRACE("Recording... not performing anything\n");
3241 if (NULL != pIndexData) {
3242 IWineD3DIndexBuffer_AddRef(pIndexData);
3244 if (NULL != oldIdxs) {
3245 IWineD3DIndexBuffer_Release(oldIdxs);
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 *ppIndexData = This->stateBlock->pIndexData;
3255 /* up ref count on ppindexdata */
3257 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3258 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3259 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3261 TRACE("(%p) No index data set\n", This);
3263 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3269 * Get / Set Viewports
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 TRACE("(%p)\n", This);
3275 This->updateStateBlock->changed.viewport = TRUE;
3276 This->updateStateBlock->set.viewport = TRUE;
3277 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3279 /* Handle recording of state blocks */
3280 if (This->isRecordingState) {
3281 TRACE("Recording... not performing anything\n");
3284 This->viewport_changed = TRUE;
3288 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3289 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3291 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3292 checkGLcall("glDepthRange");
3293 /* Note: GL requires lower left, DirectX supplies upper left */
3294 /* TODO: replace usage of renderTarget with context management */
3295 glViewport(pViewport->X,
3296 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3297 pViewport->Width, pViewport->Height);
3299 checkGLcall("glViewport");
3307 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 TRACE("(%p)\n", This);
3310 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3314 static void renderstate_stencil_twosided(
3315 IWineD3DDeviceImpl *This,
3322 GLint stencilPass ) {
3323 #if 0 /* Don't use OpenGL 2.0 calls for now */
3324 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3325 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3326 checkGLcall("glStencilFuncSeparate(...)");
3327 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3328 checkGLcall("glStencilOpSeparate(...)");
3332 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3333 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3334 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3335 GL_EXTCALL(glActiveStencilFaceEXT(face));
3336 checkGLcall("glActiveStencilFaceEXT(...)");
3337 glStencilFunc(func, ref, mask);
3338 checkGLcall("glStencilFunc(...)");
3339 glStencilOp(stencilFail, depthFail, stencilPass);
3340 checkGLcall("glStencilOp(...)");
3341 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3342 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3343 checkGLcall("glStencilFuncSeparateATI(...)");
3344 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3345 checkGLcall("glStencilOpSeparateATI(...)");
3347 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3351 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3352 DWORD onesided_enable = FALSE;
3353 DWORD twosided_enable = FALSE;
3354 GLint func = GL_ALWAYS;
3355 GLint func_ccw = GL_ALWAYS;
3358 GLint stencilFail = GL_KEEP;
3359 GLint depthFail = GL_KEEP;
3360 GLint stencilPass = GL_KEEP;
3361 GLint stencilFail_ccw = GL_KEEP;
3362 GLint depthFail_ccw = GL_KEEP;
3363 GLint stencilPass_ccw = GL_KEEP;
3365 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3366 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3367 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3368 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3369 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3370 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3371 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3372 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3373 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3374 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3375 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3376 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3377 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3378 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3379 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3380 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3381 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3382 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3383 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3384 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3385 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3386 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3387 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3388 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3391 case WINED3DRS_STENCILENABLE :
3392 onesided_enable = Value;
3394 case WINED3DRS_TWOSIDEDSTENCILMODE :
3395 twosided_enable = Value;
3397 case WINED3DRS_STENCILFUNC :
3398 func = StencilFunc(Value);
3400 case WINED3DRS_CCW_STENCILFUNC :
3401 func_ccw = StencilFunc(Value);
3403 case WINED3DRS_STENCILREF :
3406 case WINED3DRS_STENCILMASK :
3409 case WINED3DRS_STENCILFAIL :
3410 stencilFail = StencilOp(Value);
3412 case WINED3DRS_STENCILZFAIL :
3413 depthFail = StencilOp(Value);
3415 case WINED3DRS_STENCILPASS :
3416 stencilPass = StencilOp(Value);
3418 case WINED3DRS_CCW_STENCILFAIL :
3419 stencilFail_ccw = StencilOp(Value);
3421 case WINED3DRS_CCW_STENCILZFAIL :
3422 depthFail_ccw = StencilOp(Value);
3424 case WINED3DRS_CCW_STENCILPASS :
3425 stencilPass_ccw = StencilOp(Value);
3428 ERR("This should not happen!");
3431 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3432 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3433 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3434 onesided_enable, twosided_enable, ref, mask,
3435 func, stencilFail, depthFail, stencilPass,
3436 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3438 if (twosided_enable) {
3439 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3440 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3442 if (onesided_enable) {
3443 glEnable(GL_STENCIL_TEST);
3444 checkGLcall("glEnable GL_STENCIL_TEST");
3445 glStencilFunc(func, ref, mask);
3446 checkGLcall("glStencilFunc(...)");
3447 glStencilOp(stencilFail, depthFail, stencilPass);
3448 checkGLcall("glStencilOp(...)");
3450 glDisable(GL_STENCIL_TEST);
3451 checkGLcall("glDisable GL_STENCIL_TEST");
3457 * Get / Set Render States
3458 * TODO: Verify against dx9 definitions
3460 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 DWORD OldValue = This->stateBlock->renderState[State];
3465 /* Simple way of referring to either a DWORD or a 4 byte float */
3471 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3472 This->updateStateBlock->changed.renderState[State] = TRUE;
3473 This->updateStateBlock->set.renderState[State] = TRUE;
3474 This->updateStateBlock->renderState[State] = Value;
3476 /* Handle recording of state blocks */
3477 if (This->isRecordingState) {
3478 TRACE("Recording... not performing anything\n");
3485 case WINED3DRS_FILLMODE :
3486 switch ((D3DFILLMODE) Value) {
3487 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3488 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3489 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3491 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3493 checkGLcall("glPolygonMode (fillmode)");
3496 case WINED3DRS_LIGHTING :
3498 glEnable(GL_LIGHTING);
3499 checkGLcall("glEnable GL_LIGHTING");
3501 glDisable(GL_LIGHTING);
3502 checkGLcall("glDisable GL_LIGHTING");
3506 case WINED3DRS_ZENABLE :
3507 switch ((D3DZBUFFERTYPE) Value) {
3509 glDisable(GL_DEPTH_TEST);
3510 checkGLcall("glDisable GL_DEPTH_TEST");
3513 glEnable(GL_DEPTH_TEST);
3514 checkGLcall("glEnable GL_DEPTH_TEST");
3517 glEnable(GL_DEPTH_TEST);
3518 checkGLcall("glEnable GL_DEPTH_TEST");
3519 FIXME("W buffer is not well handled\n");
3522 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3526 case WINED3DRS_CULLMODE :
3528 /* If we are culling "back faces with clockwise vertices" then
3529 set front faces to be counter clockwise and enable culling
3531 switch ((D3DCULL) Value) {
3533 glDisable(GL_CULL_FACE);
3534 checkGLcall("glDisable GL_CULL_FACE");
3537 glEnable(GL_CULL_FACE);
3538 checkGLcall("glEnable GL_CULL_FACE");
3539 if (This->renderUpsideDown) {
3541 checkGLcall("glFrontFace GL_CW");
3543 glFrontFace(GL_CCW);
3544 checkGLcall("glFrontFace GL_CCW");
3546 glCullFace(GL_BACK);
3549 glEnable(GL_CULL_FACE);
3550 checkGLcall("glEnable GL_CULL_FACE");
3551 if (This->renderUpsideDown) {
3552 glFrontFace(GL_CCW);
3553 checkGLcall("glFrontFace GL_CCW");
3556 checkGLcall("glFrontFace GL_CW");
3558 glCullFace(GL_BACK);
3561 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3565 case WINED3DRS_SHADEMODE :
3566 switch ((D3DSHADEMODE) Value) {
3568 glShadeModel(GL_FLAT);
3569 checkGLcall("glShadeModel");
3571 case D3DSHADE_GOURAUD:
3572 glShadeModel(GL_SMOOTH);
3573 checkGLcall("glShadeModel");
3575 case D3DSHADE_PHONG:
3576 FIXME("D3DSHADE_PHONG isn't supported?\n");
3579 return WINED3DERR_INVALIDCALL;
3581 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3585 case WINED3DRS_DITHERENABLE :
3587 glEnable(GL_DITHER);
3588 checkGLcall("glEnable GL_DITHER");
3590 glDisable(GL_DITHER);
3591 checkGLcall("glDisable GL_DITHER");
3595 case WINED3DRS_ZWRITEENABLE :
3598 checkGLcall("glDepthMask");
3601 checkGLcall("glDepthMask");
3605 case WINED3DRS_ZFUNC :
3607 int glParm = GL_LESS;
3609 switch ((D3DCMPFUNC) Value) {
3610 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3611 case D3DCMP_LESS: glParm=GL_LESS; break;
3612 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3613 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3614 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3615 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3616 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3617 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3619 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3621 glDepthFunc(glParm);
3622 checkGLcall("glDepthFunc");
3626 case WINED3DRS_AMBIENT :
3629 D3DCOLORTOGLFLOAT4(Value, col);
3630 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3631 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3632 checkGLcall("glLightModel for MODEL_AMBIENT");
3637 case WINED3DRS_ALPHABLENDENABLE :
3640 checkGLcall("glEnable GL_BLEND");
3642 glDisable(GL_BLEND);
3643 checkGLcall("glDisable GL_BLEND");
3647 case WINED3DRS_SRCBLEND :
3648 case WINED3DRS_DESTBLEND :
3650 int newVal = GL_ZERO;
3652 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3653 case D3DBLEND_ONE : newVal = GL_ONE; break;
3654 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3655 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3656 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3657 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3658 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3659 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3660 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3661 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3662 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3664 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3665 This->srcBlend = newVal;
3666 This->dstBlend = newVal;
3669 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3670 This->srcBlend = newVal;
3671 This->dstBlend = newVal;
3674 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3677 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3678 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3679 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3680 glBlendFunc(This->srcBlend, This->dstBlend);
3682 checkGLcall("glBlendFunc");
3686 case WINED3DRS_ALPHATESTENABLE :
3687 case WINED3DRS_ALPHAFUNC :
3688 case WINED3DRS_ALPHAREF :
3689 case WINED3DRS_COLORKEYENABLE :
3692 float ref = GL_LESS;
3693 BOOL enable_ckey = FALSE;
3695 IWineD3DSurfaceImpl *surf;
3697 /* Find out if the texture on the first stage has a ckey set */
3698 if(This->stateBlock->textures[0]) {
3699 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3700 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3703 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3704 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3705 glEnable(GL_ALPHA_TEST);
3706 checkGLcall("glEnable GL_ALPHA_TEST");
3708 glDisable(GL_ALPHA_TEST);
3709 checkGLcall("glDisable GL_ALPHA_TEST");
3710 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3716 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3717 glParm = GL_NOTEQUAL;
3720 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3722 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3723 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3724 case D3DCMP_LESS: glParm = GL_LESS; break;
3725 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3726 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3727 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3728 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3729 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3730 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3732 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3735 This->alphafunc = glParm;
3736 glAlphaFunc(glParm, ref);
3737 checkGLcall("glAlphaFunc");
3741 case WINED3DRS_CLIPPLANEENABLE :
3742 case WINED3DRS_CLIPPING :
3744 /* Ensure we only do the changed clip planes */
3745 DWORD enable = 0xFFFFFFFF;
3746 DWORD disable = 0x00000000;
3748 /* If enabling / disabling all */
3749 if (State == WINED3DRS_CLIPPING) {
3751 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3754 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3758 enable = Value & ~OldValue;
3759 disable = ~Value & OldValue;
3762 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3763 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3764 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3765 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3766 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3767 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3769 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3770 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3771 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3772 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3773 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3774 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3776 /** update clipping status */
3778 This->stateBlock->clip_status.ClipUnion = 0;
3779 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3781 This->stateBlock->clip_status.ClipUnion = 0;
3782 This->stateBlock->clip_status.ClipIntersection = 0;
3787 case WINED3DRS_BLENDOP :
3789 int glParm = GL_FUNC_ADD;
3791 switch ((D3DBLENDOP) Value) {
3792 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3793 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3794 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3795 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3796 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3798 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3801 if(GL_SUPPORT(ARB_IMAGING)) {
3802 TRACE("glBlendEquation(%x)\n", glParm);
3803 GL_EXTCALL(glBlendEquation(glParm));
3804 checkGLcall("glBlendEquation");
3806 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3811 case WINED3DRS_TEXTUREFACTOR :
3815 /* Note the texture color applies to all textures whereas
3816 GL_TEXTURE_ENV_COLOR applies to active only */
3818 D3DCOLORTOGLFLOAT4(Value, col);
3819 /* Set the default alpha blend color */
3820 if (GL_SUPPORT(ARB_IMAGING)) {
3821 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3822 checkGLcall("glBlendColor");
3824 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3827 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3828 /* And now the default texture color as well */
3829 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3830 /* Note the D3DRS value applies to all textures, but GL has one
3831 per texture, so apply it now ready to be used! */
3832 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3833 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3834 checkGLcall("glActiveTextureARB");
3836 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3839 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3840 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3846 case WINED3DRS_SPECULARENABLE :
3848 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3849 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3850 specular color. This is wrong:
3851 Separate specular color means the specular colour is maintained separately, whereas
3852 single color means it is merged in. However in both cases they are being used to
3854 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3855 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3859 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3860 checkGLcall("glMaterialfv");
3861 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3862 glEnable(GL_COLOR_SUM_EXT);
3864 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3866 checkGLcall("glEnable(GL_COLOR_SUM)");
3868 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3870 /* for the case of enabled lighting: */
3871 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3872 checkGLcall("glMaterialfv");
3874 /* for the case of disabled lighting: */
3875 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3876 glDisable(GL_COLOR_SUM_EXT);
3878 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3880 checkGLcall("glDisable(GL_COLOR_SUM)");
3885 case WINED3DRS_STENCILENABLE :
3886 case WINED3DRS_TWOSIDEDSTENCILMODE :
3887 case WINED3DRS_STENCILFUNC :
3888 case WINED3DRS_CCW_STENCILFUNC :
3889 case WINED3DRS_STENCILREF :
3890 case WINED3DRS_STENCILMASK :
3891 case WINED3DRS_STENCILFAIL :
3892 case WINED3DRS_STENCILZFAIL :
3893 case WINED3DRS_STENCILPASS :
3894 case WINED3DRS_CCW_STENCILFAIL :
3895 case WINED3DRS_CCW_STENCILZFAIL :
3896 case WINED3DRS_CCW_STENCILPASS :
3897 renderstate_stencil(This, State, Value);
3899 case WINED3DRS_STENCILWRITEMASK :
3901 glStencilMask(Value);
3902 TRACE("glStencilMask(%lu)\n", Value);
3903 checkGLcall("glStencilMask");
3907 case WINED3DRS_FOGENABLE :
3911 checkGLcall("glEnable GL_FOG");
3914 checkGLcall("glDisable GL_FOG");
3919 case WINED3DRS_RANGEFOGENABLE :
3922 TRACE("Enabled RANGEFOG");
3924 TRACE("Disabled RANGEFOG");
3929 case WINED3DRS_FOGCOLOR :
3932 D3DCOLORTOGLFLOAT4(Value, col);
3933 /* Set the default alpha blend color */
3934 glFogfv(GL_FOG_COLOR, &col[0]);
3935 checkGLcall("glFog GL_FOG_COLOR");
3939 case WINED3DRS_FOGTABLEMODE :
3940 case WINED3DRS_FOGVERTEXMODE :
3942 /* 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." */
3943 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3944 glHint(GL_FOG_HINT, GL_FASTEST);
3945 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3946 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3947 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3948 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3951 if(!This->last_was_rhw) {
3952 glFogi(GL_FOG_MODE, GL_EXP);
3953 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3954 if(GL_SUPPORT(EXT_FOG_COORD)) {
3955 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3956 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3957 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3958 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3964 if(!This->last_was_rhw) {
3965 glFogi(GL_FOG_MODE, GL_EXP2);
3966 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3967 if(GL_SUPPORT(EXT_FOG_COORD)) {
3968 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3969 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3970 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3971 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3976 case D3DFOG_LINEAR: {
3977 if(!This->last_was_rhw) {
3978 glFogi(GL_FOG_MODE, GL_LINEAR);
3979 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3980 if(GL_SUPPORT(EXT_FOG_COORD)) {
3981 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3982 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3983 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3984 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3990 /* Both are none? According to msdn the alpha channel of the specular
3991 * color contains a fog factor. Set it in drawStridedSlow.
3992 * Same happens with Vertexfog on transformed vertices
3994 if(GL_SUPPORT(EXT_FOG_COORD)) {
3995 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3996 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3997 glFogi(GL_FOG_MODE, GL_LINEAR);
3998 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3999 glFogf(GL_FOG_START, (float) 0xff);
4000 checkGLcall("glFogfv GL_FOG_START");
4001 glFogf(GL_FOG_END, 0.0);
4002 checkGLcall("glFogfv GL_FOG_END");
4004 /* Disable GL fog, handle this in software in drawStridedSlow */
4006 checkGLcall("glDisable(GL_FOG)");
4010 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
4013 glHint(GL_FOG_HINT, GL_NICEST);
4014 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
4015 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
4016 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
4017 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
4018 if(GL_SUPPORT(EXT_FOG_COORD)) {
4019 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4020 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4021 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4022 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4025 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
4026 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
4027 if(GL_SUPPORT(EXT_FOG_COORD)) {
4028 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4029 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4030 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4031 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4034 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4035 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4036 if(GL_SUPPORT(EXT_FOG_COORD)) {
4037 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4038 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4039 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4040 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4043 case D3DFOG_NONE: /* Won't happen */
4044 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4047 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4048 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4053 case WINED3DRS_FOGSTART :
4056 glFogfv(GL_FOG_START, &tmpvalue.f);
4057 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4058 TRACE("Fog Start == %f\n", tmpvalue.f);
4062 case WINED3DRS_FOGEND :
4065 glFogfv(GL_FOG_END, &tmpvalue.f);
4066 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4067 TRACE("Fog End == %f\n", tmpvalue.f);
4071 case WINED3DRS_FOGDENSITY :
4074 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4075 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4079 case WINED3DRS_VERTEXBLEND :
4081 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4082 TRACE("Vertex Blending state to %ld\n", Value);
4086 case WINED3DRS_TWEENFACTOR :
4089 This->updateStateBlock->tween_factor = tmpvalue.f;
4090 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4094 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4096 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4100 case WINED3DRS_COLORVERTEX :
4101 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4102 case WINED3DRS_SPECULARMATERIALSOURCE :
4103 case WINED3DRS_AMBIENTMATERIALSOURCE :
4104 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4106 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4108 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4109 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4110 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4111 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4112 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4113 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4115 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4116 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4117 Parm = GL_AMBIENT_AND_DIFFUSE;
4121 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4123 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4125 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4132 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4134 This->tracking_color = NEEDS_TRACKING;
4135 This->tracking_parm = Parm;
4139 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4144 case WINED3DRS_LINEPATTERN :
4150 tmppattern.d = Value;
4152 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4154 if (tmppattern.lp.wRepeatFactor) {
4155 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4156 checkGLcall("glLineStipple(repeat, linepattern)");
4157 glEnable(GL_LINE_STIPPLE);
4158 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4160 glDisable(GL_LINE_STIPPLE);
4161 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4166 case WINED3DRS_ZBIAS : /* D3D8 only */
4170 TRACE("ZBias value %f\n", tmpvalue.f);
4171 glPolygonOffset(0, -tmpvalue.f);
4172 checkGLcall("glPolygonOffset(0, -Value)");
4173 glEnable(GL_POLYGON_OFFSET_FILL);
4174 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4175 glEnable(GL_POLYGON_OFFSET_LINE);
4176 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4177 glEnable(GL_POLYGON_OFFSET_POINT);
4178 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4180 glDisable(GL_POLYGON_OFFSET_FILL);
4181 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4182 glDisable(GL_POLYGON_OFFSET_LINE);
4183 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4184 glDisable(GL_POLYGON_OFFSET_POINT);
4185 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4190 case WINED3DRS_NORMALIZENORMALS :
4192 glEnable(GL_NORMALIZE);
4193 checkGLcall("glEnable(GL_NORMALIZE);");
4195 glDisable(GL_NORMALIZE);
4196 checkGLcall("glDisable(GL_NORMALIZE);");
4200 case WINED3DRS_POINTSIZE :
4201 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4203 TRACE("Set point size to %f\n", tmpvalue.f);
4204 glPointSize(tmpvalue.f);
4205 checkGLcall("glPointSize(...);");
4208 case WINED3DRS_POINTSIZE_MIN :
4209 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4211 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4212 checkGLcall("glPointParameterfEXT(...);");
4214 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4218 case WINED3DRS_POINTSIZE_MAX :
4219 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4221 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4222 checkGLcall("glPointParameterfEXT(...);");
4224 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4228 case WINED3DRS_POINTSCALE_A :
4229 case WINED3DRS_POINTSCALE_B :
4230 case WINED3DRS_POINTSCALE_C :
4231 case WINED3DRS_POINTSCALEENABLE :
4234 * POINTSCALEENABLE controls how point size value is treated. If set to
4235 * true, the point size is scaled with respect to height of viewport.
4236 * When set to false point size is in pixels.
4238 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4241 /* Default values */
4242 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4245 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4246 * This means that OpenGL will clamp really small point sizes to 1.0f.
4247 * To correct for this we need to multiply by the scale factor when sizes
4248 * are less than 1.0f. scale_factor = 1.0f / point_size.
4250 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4251 if(pointSize > 0.0f) {
4252 GLfloat scaleFactor;
4254 if(pointSize < 1.0f) {
4255 scaleFactor = pointSize * pointSize;
4260 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4261 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4262 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4263 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4264 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4265 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4266 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4270 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4271 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4272 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4274 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4275 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4276 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4278 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4282 case WINED3DRS_COLORWRITEENABLE :
4284 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4285 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4286 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4287 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4288 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4289 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4290 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4291 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4292 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4293 checkGLcall("glColorMask(...)");
4297 case WINED3DRS_LOCALVIEWER :
4299 GLint state = (Value) ? 1 : 0;
4300 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4301 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4305 case WINED3DRS_LASTPIXEL :
4308 TRACE("Last Pixel Drawing Enabled\n");
4310 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4315 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4318 TRACE("Software Processing Enabled\n");
4320 TRACE("Software Processing Disabled\n");
4325 /** not supported */
4326 case WINED3DRS_ZVISIBLE :
4329 return WINED3DERR_INVALIDCALL;
4331 case WINED3DRS_POINTSPRITEENABLE :
4333 /* TODO: NV_POINT_SPRITE */
4334 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4335 TRACE("Point sprites not supported\n");
4340 * Point sprites are always enabled. Value controls texture coordinate
4341 * replacement mode. Must be set true for point sprites to use
4344 glEnable(GL_POINT_SPRITE_ARB);
4345 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4348 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4349 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4351 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4352 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4356 case WINED3DRS_EDGEANTIALIAS :
4359 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4361 checkGLcall("glEnable(GL_BLEND)");
4362 glEnable(GL_LINE_SMOOTH);
4363 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4365 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4366 glDisable(GL_BLEND);
4367 checkGLcall("glDisable(GL_BLEND)");
4369 glDisable(GL_LINE_SMOOTH);
4370 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4374 case WINED3DRS_WRAP0 :
4375 case WINED3DRS_WRAP1 :
4376 case WINED3DRS_WRAP2 :
4377 case WINED3DRS_WRAP3 :
4378 case WINED3DRS_WRAP4 :
4379 case WINED3DRS_WRAP5 :
4380 case WINED3DRS_WRAP6 :
4381 case WINED3DRS_WRAP7 :
4382 case WINED3DRS_WRAP8 :
4383 case WINED3DRS_WRAP9 :
4384 case WINED3DRS_WRAP10 :
4385 case WINED3DRS_WRAP11 :
4386 case WINED3DRS_WRAP12 :
4387 case WINED3DRS_WRAP13 :
4388 case WINED3DRS_WRAP14 :
4389 case WINED3DRS_WRAP15 :
4391 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4392 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4393 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4394 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4395 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4397 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4399 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4401 case WINED3DRS_MULTISAMPLEANTIALIAS :
4403 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4404 TRACE("Multisample antialiasing not supported\n");
4409 glEnable(GL_MULTISAMPLE_ARB);
4410 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4412 glDisable(GL_MULTISAMPLE_ARB);
4413 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4417 case WINED3DRS_SCISSORTESTENABLE :
4420 glEnable(GL_SCISSOR_TEST);
4421 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4423 glDisable(GL_SCISSOR_TEST);
4424 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4428 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4432 glEnable(GL_POLYGON_OFFSET_FILL);
4433 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4434 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4435 checkGLcall("glPolygonOffset(...)");
4437 glDisable(GL_POLYGON_OFFSET_FILL);
4438 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4442 case WINED3DRS_ANTIALIASEDLINEENABLE :
4445 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4447 checkGLcall("glEnable(GL_BLEND)");
4448 glEnable(GL_LINE_SMOOTH);
4449 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4451 glDisable(GL_BLEND);
4452 checkGLcall("glDisable(GL_BLEND)");
4453 glDisable(GL_LINE_SMOOTH);
4454 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4458 case WINED3DRS_DEPTHBIAS :
4462 glEnable(GL_POLYGON_OFFSET_FILL);
4463 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4464 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4465 checkGLcall("glPolygonOffset(...)");
4467 glDisable(GL_POLYGON_OFFSET_FILL);
4468 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4473 case WINED3DRS_TEXTUREPERSPECTIVE :
4476 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4478 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4482 case WINED3DRS_STIPPLEDALPHA :
4485 ERR(" Stippled Alpha not supported yet.\n");
4488 case WINED3DRS_ANTIALIAS :
4491 ERR(" Antialias not supported yet.\n");
4495 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4506 *pValue = This->stateBlock->renderState[State];
4511 * Get / Set Sampler States
4512 * TODO: Verify against dx9 definitions
4515 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 * SetSampler is designed to allow for more than the standard up to 8 textures
4519 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4520 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4522 * http://developer.nvidia.com/object/General_FAQ.html#t6
4524 * There are two new settings for GForce
4526 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4527 * and the texture one:
4528 * GL_MAX_TEXTURE_COORDS_ARB.
4529 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4531 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4532 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4533 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4534 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4535 return WINED3DERR_INVALIDCALL;
4538 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4539 debug_d3dsamplerstate(Type), Type, Value);
4540 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4541 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4542 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4544 /* Handle recording of state blocks */
4545 if (This->isRecordingState) {
4546 TRACE("Recording... not performing anything\n");
4553 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4555 /** TODO: check that sampler is in range **/
4556 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4557 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4562 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4567 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4568 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4574 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 GLint scissorBox[4];
4579 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4580 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4581 pRect->left = scissorBox[0];
4582 pRect->top = scissorBox[1];
4583 pRect->right = scissorBox[0] + scissorBox[2];
4584 pRect->bottom = scissorBox[1] + scissorBox[3];
4585 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4592 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4594 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4596 This->updateStateBlock->vertexDecl = pDecl;
4597 This->updateStateBlock->changed.vertexDecl = TRUE;
4598 This->updateStateBlock->set.vertexDecl = TRUE;
4600 if (This->isRecordingState) {
4601 TRACE("Recording... not performing anything\n");
4604 if (NULL != pDecl) {
4605 IWineD3DVertexDeclaration_AddRef(pDecl);
4607 if (NULL != oldDecl) {
4608 IWineD3DVertexDeclaration_Release(oldDecl);
4613 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4618 *ppDecl = This->stateBlock->vertexDecl;
4619 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4623 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4627 This->updateStateBlock->vertexShader = pShader;
4628 This->updateStateBlock->changed.vertexShader = TRUE;
4629 This->updateStateBlock->set.vertexShader = TRUE;
4631 if (This->isRecordingState) {
4632 TRACE("Recording... not performing anything\n");
4635 if (NULL != pShader) {
4636 IWineD3DVertexShader_AddRef(pShader);
4638 if (NULL != oldShader) {
4639 IWineD3DVertexShader_Release(oldShader);
4642 if (pShader != NULL && ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration != NULL) {
4643 TRACE("(%p) : setting vertexDeclaration(%p)\n", This, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4644 IWineD3DDevice_SetVertexDeclaration(iface, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4647 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4649 * TODO: merge HAL shaders context switching from prototype
4654 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4657 if (NULL == ppShader) {
4658 return WINED3DERR_INVALIDCALL;
4660 *ppShader = This->stateBlock->vertexShader;
4661 if( NULL != *ppShader)
4662 IWineD3DVertexShader_AddRef(*ppShader);
4664 TRACE("(%p) : returning %p\n", This, *ppShader);
4668 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4669 IWineD3DDevice *iface,
4671 CONST BOOL *srcData,
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4677 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4678 iface, srcData, start, count);
4680 if (srcData == NULL || cnt < 0)
4681 return WINED3DERR_INVALIDCALL;
4683 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4684 for (i = 0; i < cnt; i++)
4685 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4687 for (i = start; i < cnt + start; ++i) {
4688 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4689 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4695 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4696 IWineD3DDevice *iface,
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4702 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4704 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4705 iface, dstData, start, count);
4707 if (dstData == NULL || cnt < 0)
4708 return WINED3DERR_INVALIDCALL;
4710 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4714 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4715 IWineD3DDevice *iface,
4720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4721 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4723 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4724 iface, srcData, start, count);
4726 if (srcData == NULL || cnt < 0)
4727 return WINED3DERR_INVALIDCALL;
4729 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4730 for (i = 0; i < cnt; i++)
4731 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4732 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4734 for (i = start; i < cnt + start; ++i) {
4735 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4736 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4742 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4743 IWineD3DDevice *iface,
4748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4749 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4751 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4752 iface, dstData, start, count);
4754 if (dstData == NULL || cnt < 0)
4755 return WINED3DERR_INVALIDCALL;
4757 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4761 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4762 IWineD3DDevice *iface,
4764 CONST float *srcData,
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4770 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4771 iface, srcData, start, count);
4773 if (srcData == NULL || cnt < 0)
4774 return WINED3DERR_INVALIDCALL;
4776 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4777 for (i = 0; i < cnt; i++)
4778 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4779 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4781 for (i = start; i < cnt + start; ++i) {
4782 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4783 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4790 IWineD3DDevice *iface,
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4799 iface, dstData, start, count);
4801 if (dstData == NULL || cnt < 0)
4802 return WINED3DERR_INVALIDCALL;
4804 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4808 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4810 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4811 This->updateStateBlock->pixelShader = pShader;
4812 This->updateStateBlock->changed.pixelShader = TRUE;
4813 This->updateStateBlock->set.pixelShader = TRUE;
4815 /* Handle recording of state blocks */
4816 if (This->isRecordingState) {
4817 TRACE("Recording... not performing anything\n");
4820 if (NULL != pShader) {
4821 IWineD3DPixelShader_AddRef(pShader);
4823 if (NULL != oldShader) {
4824 IWineD3DPixelShader_Release(oldShader);
4827 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4829 * TODO: merge HAL shaders context switching from prototype
4834 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4837 if (NULL == ppShader) {
4838 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4839 return WINED3DERR_INVALIDCALL;
4842 *ppShader = This->stateBlock->pixelShader;
4843 if (NULL != *ppShader) {
4844 IWineD3DPixelShader_AddRef(*ppShader);
4846 TRACE("(%p) : returning %p\n", This, *ppShader);
4850 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4851 IWineD3DDevice *iface,
4853 CONST BOOL *srcData,
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4857 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4859 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4860 iface, srcData, start, count);
4862 if (srcData == NULL || cnt < 0)
4863 return WINED3DERR_INVALIDCALL;
4865 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4866 for (i = 0; i < cnt; i++)
4867 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4869 for (i = start; i < cnt + start; ++i) {
4870 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4871 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4877 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4878 IWineD3DDevice *iface,
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4884 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4886 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4887 iface, dstData, start, count);
4889 if (dstData == NULL || cnt < 0)
4890 return WINED3DERR_INVALIDCALL;
4892 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4896 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4897 IWineD3DDevice *iface,
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4905 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4906 iface, srcData, start, count);
4908 if (srcData == NULL || cnt < 0)
4909 return WINED3DERR_INVALIDCALL;
4911 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4912 for (i = 0; i < cnt; i++)
4913 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4914 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4916 for (i = start; i < cnt + start; ++i) {
4917 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4918 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4924 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4925 IWineD3DDevice *iface,
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4933 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4934 iface, dstData, start, count);
4936 if (dstData == NULL || cnt < 0)
4937 return WINED3DERR_INVALIDCALL;
4939 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4943 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4944 IWineD3DDevice *iface,
4946 CONST float *srcData,
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4950 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4953 iface, srcData, start, count);
4955 if (srcData == NULL || cnt < 0)
4956 return WINED3DERR_INVALIDCALL;
4958 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4959 for (i = 0; i < cnt; i++)
4960 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4961 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4963 for (i = start; i < cnt + start; ++i) {
4964 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4965 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4971 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4972 IWineD3DDevice *iface,
4977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4978 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4981 iface, dstData, start, count);
4983 if (dstData == NULL || cnt < 0)
4984 return WINED3DERR_INVALIDCALL;
4986 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4990 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4992 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4993 char *dest_ptr, *dest_conv = NULL;
4995 DWORD DestFVF = dest->fvf;
4997 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5001 if (SrcFVF & D3DFVF_NORMAL) {
5002 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5005 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5006 ERR("Source has no position mask\n");
5007 return WINED3DERR_INVALIDCALL;
5010 /* We might access VBOs from this code, so hold the lock */
5013 if (dest->resource.allocatedMemory == NULL) {
5014 /* This may happen if we do direct locking into a vbo. Unlikely,
5015 * but theoretically possible(ddraw processvertices test)
5017 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5018 if(!dest->resource.allocatedMemory) {
5020 ERR("Out of memory\n");
5021 return E_OUTOFMEMORY;
5025 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5026 checkGLcall("glBindBufferARB");
5027 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5029 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5031 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5032 checkGLcall("glUnmapBufferARB");
5036 /* Get a pointer into the destination vbo(create one if none exists) and
5037 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5039 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5044 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5045 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5047 ERR("glMapBuffer failed\n");
5048 /* Continue without storing converted vertices */
5053 * a) D3DRS_CLIPPING is enabled
5054 * b) WINED3DVOP_CLIP is passed
5056 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5057 static BOOL warned = FALSE;
5059 * The clipping code is not quite correct. Some things need
5060 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5061 * so disable clipping for now.
5062 * (The graphics in Half-Life are broken, and my processvertices
5063 * test crashes with IDirect3DDevice3)
5069 FIXME("Clipping is broken and disabled for now\n");
5071 } else doClip = FALSE;
5072 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5074 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5077 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5080 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5083 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5084 D3DTS_WORLDMATRIX(0),
5087 TRACE("View mat:\n");
5088 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); \
5089 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); \
5090 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); \
5091 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); \
5093 TRACE("Proj mat:\n");
5094 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); \
5095 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); \
5096 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); \
5097 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); \
5099 TRACE("World mat:\n");
5100 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); \
5101 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); \
5102 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); \
5103 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); \
5105 /* Get the viewport */
5106 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5107 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5108 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5110 multiply_matrix(&mat,&view_mat,&world_mat);
5111 multiply_matrix(&mat,&proj_mat,&mat);
5113 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5115 for (i = 0; i < dwCount; i+= 1) {
5116 unsigned int tex_index;
5118 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5119 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5120 /* The position first */
5122 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5124 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5126 /* Multiplication with world, view and projection matrix */
5127 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);
5128 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);
5129 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);
5130 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);
5132 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5134 /* WARNING: The following things are taken from d3d7 and were not yet checked
5135 * against d3d8 or d3d9!
5138 /* Clipping conditions: From
5139 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5141 * A vertex is clipped if it does not match the following requirements
5145 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5147 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5148 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5152 if( doClip == FALSE ||
5153 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5154 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5157 /* "Normal" viewport transformation (not clipped)
5158 * 1) The values are divided by rhw
5159 * 2) The y axis is negative, so multiply it with -1
5160 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5161 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5162 * 4) Multiply x with Width/2 and add Width/2
5163 * 5) The same for the height
5164 * 6) Add the viewpoint X and Y to the 2D coordinates and
5165 * The minimum Z value to z
5166 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5168 * Well, basically it's simply a linear transformation into viewport
5180 z *= vp.MaxZ - vp.MinZ;
5182 x += vp.Width / 2 + vp.X;
5183 y += vp.Height / 2 + vp.Y;
5188 /* That vertex got clipped
5189 * Contrary to OpenGL it is not dropped completely, it just
5190 * undergoes a different calculation.
5192 TRACE("Vertex got clipped\n");
5199 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5200 * outside of the main vertex buffer memory. That needs some more
5205 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5208 ( (float *) dest_ptr)[0] = x;
5209 ( (float *) dest_ptr)[1] = y;
5210 ( (float *) dest_ptr)[2] = z;
5211 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5213 dest_ptr += 3 * sizeof(float);
5215 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5216 dest_ptr += sizeof(float);
5221 ( (float *) dest_conv)[0] = x * w;
5222 ( (float *) dest_conv)[1] = y * w;
5223 ( (float *) dest_conv)[2] = z * w;
5224 ( (float *) dest_conv)[3] = w;
5226 dest_conv += 3 * sizeof(float);
5228 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5229 dest_conv += sizeof(float);
5233 if (DestFVF & D3DFVF_PSIZE) {
5234 dest_ptr += sizeof(DWORD);
5235 if(dest_conv) dest_conv += sizeof(DWORD);
5237 if (DestFVF & D3DFVF_NORMAL) {
5239 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5240 /* AFAIK this should go into the lighting information */
5241 FIXME("Didn't expect the destination to have a normal\n");
5242 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5244 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5248 if (DestFVF & D3DFVF_DIFFUSE) {
5250 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5252 static BOOL warned = FALSE;
5254 if(warned == FALSE) {
5255 ERR("No diffuse color in source, but destination has one\n");
5259 *( (DWORD *) dest_ptr) = 0xffffffff;
5260 dest_ptr += sizeof(DWORD);
5263 *( (DWORD *) dest_conv) = 0xffffffff;
5264 dest_conv += sizeof(DWORD);
5268 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5270 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5271 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5272 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5273 dest_conv += sizeof(DWORD);
5278 if (DestFVF & D3DFVF_SPECULAR) {
5279 /* What's the color value in the feedback buffer? */
5281 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5283 static BOOL warned = FALSE;
5285 if(warned == FALSE) {
5286 ERR("No specular color in source, but destination has one\n");
5290 *( (DWORD *) dest_ptr) = 0xFF000000;
5291 dest_ptr += sizeof(DWORD);
5294 *( (DWORD *) dest_conv) = 0xFF000000;
5295 dest_conv += sizeof(DWORD);
5299 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5301 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5302 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5303 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5304 dest_conv += sizeof(DWORD);
5309 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5311 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5312 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5314 ERR("No source texture, but destination requests one\n");
5315 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5316 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5319 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5321 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5328 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5329 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5336 #undef copy_and_next
5338 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5341 WineDirect3DVertexStridedData strided;
5342 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5344 /* We don't need the source vbo because this buffer is only used as
5345 * a source for ProcessVertices. Avoid wasting resources by converting the
5346 * buffer and loading the VBO
5349 TRACE("Releaseing the source vbo, it won't be needed\n");
5351 if(!SrcImpl->resource.allocatedMemory) {
5352 /* Rescue the data from the buffer */
5354 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5355 if(!SrcImpl->resource.allocatedMemory) {
5356 ERR("Out of memory\n");
5357 return E_OUTOFMEMORY;
5361 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5362 checkGLcall("glBindBufferARB");
5364 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5366 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5369 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5370 checkGLcall("glUnmapBufferARB");
5375 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5376 checkGLcall("glBindBufferARB");
5377 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5378 checkGLcall("glDeleteBuffersARB");
5384 memset(&strided, 0, sizeof(strided));
5385 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5387 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5391 * Apply / Get / Set Texture Stage States
5392 * TODO: Verify against dx9 definitions
5395 /* 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 */
5396 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5398 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5399 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5401 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5403 /* Check that the stage is within limits */
5404 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5405 TRACE("Attempt to access invalid texture rejected\n");
5412 case WINED3DTSS_ALPHAOP :
5413 case WINED3DTSS_COLOROP :
5414 /* nothing to do as moved to drawprim for now */
5416 case WINED3DTSS_ADDRESSW :
5417 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5418 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5419 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5422 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5423 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5424 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5425 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5428 case WINED3DTSS_TEXCOORDINDEX :
5430 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5432 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5433 one flag, you can still specify an index value, which the system uses to
5434 determine the texture wrapping mode.
5435 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5436 means use the vertex position (camera-space) as the input texture coordinates
5437 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5438 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5439 to the TEXCOORDINDEX value */
5442 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5444 switch (Value & 0xFFFF0000) {
5445 case D3DTSS_TCI_PASSTHRU:
5446 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5447 glDisable(GL_TEXTURE_GEN_S);
5448 glDisable(GL_TEXTURE_GEN_T);
5449 glDisable(GL_TEXTURE_GEN_R);
5450 glDisable(GL_TEXTURE_GEN_Q);
5451 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5454 case D3DTSS_TCI_CAMERASPACEPOSITION:
5455 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5456 as the input texture coordinates for this stage's texture transformation. This
5457 equates roughly to EYE_LINEAR */
5459 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5460 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5461 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5462 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5463 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5465 glMatrixMode(GL_MODELVIEW);
5468 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5469 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5470 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5471 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5474 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5475 glEnable(GL_TEXTURE_GEN_S);
5476 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5477 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5478 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5479 glEnable(GL_TEXTURE_GEN_T);
5480 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5481 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5482 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5483 glEnable(GL_TEXTURE_GEN_R);
5484 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5485 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5486 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5490 case D3DTSS_TCI_CAMERASPACENORMAL:
5492 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5493 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5494 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5495 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5496 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5497 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5499 glMatrixMode(GL_MODELVIEW);
5502 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5503 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5504 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5505 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5508 glEnable(GL_TEXTURE_GEN_S);
5509 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5510 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5511 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5512 glEnable(GL_TEXTURE_GEN_T);
5513 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5514 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5515 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5516 glEnable(GL_TEXTURE_GEN_R);
5517 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5518 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5519 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5524 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5526 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5527 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5528 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5529 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5530 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5531 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5533 glMatrixMode(GL_MODELVIEW);
5536 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5537 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5538 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5539 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5542 glEnable(GL_TEXTURE_GEN_S);
5543 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5544 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5545 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5546 glEnable(GL_TEXTURE_GEN_T);
5547 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5548 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5549 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5550 glEnable(GL_TEXTURE_GEN_R);
5551 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5552 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5553 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5558 /* Unhandled types: */
5561 /* ? disable GL_TEXTURE_GEN_n ? */
5562 glDisable(GL_TEXTURE_GEN_S);
5563 glDisable(GL_TEXTURE_GEN_T);
5564 glDisable(GL_TEXTURE_GEN_R);
5565 glDisable(GL_TEXTURE_GEN_Q);
5566 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5573 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5574 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5577 case WINED3DTSS_BUMPENVMAT00 :
5578 case WINED3DTSS_BUMPENVMAT01 :
5579 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5581 case WINED3DTSS_BUMPENVMAT10 :
5582 case WINED3DTSS_BUMPENVMAT11 :
5583 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5586 case WINED3DTSS_BUMPENVLSCALE :
5587 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5590 case WINED3DTSS_BUMPENVLOFFSET :
5591 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5594 case WINED3DTSS_RESULTARG :
5595 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5599 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5600 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5609 * Get / Set Texture Stage States
5610 * TODO: Verify against dx9 definitions
5612 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5617 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5619 /* Reject invalid texture units */
5620 if (Stage >= GL_LIMITS(texture_stages)) {
5621 TRACE("Attempt to access invalid texture rejected\n");
5622 return WINED3DERR_INVALIDCALL;
5625 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5626 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5627 This->updateStateBlock->textureState[Stage][Type] = Value;
5632 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5635 *pValue = This->updateStateBlock->textureState[Stage][Type];
5642 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5645 IWineD3DBaseTexture *oldTexture;
5647 oldTexture = This->updateStateBlock->textures[Stage];
5648 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5650 #if 0 /* TODO: check so vertex textures */
5651 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5652 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5657 /* Reject invalid texture units */
5658 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5659 WARN("Attempt to access invalid texture rejected\n");
5660 return WINED3DERR_INVALIDCALL;
5663 if(pTexture != NULL) {
5664 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5666 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5667 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5668 return WINED3DERR_INVALIDCALL;
5672 oldTexture = This->updateStateBlock->textures[Stage];
5673 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5674 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5676 This->updateStateBlock->set.textures[Stage] = TRUE;
5677 This->updateStateBlock->changed.textures[Stage] = TRUE;
5678 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5679 This->updateStateBlock->textures[Stage] = pTexture;
5681 /* Handle recording of state blocks */
5682 if (This->isRecordingState) {
5683 TRACE("Recording... not performing anything\n");
5687 /** NOTE: MSDN says that setTexture increases the reference count,
5688 * and the the application nust set the texture back to null (or have a leaky application),
5689 * This means we should pass the refcount up to the parent
5690 *******************************/
5691 if (NULL != This->updateStateBlock->textures[Stage]) {
5692 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5695 if (NULL != oldTexture) {
5696 IWineD3DBaseTexture_Release(oldTexture);
5699 /* Reset color keying */
5700 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5701 BOOL enable_ckey = FALSE;
5704 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5705 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5709 glAlphaFunc(GL_NOTEQUAL, 0.0);
5710 checkGLcall("glAlphaFunc");
5717 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5719 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5721 /* Reject invalid texture units */
5722 if (Stage >= GL_LIMITS(sampler_stages)) {
5723 TRACE("Attempt to access invalid texture rejected\n");
5724 return WINED3DERR_INVALIDCALL;
5726 *ppTexture=This->updateStateBlock->textures[Stage];
5728 IWineD3DBaseTexture_AddRef(*ppTexture);
5730 return WINED3DERR_INVALIDCALL;
5737 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5738 IWineD3DSurface **ppBackBuffer) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 IWineD3DSwapChain *swapChain;
5743 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5745 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5746 if (hr == WINED3D_OK) {
5747 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5748 IWineD3DSwapChain_Release(swapChain);
5750 *ppBackBuffer = NULL;
5755 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 WARN("(%p) : stub, calling idirect3d for now\n", This);
5758 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5761 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 IWineD3DSwapChain *swapChain;
5766 if(iSwapChain > 0) {
5767 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5768 if (hr == WINED3D_OK) {
5769 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5770 IWineD3DSwapChain_Release(swapChain);
5772 FIXME("(%p) Error getting display mode\n", This);
5775 /* Don't read the real display mode,
5776 but return the stored mode instead. X11 can't change the color
5777 depth, and some apps are pretty angry if they SetDisplayMode from
5778 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5780 Also don't relay to the swapchain because with ddraw it's possible
5781 that there isn't a swapchain at all */
5782 pMode->Width = This->ddraw_width;
5783 pMode->Height = This->ddraw_height;
5784 pMode->Format = This->ddraw_format;
5785 pMode->RefreshRate = 0;
5792 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 TRACE("(%p)->(%p)\n", This, hWnd);
5796 This->ddraw_window = hWnd;
5800 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 TRACE("(%p)->(%p)\n", This, hWnd);
5804 *hWnd = This->ddraw_window;
5809 * Stateblock related functions
5812 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5814 IWineD3DStateBlockImpl *object;
5815 TRACE("(%p)", This);
5817 if (This->isRecordingState) {
5818 return WINED3DERR_INVALIDCALL;
5821 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5822 if (NULL == object ) {
5823 FIXME("(%p)Error allocating memory for stateblock\n", This);
5824 return E_OUTOFMEMORY;
5826 TRACE("(%p) creted object %p\n", This, object);
5827 object->wineD3DDevice= This;
5828 /** FIXME: object->parent = parent; **/
5829 object->parent = NULL;
5830 object->blockType = WINED3DSBT_ALL;
5832 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5834 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5835 This->updateStateBlock = object;
5836 This->isRecordingState = TRUE;
5838 TRACE("(%p) recording stateblock %p\n",This , object);
5842 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5845 if (!This->isRecordingState) {
5846 FIXME("(%p) not recording! returning error\n", This);
5847 *ppStateBlock = NULL;
5848 return WINED3DERR_INVALIDCALL;
5851 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5852 This->isRecordingState = FALSE;
5853 This->updateStateBlock = This->stateBlock;
5854 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5855 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5856 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5861 * Scene related functions
5863 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5864 /* At the moment we have no need for any functionality at the beginning
5866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5867 TRACE("(%p) : stub\n", This);
5871 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5873 TRACE("(%p)\n", This);
5875 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5877 checkGLcall("glFlush");
5879 TRACE("End Scene\n");
5880 if(This->renderTarget != NULL) {
5882 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5883 IUnknown *targetContainer = NULL;
5884 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5885 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5886 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5887 /** always dirtify for now. we must find a better way to see that surface have been modified
5888 (Modifications should will only occur via draw-primitive, but we do need better locking
5889 switching to render-to-texture should remove the overhead though.
5891 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5892 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5893 IWineD3DSurface_PreLoad(This->renderTarget);
5894 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5895 IUnknown_Release(targetContainer);
5898 This->sceneEnded = TRUE;
5903 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5904 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5905 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5907 IWineD3DSwapChain *swapChain = NULL;
5909 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5911 TRACE("(%p) Presenting the frame\n", This);
5913 for(i = 0 ; i < swapchains ; i ++) {
5915 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5916 TRACE("presentinng chain %d, %p\n", i, swapChain);
5917 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5918 IWineD3DSwapChain_Release(swapChain);
5924 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5925 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5928 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5929 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5930 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5931 GLbitfield glMask = 0;
5932 GLboolean old_ztest;
5933 GLfloat old_z_clear_value;
5934 GLint old_stencil_clear_value;
5935 GLfloat old_color_clear_value[4];
5937 CONST D3DRECT* curRect;
5939 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5940 Count, pRects, Flags, Z, Stencil);
5944 glEnable(GL_SCISSOR_TEST);
5945 checkGLcall("glEnable GL_SCISSOR_TEST");
5947 if (Count > 0 && pRects) {
5953 /* Only set the values up once, as they are not changing */
5954 if (Flags & D3DCLEAR_STENCIL) {
5955 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5956 glClearStencil(Stencil);
5957 checkGLcall("glClearStencil");
5958 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5959 glStencilMask(0xFFFFFFFF);
5962 if (Flags & D3DCLEAR_ZBUFFER) {
5963 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5964 glDepthMask(GL_TRUE);
5965 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5967 checkGLcall("glClearDepth");
5968 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5971 if (Flags & D3DCLEAR_TARGET) {
5972 TRACE("Clearing screen with glClear to color %lx\n", Color);
5973 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5974 glClearColor(D3DCOLOR_R(Color),
5978 checkGLcall("glClearColor");
5980 /* Clear ALL colors! */
5981 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5982 glMask = glMask | GL_COLOR_BUFFER_BIT;
5985 /* Now process each rect in turn */
5986 for (i = 0; i < Count || i == 0; i++) {
5989 /* Note gl uses lower left, width/height */
5990 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5991 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5992 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5993 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5994 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5995 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5996 checkGLcall("glScissor");
5998 glScissor(This->stateBlock->viewport.X,
5999 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6000 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6001 This->stateBlock->viewport.Width,
6002 This->stateBlock->viewport.Height);
6003 checkGLcall("glScissor");
6006 /* Clear the selected rectangle (or full screen) */
6008 checkGLcall("glClear");
6010 /* Step to the next rectangle */
6011 if (curRect) curRect = curRect + sizeof(D3DRECT);
6014 /* Restore the old values (why..?) */
6015 if (Flags & D3DCLEAR_STENCIL) {
6016 glClearStencil(old_stencil_clear_value);
6017 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6019 if (Flags & D3DCLEAR_ZBUFFER) {
6020 glDepthMask(old_ztest);
6021 glClearDepth(old_z_clear_value);
6023 if (Flags & D3DCLEAR_TARGET) {
6024 glClearColor(old_color_clear_value[0],
6025 old_color_clear_value[1],
6026 old_color_clear_value[2],
6027 old_color_clear_value[3]);
6028 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6029 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6030 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6031 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6034 glDisable(GL_SCISSOR_TEST);
6035 checkGLcall("glDisable");
6044 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6045 UINT PrimitiveCount) {
6047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6048 This->stateBlock->streamIsUP = FALSE;
6050 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6051 debug_d3dprimitivetype(PrimitiveType),
6052 StartVertex, PrimitiveCount);
6053 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6054 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6060 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6061 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6062 D3DPRIMITIVETYPE PrimitiveType,
6063 INT baseVIndex, UINT minIndex,
6064 UINT NumVertices, UINT startIndex, UINT primCount) {
6066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6068 IWineD3DIndexBuffer *pIB;
6069 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6071 pIB = This->stateBlock->pIndexData;
6072 This->stateBlock->streamIsUP = FALSE;
6074 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6075 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6076 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6078 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6079 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6085 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6086 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6091 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6092 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6093 UINT VertexStreamZeroStride) {
6094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6096 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6097 debug_d3dprimitivetype(PrimitiveType),
6098 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6100 /* release the stream source */
6101 if (This->stateBlock->streamSource[0] != NULL) {
6102 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6105 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6106 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6107 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6108 This->stateBlock->streamIsUP = TRUE;
6110 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6111 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6113 /* MSDN specifies stream zero settings must be set to NULL */
6114 This->stateBlock->streamStride[0] = 0;
6115 This->stateBlock->streamSource[0] = NULL;
6117 /*stream zero settings set to null at end, as per the msdn */
6121 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6122 UINT MinVertexIndex, UINT NumVertices,
6123 UINT PrimitiveCount, CONST void* pIndexData,
6124 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6125 UINT VertexStreamZeroStride) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6129 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6130 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6131 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6132 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6134 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6140 /* release the stream and index data */
6141 if (This->stateBlock->streamSource[0] != NULL) {
6142 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6144 if (This->stateBlock->pIndexData) {
6145 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6148 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6149 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6150 This->stateBlock->streamIsUP = TRUE;
6151 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6153 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6155 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6156 This->stateBlock->streamSource[0] = NULL;
6157 This->stateBlock->streamStride[0] = 0;
6158 This->stateBlock->pIndexData = NULL;
6163 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6165 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6168 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6169 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6171 HRESULT hr = WINED3D_OK;
6172 WINED3DRESOURCETYPE sourceType;
6173 WINED3DRESOURCETYPE destinationType;
6176 /* TODO: think about moving the code into IWineD3DBaseTexture */
6178 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6180 /* verify that the source and destination textures aren't NULL */
6181 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6182 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6183 This, pSourceTexture, pDestinationTexture);
6184 hr = WINED3DERR_INVALIDCALL;
6187 if (pSourceTexture == pDestinationTexture) {
6188 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6189 This, pSourceTexture, pDestinationTexture);
6190 hr = WINED3DERR_INVALIDCALL;
6192 /* Verify that the source and destination textures are the same type */
6193 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6194 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6196 if (sourceType != destinationType) {
6197 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6199 hr = WINED3DERR_INVALIDCALL;
6202 /* check that both textures have the identical numbers of levels */
6203 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6204 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6205 hr = WINED3DERR_INVALIDCALL;
6208 if (WINED3D_OK == hr) {
6210 /* Make sure that the destination texture is loaded */
6211 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6213 /* Update every surface level of the texture */
6214 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6216 switch (sourceType) {
6217 case WINED3DRTYPE_TEXTURE:
6219 IWineD3DSurface *srcSurface;
6220 IWineD3DSurface *destSurface;
6222 for (i = 0 ; i < levels ; ++i) {
6223 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6224 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6225 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6226 IWineD3DSurface_Release(srcSurface);
6227 IWineD3DSurface_Release(destSurface);
6228 if (WINED3D_OK != hr) {
6229 WARN("(%p) : Call to update surface failed\n", This);
6235 case WINED3DRTYPE_CUBETEXTURE:
6237 IWineD3DSurface *srcSurface;
6238 IWineD3DSurface *destSurface;
6239 WINED3DCUBEMAP_FACES faceType;
6241 for (i = 0 ; i < levels ; ++i) {
6242 /* Update each cube face */
6243 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6244 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6245 if (WINED3D_OK != hr) {
6246 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6248 TRACE("Got srcSurface %p\n", srcSurface);
6250 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6251 if (WINED3D_OK != hr) {
6252 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6254 TRACE("Got desrSurface %p\n", destSurface);
6256 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6257 IWineD3DSurface_Release(srcSurface);
6258 IWineD3DSurface_Release(destSurface);
6259 if (WINED3D_OK != hr) {
6260 WARN("(%p) : Call to update surface failed\n", This);
6267 #if 0 /* TODO: Add support for volume textures */
6268 case WINED3DRTYPE_VOLUMETEXTURE:
6270 IWineD3DVolume srcVolume = NULL;
6271 IWineD3DSurface destVolume = NULL;
6273 for (i = 0 ; i < levels ; ++i) {
6274 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6275 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6276 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6277 IWineD3DVolume_Release(srcSurface);
6278 IWineD3DVolume_Release(destSurface);
6279 if (WINED3D_OK != hr) {
6280 WARN("(%p) : Call to update volume failed\n", This);
6288 FIXME("(%p) : Unsupported source and destination type\n", This);
6289 hr = WINED3DERR_INVALIDCALL;
6296 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6297 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6298 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6301 TRACE("(%p) : stub\n", This);
6304 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6306 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6307 * NOTE It may be best to move the code into surface to occomplish this
6308 ****************************************/
6310 WINED3DSURFACE_DESC surfaceDesc;
6311 unsigned int surfaceWidth, surfaceHeight;
6312 glDescriptor *targetGlDescription = NULL;
6313 glDescriptor *surfaceGlDescription = NULL;
6314 IWineD3DSwapChainImpl *container = NULL;
6316 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6317 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6318 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6320 surfaceDesc.Width = &surfaceWidth;
6321 surfaceDesc.Height = &surfaceHeight;
6322 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6323 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6325 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6326 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6328 /* TODO: opengl Context switching for swapchains etc... */
6329 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6330 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6331 glReadBuffer(GL_BACK);
6332 vcheckGLcall("glReadBuffer(GL_BACK)");
6333 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6334 glReadBuffer(GL_FRONT);
6335 vcheckGLcall("glReadBuffer(GL_FRONT)");
6336 } else if (pRenderTarget == This->depthStencilBuffer) {
6337 FIXME("Reading of depthstencil not yet supported\n");
6340 glReadPixels(surfaceGlDescription->target,
6341 surfaceGlDescription->level,
6344 surfaceGlDescription->glFormat,
6345 surfaceGlDescription->glType,
6346 (void *)IWineD3DSurface_GetData(pSurface));
6347 vcheckGLcall("glReadPixels(...)");
6348 if(NULL != container ){
6349 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6352 IWineD3DBaseTexture *container;
6353 GLenum textureDimensions = GL_TEXTURE_2D;
6355 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6356 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6357 IWineD3DBaseTexture_Release(container);
6359 /* TODO: 2D -> Cube surface coppies etc.. */
6360 if (surfaceGlDescription->target != textureDimensions) {
6361 FIXME("(%p) : Texture dimension mismatch\n", This);
6363 glEnable(textureDimensions);
6364 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6365 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6366 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6367 vcheckGLcall("glBindTexture");
6368 glGetTexImage(surfaceGlDescription->target,
6369 surfaceGlDescription->level,
6370 surfaceGlDescription->glFormat,
6371 surfaceGlDescription->glType,
6372 (void *)IWineD3DSurface_GetData(pSurface));
6373 glDisable(textureDimensions);
6374 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6381 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6382 IWineD3DSwapChain *swapChain;
6384 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6385 if(hr == WINED3D_OK) {
6386 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6387 IWineD3DSwapChain_Release(swapChain);
6392 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6394 /* return a sensible default */
6396 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6397 FIXME("(%p) : stub\n", This);
6401 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6404 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6405 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6406 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6407 return WINED3DERR_INVALIDCALL;
6409 for (j = 0; j < 256; ++j) {
6410 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6411 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6412 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6413 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6415 TRACE("(%p) : returning\n", This);
6419 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6422 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6423 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6424 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6425 return WINED3DERR_INVALIDCALL;
6427 for (j = 0; j < 256; ++j) {
6428 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6429 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6430 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6431 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6433 TRACE("(%p) : returning\n", This);
6437 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6439 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6440 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6441 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6442 return WINED3DERR_INVALIDCALL;
6444 /*TODO: stateblocks */
6445 This->currentPalette = PaletteNumber;
6446 TRACE("(%p) : returning\n", This);
6450 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6452 if (PaletteNumber == NULL) {
6453 WARN("(%p) : returning Invalid Call\n", This);
6454 return WINED3DERR_INVALIDCALL;
6456 /*TODO: stateblocks */
6457 *PaletteNumber = This->currentPalette;
6458 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6462 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6464 static BOOL showFixmes = TRUE;
6466 FIXME("(%p) : stub\n", This);
6470 This->softwareVertexProcessing = bSoftware;
6475 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6477 static BOOL showFixmes = TRUE;
6479 FIXME("(%p) : stub\n", This);
6482 return This->softwareVertexProcessing;
6486 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6488 IWineD3DSwapChain *swapChain;
6491 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6493 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6494 if(hr == WINED3D_OK){
6495 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6496 IWineD3DSwapChain_Release(swapChain);
6498 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6504 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6506 static BOOL showfixmes = TRUE;
6507 if(nSegments != 0.0f) {
6509 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6516 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6518 static BOOL showfixmes = TRUE;
6520 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6526 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6528 /** TODO: remove casts to IWineD3DSurfaceImpl
6529 * NOTE: move code to surface to accomplish this
6530 ****************************************/
6531 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6532 int srcWidth, srcHeight;
6533 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6534 WINED3DFORMAT destFormat, srcFormat;
6536 int destLeft, destTop;
6537 WINED3DPOOL srcPool, destPool;
6539 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6540 glDescriptor *glDescription = NULL;
6541 GLenum textureDimensions = GL_TEXTURE_2D;
6542 IWineD3DBaseTexture *baseTexture;
6544 WINED3DSURFACE_DESC winedesc;
6546 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6547 memset(&winedesc, 0, sizeof(winedesc));
6548 winedesc.Width = &srcSurfaceWidth;
6549 winedesc.Height = &srcSurfaceHeight;
6550 winedesc.Pool = &srcPool;
6551 winedesc.Format = &srcFormat;
6553 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6555 winedesc.Width = &destSurfaceWidth;
6556 winedesc.Height = &destSurfaceHeight;
6557 winedesc.Pool = &destPool;
6558 winedesc.Format = &destFormat;
6559 winedesc.Size = &destSize;
6561 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6563 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6564 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6565 return WINED3DERR_INVALIDCALL;
6568 if (destFormat == WINED3DFMT_UNKNOWN) {
6569 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6570 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6572 /* Get the update surface description */
6573 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6576 /* Make sure the surface is loaded and up to date */
6577 IWineD3DSurface_PreLoad(pDestinationSurface);
6579 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6583 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6584 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6585 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6586 destLeft = pDestPoint ? pDestPoint->x : 0;
6587 destTop = pDestPoint ? pDestPoint->y : 0;
6590 /* This function doesn't support compressed textures
6591 the pitch is just bytesPerPixel * width */
6592 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6593 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6594 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6595 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6597 /* TODO DXT formats */
6599 if(pSourceRect != NULL && pSourceRect->top != 0){
6600 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6602 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6604 ,glDescription->level
6609 ,glDescription->glFormat
6610 ,glDescription->glType
6611 ,IWineD3DSurface_GetData(pSourceSurface)
6615 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6617 /* need to lock the surface to get the data */
6618 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6621 /* TODO: Cube and volume support */
6623 /* not a whole row so we have to do it a line at a time */
6626 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6627 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6629 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6631 glTexSubImage2D(glDescription->target
6632 ,glDescription->level
6637 ,glDescription->glFormat
6638 ,glDescription->glType
6639 ,data /* could be quicker using */
6644 } else { /* Full width, so just write out the whole texture */
6646 if (WINED3DFMT_DXT1 == destFormat ||
6647 WINED3DFMT_DXT2 == destFormat ||
6648 WINED3DFMT_DXT3 == destFormat ||
6649 WINED3DFMT_DXT4 == destFormat ||
6650 WINED3DFMT_DXT5 == destFormat) {
6651 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6652 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6653 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6654 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6655 } if (destFormat != srcFormat) {
6656 FIXME("Updating mixed format compressed texture is not curretly support\n");
6658 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6659 glDescription->level,
6660 glDescription->glFormatInternal,
6665 IWineD3DSurface_GetData(pSourceSurface));
6668 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6673 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6675 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6676 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6677 data returned by GetData non-power2 width/height with hardware non-power2
6678 pow2Width/height are set to surface width height, repacking isn't needed so it
6679 doesn't matter which function gets called. */
6680 glTexSubImage2D(glDescription->target
6681 ,glDescription->level
6686 ,glDescription->glFormat
6687 ,glDescription->glType
6688 ,IWineD3DSurface_GetData(pSourceSurface)
6692 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6693 glTexSubImage2D(glDescription->target
6694 ,glDescription->level
6697 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6698 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6699 ,glDescription->glFormat
6700 ,glDescription->glType
6701 ,IWineD3DSurface_GetData(pSourceSurface)
6707 checkGLcall("glTexSubImage2D");
6709 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6710 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6711 * surface bigger than it needs to be hmm.. */
6712 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6713 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6714 IWineD3DBaseTexture_Release(baseTexture);
6717 glDisable(textureDimensions); /* This needs to be managed better.... */
6723 /* Used by DirectX 8 */
6724 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6725 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6726 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6729 HRESULT hr = WINED3D_OK;
6730 WINED3DFORMAT srcFormat, destFormat;
6731 UINT srcWidth, destWidth;
6732 UINT srcHeight, destHeight;
6734 WINED3DSURFACE_DESC winedesc;
6736 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6737 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6740 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6741 memset(&winedesc, 0, sizeof(winedesc));
6743 winedesc.Format = &srcFormat;
6744 winedesc.Width = &srcWidth;
6745 winedesc.Height = &srcHeight;
6746 winedesc.Size = &srcSize;
6747 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6749 winedesc.Format = &destFormat;
6750 winedesc.Width = &destWidth;
6751 winedesc.Height = &destHeight;
6752 winedesc.Size = NULL;
6753 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6755 /* Check that the source and destination formats match */
6756 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6757 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6758 return WINED3DERR_INVALIDCALL;
6759 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6760 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6761 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6762 destFormat = srcFormat;
6765 /* Quick if complete copy ... */
6766 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6768 if (srcWidth == destWidth && srcHeight == destHeight) {
6769 WINED3DLOCKED_RECT lrSrc;
6770 WINED3DLOCKED_RECT lrDst;
6771 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6772 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6773 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6775 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6777 IWineD3DSurface_UnlockRect(pSourceSurface);
6778 IWineD3DSurface_UnlockRect(pDestinationSurface);
6779 TRACE("Unlocked src and dst\n");
6783 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6784 hr = WINED3DERR_INVALIDCALL;
6789 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6791 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6794 /* Copy rect by rect */
6795 for (i = 0; i < cRects; ++i) {
6796 CONST RECT* r = &pSourceRectsArray[i];
6797 CONST POINT* p = &pDestPointsArray[i];
6800 WINED3DLOCKED_RECT lrSrc;
6801 WINED3DLOCKED_RECT lrDst;
6804 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6805 if (srcFormat == WINED3DFMT_DXT1) {
6806 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6808 copyperline = ((r->right - r->left) * bytesPerPixel);
6811 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6812 dest_rect.left = p->x;
6813 dest_rect.top = p->y;
6814 dest_rect.right = p->x + (r->right - r->left);
6815 dest_rect.bottom= p->y + (r->bottom - r->top);
6816 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6817 TRACE("Locked src and dst\n");
6819 /* Find where to start */
6820 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6821 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6823 IWineD3DSurface_UnlockRect(pSourceSurface);
6824 IWineD3DSurface_UnlockRect(pDestinationSurface);
6825 TRACE("Unlocked src and dst\n");
6828 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6829 hr = WINED3DERR_INVALIDCALL;
6836 /* Implementation details at http://developer.nvidia.com/attach/6494
6838 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6839 hmm.. no longer supported use
6840 OpenGL evaluators or tessellate surfaces within your application.
6843 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6844 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6846 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6847 FIXME("(%p) : Stub\n", This);
6852 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6853 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6855 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6856 FIXME("(%p) : Stub\n", This);
6860 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6862 TRACE("(%p) Handle(%d)\n", This, Handle);
6863 FIXME("(%p) : Stub\n", This);
6867 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6868 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6869 fill a surface with a block of color! */
6870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6871 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6872 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6873 IWineD3DSwapChainImpl *container = NULL;
6874 BOOL isRenderTarget = FALSE;
6875 unsigned int width, height;
6876 unsigned int top, left;
6879 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6881 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6882 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6883 return WINED3DERR_INVALIDCALL;
6886 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6887 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6888 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6889 /* TODO: make sure we set everything back to the way it was, and context management!
6890 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6891 vcheckGLcall("glIntegerv");
6892 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6893 vcheckGLcall("glIntegerv");
6895 TRACE("Color fill to render targets may cause some graphics issues\n");
6896 if (pSurface == container->frontBuffer) {
6897 glDrawBuffer(GL_FRONT);
6899 glDrawBuffer(GL_BACK);
6902 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6903 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6905 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6907 if (container != NULL) {
6908 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6910 /* we can use GL_STENCIL_INDEX etc...*/
6913 if (container != NULL) {
6914 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6916 isRenderTarget = TRUE;
6918 /* TODO: drawing to GL_FRONT and GL_BACK */
6919 /* TODO: see if things can be speeded up by using the correct
6920 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6921 if (pRect == NULL) {
6924 width = surface->currentDesc.Width;
6925 height = surface->currentDesc.Height;
6929 width = pRect->x2 - left;
6930 height = pRect->y2 - top;
6933 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6934 /* Create a 'line' of color color, in the correct format for the surface */
6935 for (u = 0 ; u < width ; u ++) {
6940 if (isRenderTarget == FALSE) {
6941 glDescriptor *glDesc;
6942 IWineD3DSurface_PreLoad(pSurface);
6944 /* draw a block of the coloured line on the sufrace */
6945 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6946 for (v = 0 ; v< height;v++) {
6947 glTexSubImage2D(glDesc->target
6948 ,glDesc->level /* level */
6958 checkGLcall("glTexSubImage2D");
6960 glDisable(glDesc->target);
6962 /** FIXME: Using GLClear may be faster **/
6963 glRasterPos2i(left, top);
6964 glPixelZoom((float)width ,(float)height);
6965 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6966 checkGLcall("glDrawPixels");
6968 HeapFree(GetProcessHeap(), 0, data);
6974 /* rendertarget and deptth stencil functions */
6975 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6978 /* FIXME: Implelent RenderTargetIndex >0 */
6979 if(RenderTargetIndex > 0)
6980 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6982 *ppRenderTarget = This->renderTarget;
6983 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6984 /* Note inc ref on returned surface */
6985 if(*ppRenderTarget != NULL)
6986 IWineD3DSurface_AddRef(*ppRenderTarget);
6990 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6992 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6993 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6994 IWineD3DSwapChainImpl *Swapchain;
6997 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6999 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7000 if(hr != WINED3D_OK) {
7001 ERR("Can't get the swapchain\n");
7005 /* Make sure to release the swapchain */
7006 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7008 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7009 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7010 return WINED3DERR_INVALIDCALL;
7012 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7013 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7014 return WINED3DERR_INVALIDCALL;
7017 if(Swapchain->frontBuffer != Front) {
7018 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7020 if(Swapchain->frontBuffer)
7021 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7022 Swapchain->frontBuffer = Front;
7024 if(Swapchain->frontBuffer) {
7025 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7029 if(Back && !Swapchain->backBuffer) {
7030 /* We need memory for the back buffer array - only one back buffer this way */
7031 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7032 if(!Swapchain->backBuffer) {
7033 ERR("Out of memory\n");
7034 return E_OUTOFMEMORY;
7038 if(Swapchain->backBuffer[0] != Back) {
7039 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7041 if(!Swapchain->backBuffer[0]) {
7042 /* GL was told to draw to the front buffer at creation,
7045 glDrawBuffer(GL_BACK);
7046 checkGLcall("glDrawBuffer(GL_BACK)");
7047 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7048 Swapchain->presentParms.BackBufferCount = 1;
7050 /* That makes problems - disable for now */
7051 /* glDrawBuffer(GL_FRONT); */
7052 checkGLcall("glDrawBuffer(GL_FRONT)");
7053 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7054 Swapchain->presentParms.BackBufferCount = 0;
7058 if(Swapchain->backBuffer[0])
7059 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7060 Swapchain->backBuffer[0] = Back;
7062 if(Swapchain->backBuffer[0]) {
7063 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7065 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7073 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7075 *ppZStencilSurface = This->depthStencilBuffer;
7076 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7078 if(*ppZStencilSurface != NULL) {
7079 /* Note inc ref on returned surface */
7080 IWineD3DSurface_AddRef(*ppZStencilSurface);
7085 /* internal static helper functions */
7086 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7087 IWineD3DSurface *RenderSurface);
7089 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7091 HRESULT hr = WINED3D_OK;
7092 WINED3DVIEWPORT viewport;
7094 TRACE("(%p) Swapping rendertarget\n",This);
7095 if (RenderTargetIndex > 0) {
7096 FIXME("(%p) Render targets other than the first are not supported\n",This);
7097 RenderTargetIndex = 0;
7100 /* MSDN says that null disables the render target
7101 but a device must always be associated with a render target
7102 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7104 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7107 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7108 FIXME("Trying to set render target 0 to NULL\n");
7109 return WINED3DERR_INVALIDCALL;
7111 /* TODO: replace Impl* usage with interface usage */
7112 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7113 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);
7114 return WINED3DERR_INVALIDCALL;
7116 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7117 * builds, but I think wine counts as a 'debug' build for now.
7118 ******************************/
7119 /* If we are trying to set what we already have, don't bother */
7120 if (pRenderTarget == This->renderTarget) {
7121 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7123 /* Otherwise, set the render target up */
7125 if (FALSE == This->sceneEnded) {
7126 IWineD3DDevice_EndScene(iface);
7128 TRACE("clearing renderer\n");
7129 /* IWineD3DDeviceImpl_CleanRender(iface); */
7130 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7131 depending on the renter target implementation being used.
7132 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7133 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7134 stencil buffer and incure an extra memory overhead */
7135 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7138 if (SUCCEEDED(hr)) {
7139 /* Finally, reset the viewport as the MSDN states. */
7140 /* TODO: Replace impl usage */
7141 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7142 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7145 viewport.MaxZ = 1.0f;
7146 viewport.MinZ = 0.0f;
7147 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7149 FIXME("Unknown error setting the render target\n");
7151 This->sceneEnded = FALSE;
7155 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7157 HRESULT hr = WINED3D_OK;
7158 IWineD3DSurface *tmp;
7160 TRACE("(%p) Swapping z-buffer\n",This);
7162 if (pNewZStencil == This->stencilBufferTarget) {
7163 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7165 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7166 * depending on the renter target implementation being used.
7167 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7168 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7169 * stencil buffer and incure an extra memory overhead
7170 ******************************************************/
7173 tmp = This->stencilBufferTarget;
7174 This->stencilBufferTarget = pNewZStencil;
7175 /* should we be calling the parent or the wined3d surface? */
7176 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7177 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7179 /** TODO: glEnable/glDisable on depth/stencil depending on
7180 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7181 **********************************************************/
7188 #ifdef GL_VERSION_1_3
7189 /* Internal functions not in DirectX */
7190 /** TODO: move this off to the opengl context manager
7191 *(the swapchain doesn't need to know anything about offscreen rendering!)
7192 ****************************************************/
7194 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7198 TRACE("(%p), %p\n", This, swapchain);
7200 if (swapchain->win != swapchain->drawable) {
7201 /* Set everything back the way it ws */
7202 swapchain->render_ctx = swapchain->glCtx;
7203 swapchain->drawable = swapchain->win;
7208 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7209 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7213 unsigned int height;
7214 WINED3DFORMAT format;
7215 WINED3DSURFACE_DESC surfaceDesc;
7216 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7217 surfaceDesc.Width = &width;
7218 surfaceDesc.Height = &height;
7219 surfaceDesc.Format = &format;
7220 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7222 /* I need a get width/height function (and should do something with the format) */
7223 for (i = 0; i < CONTEXT_CACHE; ++i) {
7224 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7225 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7226 the pSurface can be set to 0 allowing it to be reused from cache **/
7227 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7228 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7229 *context = &This->contextCache[i];
7232 if (This->contextCache[i].Width == 0) {
7233 This->contextCache[i].pSurface = pSurface;
7234 This->contextCache[i].Width = width;
7235 This->contextCache[i].Height = height;
7236 *context = &This->contextCache[i];
7240 if (i == CONTEXT_CACHE) {
7241 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7242 glContext *dropContext = 0;
7243 for (i = 0; i < CONTEXT_CACHE; i++) {
7244 if (This->contextCache[i].usedcount < minUsage) {
7245 dropContext = &This->contextCache[i];
7246 minUsage = This->contextCache[i].usedcount;
7249 /* clean up the context (this doesn't work for ATI at the moment */
7251 glXDestroyContext(swapchain->display, dropContext->context);
7252 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7255 dropContext->Width = 0;
7256 dropContext->pSurface = pSurface;
7257 *context = dropContext;
7259 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7260 for (i = 0; i < CONTEXT_CACHE; i++) {
7261 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7265 if (*context != NULL)
7268 return E_OUTOFMEMORY;
7272 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7273 * the functionality needs splitting up so that we don't do more than we should do.
7274 * this only seems to impact performance a little.
7275 ******************************/
7276 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7277 IWineD3DSurface *RenderSurface) {
7278 HRESULT ret = WINED3DERR_INVALIDCALL;
7281 * Currently only active for GLX >= 1.3
7282 * for others versions we'll have to use GLXPixmaps
7284 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7285 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7286 * so only check OpenGL version
7287 * ..........................
7288 * I don't believe that it is a problem with NVidia headers,
7289 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7290 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7292 * Your application will report GLX version 1.2 on glXQueryVersion.
7293 * However, it is safe to call the GLX 1.3 functions as described below.
7295 #if defined(GL_VERSION_1_3)
7297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7298 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7299 IWineD3DSurface *tmp;
7300 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7301 GLXFBConfig* cfgs = NULL;
7305 IWineD3DSwapChain *currentSwapchain;
7306 IWineD3DSwapChainImpl *swapchain;
7307 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7308 * but switch them off if the StencilSurface is set to NULL
7309 ** *********************************************************/
7310 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7311 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7314 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7315 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7318 #define PUSH1(att) attribs[nAttribs++] = (att);
7319 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7321 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7323 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7324 IWineD3DSwapChainImpl *impSwapChain;
7325 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7326 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7327 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7332 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7333 PUSH2(GLX_X_RENDERABLE, TRUE);
7334 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7335 TRACE("calling makeglcfg\n");
7336 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7339 TRACE("calling chooseFGConfig\n");
7340 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7343 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7344 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7345 why we failed and only show this message once! */
7346 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"); /**/
7348 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7349 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7350 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7351 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7352 TRACE("calling makeglcfg\n");
7353 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7355 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7362 for (i = 0; i < nCfgs; ++i) {
7363 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7364 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7365 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7368 if (NULL != This->renderTarget) {
7370 vcheckGLcall("glFlush");
7371 /** This is only useful if the old render target was a swapchain,
7372 * we need to supercede this with a function that displays
7373 * the current buffer on the screen. This is easy to do in glx1.3 but
7374 * we need to do copy-write pixels in glx 1.2.
7375 ************************************************/
7376 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7378 printf("Hit Enter to get next frame ...\n");
7384 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain) != WINED3D_OK) {
7385 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7386 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
7390 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7391 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7392 **********************************************************************/
7393 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7394 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7395 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7396 TRACE("making swapchain active\n");
7397 if (RenderSurface != This->renderTarget) {
7398 BOOL backbuf = FALSE;
7401 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7402 if(RenderSurface == swapchain->backBuffer[i]) {
7410 /* This could be flagged so that some operations work directly with the front buffer */
7411 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7413 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7415 TRACE("Error in setting current context: context %p drawable %ld !\n",
7416 impSwapChain->glCtx, impSwapChain->win);
7419 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7421 checkGLcall("glXMakeContextCurrent");
7423 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7425 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7427 /** ********************************************************************
7428 * This is a quickly hacked out implementation of offscreen textures.
7429 * It will work in most cases but there may be problems if the client
7430 * modifies the texture directly, or expects the contents of the rendertarget
7433 * There are some real speed vs compatibility issues here:
7434 * we should really use a new context for every texture, but that eats ram.
7435 * we should also be restoring the texture to the pbuffer but that eats CPU
7436 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7437 * but if this means reusing the display backbuffer then we need to make sure that
7438 * states are correctly preserved.
7439 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7440 * and gain a good performance increase at the cost of compatibility.
7441 * I would suggest that, when this is the case, a user configurable flag be made
7442 * available, allowing the user to choose the best emulated experience for them.
7443 *********************************************************************/
7445 XVisualInfo *visinfo;
7446 glContext *newContext;
7448 /* Here were using a shared context model */
7449 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7450 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7453 /* If the context doesn't exist then create a new one */
7454 /* TODO: This should really be part of findGlContext */
7455 if (NULL == newContext->context) {
7457 TRACE("making new buffer\n");
7459 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7460 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7463 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7465 /** ****************************************
7466 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7468 * In future releases, we may provide the calls glXCreateNewContext,
7469 * glXQueryDrawable and glXMakeContextCurrent.
7470 * so until then we have to use glXGetVisualFromFBConfig &co..
7471 ********************************************/
7474 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7476 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7478 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7482 if (NULL == newContext || NULL == newContext->context) {
7483 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7485 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7486 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7487 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7490 /* Clean up the old context */
7491 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7492 /* Set the current context of the swapchain to the new context */
7493 impSwapChain->drawable = newContext->drawable;
7494 impSwapChain->render_ctx = newContext->context;
7498 #if 1 /* Apply the stateblock to the new context
7499 FIXME: This is a bit of a hack, each context should know it's own state,
7500 the directX current directX state should then be applied to the context */
7503 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7504 oldUpdateStateBlock = This->updateStateBlock;
7505 oldRecording= This->isRecordingState;
7506 This->isRecordingState = FALSE;
7507 This->updateStateBlock = This->stateBlock;
7508 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7510 This->isRecordingState = oldRecording;
7511 This->updateStateBlock = oldUpdateStateBlock;
7516 /* clean up the current rendertargets swapchain (if it belonged to one) */
7517 if (currentSwapchain != NULL) {
7518 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7521 /* Were done with the opengl context management, setup the rendertargets */
7523 tmp = This->renderTarget;
7524 This->renderTarget = RenderSurface;
7525 IWineD3DSurface_AddRef(This->renderTarget);
7526 IWineD3DSurface_Release(tmp);
7532 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7533 /* Check that the container is not a swapchain member */
7535 IWineD3DSwapChain *tmpSwapChain;
7536 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7537 This->renderUpsideDown = TRUE;
7539 This->renderUpsideDown = FALSE;
7540 IWineD3DSwapChain_Release(tmpSwapChain);
7542 /* Force updating the cull mode */
7543 TRACE("setting render state\n");
7544 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7545 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7547 /* Force updating projection matrix */
7548 This->last_was_rhw = FALSE;
7549 This->proj_valid = FALSE;
7557 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7558 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7563 if ( NULL != impSwapChain) {
7564 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7572 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7573 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7575 /* TODO: the use of Impl is deprecated. */
7576 /* some basic validation checks */
7577 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7579 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7581 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7582 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7583 return WINED3DERR_INVALIDCALL;
7585 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7586 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7587 return WINED3DERR_INVALIDCALL;
7589 /* TODO: make the cursor 'real' */
7591 This->xHotSpot = XHotSpot;
7592 This->yHotSpot = YHotSpot;
7597 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7599 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7601 This->xScreenSpace = XScreenSpace;
7602 This->yScreenSpace = YScreenSpace;
7608 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7610 TRACE("(%p) : visible(%d)\n", This, bShow);
7612 This->bCursorVisible = bShow;
7617 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7619 TRACE("(%p) : state (%lu)\n", This, This->state);
7620 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7621 switch (This->state) {
7624 case WINED3DERR_DEVICELOST:
7626 ResourceList *resourceList = This->resources;
7627 while (NULL != resourceList) {
7628 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7629 return WINED3DERR_DEVICENOTRESET;
7630 resourceList = resourceList->next;
7632 return WINED3DERR_DEVICELOST;
7634 case WINED3DERR_DRIVERINTERNALERROR:
7635 return WINED3DERR_DRIVERINTERNALERROR;
7639 return WINED3DERR_DRIVERINTERNALERROR;
7643 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7645 /** FIXME: Resource tracking needs to be done,
7646 * The closes we can do to this is set the priorities of all managed textures low
7647 * and then reset them.
7648 ***********************************************************/
7649 FIXME("(%p) : stub\n", This);
7653 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7655 /** FIXME: Resource trascking needs to be done.
7656 * in effect this pulls all non only default
7657 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7658 * and should clear down the context and set it up according to pPresentationParameters
7659 ***********************************************************/
7660 FIXME("(%p) : stub\n", This);
7664 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7666 /** FIXME: always true at the moment **/
7667 if(bEnableDialogs == FALSE) {
7668 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7674 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7676 TRACE("(%p) : pParameters %p\n", This, pParameters);
7678 *pParameters = This->createParms;
7682 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7683 IWineD3DSwapChain *swapchain;
7684 HRESULT hrc = WINED3D_OK;
7686 TRACE("Relaying to swapchain\n");
7688 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7689 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7690 IWineD3DSwapChain_Release(swapchain);
7695 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7696 IWineD3DSwapChain *swapchain;
7697 HRESULT hrc = WINED3D_OK;
7699 TRACE("Relaying to swapchain\n");
7701 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7702 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7703 IWineD3DSwapChain_Release(swapchain);
7709 /** ********************************************************
7710 * Notification functions
7711 ** ********************************************************/
7712 /** This function must be called in the release of a resource when ref == 0,
7713 * the contents of resource must still be correct,
7714 * any handels to other resource held by the caller must be closed
7715 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7716 *****************************************************/
7717 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7719 ResourceList* resourceList;
7721 TRACE("(%p) : resource %p\n", This, resource);
7723 EnterCriticalSection(&resourceStoreCriticalSection);
7725 /* add a new texture to the frot of the linked list */
7726 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7727 resourceList->resource = resource;
7729 /* Get the old head */
7730 resourceList->next = This->resources;
7732 This->resources = resourceList;
7733 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7736 LeaveCriticalSection(&resourceStoreCriticalSection);
7741 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7743 ResourceList* resourceList = NULL;
7744 ResourceList* previousResourceList = NULL;
7746 TRACE("(%p) : resource %p\n", This, resource);
7749 EnterCriticalSection(&resourceStoreCriticalSection);
7751 resourceList = This->resources;
7753 while (resourceList != NULL) {
7754 if(resourceList->resource == resource) break;
7755 previousResourceList = resourceList;
7756 resourceList = resourceList->next;
7759 if (resourceList == NULL) {
7760 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7762 LeaveCriticalSection(&resourceStoreCriticalSection);
7766 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7768 /* make sure we don't leave a hole in the list */
7769 if (previousResourceList != NULL) {
7770 previousResourceList->next = resourceList->next;
7772 This->resources = resourceList->next;
7776 LeaveCriticalSection(&resourceStoreCriticalSection);
7782 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7786 TRACE("(%p) : resource %p\n", This, resource);
7787 switch(IWineD3DResource_GetType(resource)){
7788 case WINED3DRTYPE_SURFACE:
7789 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7791 case WINED3DRTYPE_TEXTURE:
7792 case WINED3DRTYPE_CUBETEXTURE:
7793 case WINED3DRTYPE_VOLUMETEXTURE:
7794 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7795 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7796 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7797 This->stateBlock->textures[counter] = NULL;
7799 if (This->updateStateBlock != This->stateBlock ){
7800 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7801 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7802 This->updateStateBlock->textures[counter] = NULL;
7807 case WINED3DRTYPE_VOLUME:
7808 /* TODO: nothing really? */
7810 case WINED3DRTYPE_VERTEXBUFFER:
7811 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7814 TRACE("Cleaning up stream pointers\n");
7816 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7817 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7818 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7820 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7821 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7822 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7823 This->updateStateBlock->streamSource[streamNumber] = 0;
7824 /* Set changed flag? */
7827 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) */
7828 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7829 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7830 This->stateBlock->streamSource[streamNumber] = 0;
7833 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7834 else { /* This shouldn't happen */
7835 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7842 case WINED3DRTYPE_INDEXBUFFER:
7843 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7844 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7845 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7846 This->updateStateBlock->pIndexData = NULL;
7849 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7850 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7851 This->stateBlock->pIndexData = NULL;
7857 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7862 /* Remove the resoruce from the resourceStore */
7863 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7865 TRACE("Resource released\n");
7869 /**********************************************************
7870 * IWineD3DDevice VTbl follows
7871 **********************************************************/
7873 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7875 /*** IUnknown methods ***/
7876 IWineD3DDeviceImpl_QueryInterface,
7877 IWineD3DDeviceImpl_AddRef,
7878 IWineD3DDeviceImpl_Release,
7879 /*** IWineD3DDevice methods ***/
7880 IWineD3DDeviceImpl_GetParent,
7881 /*** Creation methods**/
7882 IWineD3DDeviceImpl_CreateVertexBuffer,
7883 IWineD3DDeviceImpl_CreateIndexBuffer,
7884 IWineD3DDeviceImpl_CreateStateBlock,
7885 IWineD3DDeviceImpl_CreateSurface,
7886 IWineD3DDeviceImpl_CreateTexture,
7887 IWineD3DDeviceImpl_CreateVolumeTexture,
7888 IWineD3DDeviceImpl_CreateVolume,
7889 IWineD3DDeviceImpl_CreateCubeTexture,
7890 IWineD3DDeviceImpl_CreateQuery,
7891 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7892 IWineD3DDeviceImpl_CreateVertexDeclaration,
7893 IWineD3DDeviceImpl_CreateVertexShader,
7894 IWineD3DDeviceImpl_CreatePixelShader,
7895 IWineD3DDeviceImpl_CreatePalette,
7896 /*** Odd functions **/
7897 IWineD3DDeviceImpl_Init3D,
7898 IWineD3DDeviceImpl_Uninit3D,
7899 IWineD3DDeviceImpl_EnumDisplayModes,
7900 IWineD3DDeviceImpl_EvictManagedResources,
7901 IWineD3DDeviceImpl_GetAvailableTextureMem,
7902 IWineD3DDeviceImpl_GetBackBuffer,
7903 IWineD3DDeviceImpl_GetCreationParameters,
7904 IWineD3DDeviceImpl_GetDeviceCaps,
7905 IWineD3DDeviceImpl_GetDirect3D,
7906 IWineD3DDeviceImpl_GetDisplayMode,
7907 IWineD3DDeviceImpl_SetDisplayMode,
7908 IWineD3DDeviceImpl_GetHWND,
7909 IWineD3DDeviceImpl_SetHWND,
7910 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7911 IWineD3DDeviceImpl_GetRasterStatus,
7912 IWineD3DDeviceImpl_GetSwapChain,
7913 IWineD3DDeviceImpl_Reset,
7914 IWineD3DDeviceImpl_SetDialogBoxMode,
7915 IWineD3DDeviceImpl_SetCursorProperties,
7916 IWineD3DDeviceImpl_SetCursorPosition,
7917 IWineD3DDeviceImpl_ShowCursor,
7918 IWineD3DDeviceImpl_TestCooperativeLevel,
7919 IWineD3DDeviceImpl_EnumZBufferFormats,
7920 IWineD3DDeviceImpl_EnumTextureFormats,
7921 /*** Getters and setters **/
7922 IWineD3DDeviceImpl_SetClipPlane,
7923 IWineD3DDeviceImpl_GetClipPlane,
7924 IWineD3DDeviceImpl_SetClipStatus,
7925 IWineD3DDeviceImpl_GetClipStatus,
7926 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7927 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7928 IWineD3DDeviceImpl_SetDepthStencilSurface,
7929 IWineD3DDeviceImpl_GetDepthStencilSurface,
7930 IWineD3DDeviceImpl_SetFVF,
7931 IWineD3DDeviceImpl_GetFVF,
7932 IWineD3DDeviceImpl_SetGammaRamp,
7933 IWineD3DDeviceImpl_GetGammaRamp,
7934 IWineD3DDeviceImpl_SetIndices,
7935 IWineD3DDeviceImpl_GetIndices,
7936 IWineD3DDeviceImpl_SetLight,
7937 IWineD3DDeviceImpl_GetLight,
7938 IWineD3DDeviceImpl_SetLightEnable,
7939 IWineD3DDeviceImpl_GetLightEnable,
7940 IWineD3DDeviceImpl_SetMaterial,
7941 IWineD3DDeviceImpl_GetMaterial,
7942 IWineD3DDeviceImpl_SetNPatchMode,
7943 IWineD3DDeviceImpl_GetNPatchMode,
7944 IWineD3DDeviceImpl_SetPaletteEntries,
7945 IWineD3DDeviceImpl_GetPaletteEntries,
7946 IWineD3DDeviceImpl_SetPixelShader,
7947 IWineD3DDeviceImpl_GetPixelShader,
7948 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7949 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7950 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7951 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7952 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7953 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7954 IWineD3DDeviceImpl_SetRenderState,
7955 IWineD3DDeviceImpl_GetRenderState,
7956 IWineD3DDeviceImpl_SetRenderTarget,
7957 IWineD3DDeviceImpl_GetRenderTarget,
7958 IWineD3DDeviceImpl_SetFrontBackBuffers,
7959 IWineD3DDeviceImpl_SetSamplerState,
7960 IWineD3DDeviceImpl_GetSamplerState,
7961 IWineD3DDeviceImpl_SetScissorRect,
7962 IWineD3DDeviceImpl_GetScissorRect,
7963 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7964 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7965 IWineD3DDeviceImpl_SetStreamSource,
7966 IWineD3DDeviceImpl_GetStreamSource,
7967 IWineD3DDeviceImpl_SetStreamSourceFreq,
7968 IWineD3DDeviceImpl_GetStreamSourceFreq,
7969 IWineD3DDeviceImpl_SetTexture,
7970 IWineD3DDeviceImpl_GetTexture,
7971 IWineD3DDeviceImpl_SetTextureStageState,
7972 IWineD3DDeviceImpl_GetTextureStageState,
7973 IWineD3DDeviceImpl_SetTransform,
7974 IWineD3DDeviceImpl_GetTransform,
7975 IWineD3DDeviceImpl_SetVertexDeclaration,
7976 IWineD3DDeviceImpl_GetVertexDeclaration,
7977 IWineD3DDeviceImpl_SetVertexShader,
7978 IWineD3DDeviceImpl_GetVertexShader,
7979 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7980 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7981 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7982 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7983 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7984 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7985 IWineD3DDeviceImpl_SetViewport,
7986 IWineD3DDeviceImpl_GetViewport,
7987 IWineD3DDeviceImpl_MultiplyTransform,
7988 IWineD3DDeviceImpl_ValidateDevice,
7989 IWineD3DDeviceImpl_ProcessVertices,
7990 /*** State block ***/
7991 IWineD3DDeviceImpl_BeginStateBlock,
7992 IWineD3DDeviceImpl_EndStateBlock,
7993 /*** Scene management ***/
7994 IWineD3DDeviceImpl_BeginScene,
7995 IWineD3DDeviceImpl_EndScene,
7996 IWineD3DDeviceImpl_Present,
7997 IWineD3DDeviceImpl_Clear,
7999 IWineD3DDeviceImpl_DrawPrimitive,
8000 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8001 IWineD3DDeviceImpl_DrawPrimitiveUP,
8002 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8003 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8004 IWineD3DDeviceImpl_DrawRectPatch,
8005 IWineD3DDeviceImpl_DrawTriPatch,
8006 IWineD3DDeviceImpl_DeletePatch,
8007 IWineD3DDeviceImpl_ColorFill,
8008 IWineD3DDeviceImpl_UpdateTexture,
8009 IWineD3DDeviceImpl_UpdateSurface,
8010 IWineD3DDeviceImpl_CopyRects,
8011 IWineD3DDeviceImpl_StretchRect,
8012 IWineD3DDeviceImpl_GetRenderTargetData,
8013 IWineD3DDeviceImpl_GetFrontBufferData,
8014 /*** Internal use IWineD3DDevice methods ***/
8015 IWineD3DDeviceImpl_SetupTextureStates,
8016 /*** object tracking ***/
8017 IWineD3DDeviceImpl_ResourceReleased
8021 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8022 WINED3DRS_ALPHABLENDENABLE ,
8023 WINED3DRS_ALPHAFUNC ,
8024 WINED3DRS_ALPHAREF ,
8025 WINED3DRS_ALPHATESTENABLE ,
8027 WINED3DRS_COLORWRITEENABLE ,
8028 WINED3DRS_DESTBLEND ,
8029 WINED3DRS_DITHERENABLE ,
8030 WINED3DRS_FILLMODE ,
8031 WINED3DRS_FOGDENSITY ,
8033 WINED3DRS_FOGSTART ,
8034 WINED3DRS_LASTPIXEL ,
8035 WINED3DRS_SHADEMODE ,
8036 WINED3DRS_SRCBLEND ,
8037 WINED3DRS_STENCILENABLE ,
8038 WINED3DRS_STENCILFAIL ,
8039 WINED3DRS_STENCILFUNC ,
8040 WINED3DRS_STENCILMASK ,
8041 WINED3DRS_STENCILPASS ,
8042 WINED3DRS_STENCILREF ,
8043 WINED3DRS_STENCILWRITEMASK ,
8044 WINED3DRS_STENCILZFAIL ,
8045 WINED3DRS_TEXTUREFACTOR ,
8056 WINED3DRS_ZWRITEENABLE
8059 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8060 WINED3DTSS_ADDRESSW ,
8061 WINED3DTSS_ALPHAARG0 ,
8062 WINED3DTSS_ALPHAARG1 ,
8063 WINED3DTSS_ALPHAARG2 ,
8064 WINED3DTSS_ALPHAOP ,
8065 WINED3DTSS_BUMPENVLOFFSET ,
8066 WINED3DTSS_BUMPENVLSCALE ,
8067 WINED3DTSS_BUMPENVMAT00 ,
8068 WINED3DTSS_BUMPENVMAT01 ,
8069 WINED3DTSS_BUMPENVMAT10 ,
8070 WINED3DTSS_BUMPENVMAT11 ,
8071 WINED3DTSS_COLORARG0 ,
8072 WINED3DTSS_COLORARG1 ,
8073 WINED3DTSS_COLORARG2 ,
8074 WINED3DTSS_COLOROP ,
8075 WINED3DTSS_RESULTARG ,
8076 WINED3DTSS_TEXCOORDINDEX ,
8077 WINED3DTSS_TEXTURETRANSFORMFLAGS
8080 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8081 WINED3DSAMP_ADDRESSU ,
8082 WINED3DSAMP_ADDRESSV ,
8083 WINED3DSAMP_ADDRESSW ,
8084 WINED3DSAMP_BORDERCOLOR ,
8085 WINED3DSAMP_MAGFILTER ,
8086 WINED3DSAMP_MINFILTER ,
8087 WINED3DSAMP_MIPFILTER ,
8088 WINED3DSAMP_MIPMAPLODBIAS ,
8089 WINED3DSAMP_MAXMIPLEVEL ,
8090 WINED3DSAMP_MAXANISOTROPY ,
8091 WINED3DSAMP_SRGBTEXTURE ,
8092 WINED3DSAMP_ELEMENTINDEX
8095 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8097 WINED3DRS_AMBIENTMATERIALSOURCE ,
8098 WINED3DRS_CLIPPING ,
8099 WINED3DRS_CLIPPLANEENABLE ,
8100 WINED3DRS_COLORVERTEX ,
8101 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8102 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8103 WINED3DRS_FOGDENSITY ,
8105 WINED3DRS_FOGSTART ,
8106 WINED3DRS_FOGTABLEMODE ,
8107 WINED3DRS_FOGVERTEXMODE ,
8108 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8109 WINED3DRS_LIGHTING ,
8110 WINED3DRS_LOCALVIEWER ,
8111 WINED3DRS_MULTISAMPLEANTIALIAS ,
8112 WINED3DRS_MULTISAMPLEMASK ,
8113 WINED3DRS_NORMALIZENORMALS ,
8114 WINED3DRS_PATCHEDGESTYLE ,
8115 WINED3DRS_POINTSCALE_A ,
8116 WINED3DRS_POINTSCALE_B ,
8117 WINED3DRS_POINTSCALE_C ,
8118 WINED3DRS_POINTSCALEENABLE ,
8119 WINED3DRS_POINTSIZE ,
8120 WINED3DRS_POINTSIZE_MAX ,
8121 WINED3DRS_POINTSIZE_MIN ,
8122 WINED3DRS_POINTSPRITEENABLE ,
8123 WINED3DRS_RANGEFOGENABLE ,
8124 WINED3DRS_SPECULARMATERIALSOURCE ,
8125 WINED3DRS_TWEENFACTOR ,
8126 WINED3DRS_VERTEXBLEND
8129 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8130 WINED3DTSS_TEXCOORDINDEX ,
8131 WINED3DTSS_TEXTURETRANSFORMFLAGS
8134 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8135 WINED3DSAMP_DMAPOFFSET