2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
225 case D3DLIGHT_DIRECTIONAL:
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 ptr = list_head( &This->glsl_shader_progs );
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
293 This->stateBlock->shaderPrgId = curLink->programId;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
303 This->stateBlock->shaderPrgId = programId;
305 /* Allocate a new link for the list of programs */
306 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
307 newLink->programId = programId;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
350 /** Detach the GLSL pixel or vertex shader object from the shader program */
351 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
355 if (shaderObj != 0 && programId != 0) {
356 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
357 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
358 checkGLcall("glDetachObjectARB");
362 /** Delete a GLSL shader program */
363 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
368 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
369 GL_EXTCALL(glDeleteObjectARB(obj));
370 checkGLcall("glDeleteObjectARB");
374 /** Delete the list of linked programs this shader is associated with.
375 * Also at this point, check to see if there are any objects left attached
376 * to each GLSL program. If not, delete the GLSL program object.
377 * This will be run when a device is released. */
378 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
380 struct list *ptr = NULL;
381 struct glsl_shader_prog_link *curLink = NULL;
382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
386 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
387 (one pixel shader and one vertex shader at most) */
389 ptr = list_head( &This->glsl_shader_progs );
391 /* First, get the current item,
392 * save the link to the next pointer,
393 * detach and delete shader objects,
394 * then de-allocate the list item's memory */
395 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
396 ptr = list_next( &This->glsl_shader_progs, ptr );
398 /* See if this object is still attached to the program - it may have been detached already */
399 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
400 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
401 for (i = 0; i < numAttached; i++) {
402 detach_glsl_shader(iface, objList[i], curLink->programId);
405 delete_glsl_shader_program(iface, curLink->programId);
407 /* Free the memory for this list item */
408 HeapFree(GetProcessHeap(), 0, curLink);
413 /* Apply the current values to the specified texture stage */
414 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
423 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
424 clamping, MIPLOD, etc. This will work for up to 16 samplers.
427 if (Sampler >= GL_LIMITS(sampler_stages)) {
428 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
431 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
432 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
434 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
435 checkGLcall("glActiveTextureARB");
437 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
438 } else if (Sampler > 0) {
439 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
443 /* TODO: change this to a lookup table
444 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
445 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
446 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
447 especially when there are a number of groups of states. */
449 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
451 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
452 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
453 /* these are the only two supported states that need to be applied */
454 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
455 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
456 #if 0 /* not supported at the moment */
457 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
458 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
459 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
460 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
461 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
462 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
463 APPLY_STATE(WINED3DTSS_RESULTARG);
464 APPLY_STATE(WINED3DTSS_CONSTANT);
466 /* a quick sanity check in case someone forgot to update this function */
467 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
468 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
472 /* apply any sampler states that always need applying */
473 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
474 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
475 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
476 GL_TEXTURE_LOD_BIAS_EXT,
478 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
481 /* Note the D3DRS value applies to all textures, but GL has one
482 * per texture, so apply it now ready to be used!
484 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
485 /* Set the default alpha blend color */
486 if (GL_SUPPORT(ARB_IMAGING)) {
487 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
488 checkGLcall("glBlendColor");
490 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
493 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
494 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
495 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
497 /* TODO: NV_POINT_SPRITE */
498 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
499 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
500 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
501 glDisable(GL_POINT_SMOOTH);
503 /* Centre the texture on the vertex */
504 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
505 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
507 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
508 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
509 checkGLcall("glTexEnvf(...)");
510 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
511 glEnable( GL_POINT_SPRITE_ARB );
512 checkGLcall("glEnable(...)");
514 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
515 glDisable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
520 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
523 /**********************************************************
524 * IUnknown parts follows
525 **********************************************************/
527 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
532 if (IsEqualGUID(riid, &IID_IUnknown)
533 || IsEqualGUID(riid, &IID_IWineD3DBase)
534 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
535 IUnknown_AddRef(iface);
540 return E_NOINTERFACE;
543 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
545 ULONG refCount = InterlockedIncrement(&This->ref);
547 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
551 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
553 ULONG refCount = InterlockedDecrement(&This->ref);
555 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
558 /* TODO: Clean up all the surfaces and textures! */
559 /* NOTE: You must release the parent if the object was created via a callback
560 ** ***************************/
562 /* Delete any GLSL shader programs that may exist */
563 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
564 wined3d_settings.ps_selected_mode == SHADER_GLSL)
565 delete_glsl_shader_list(iface);
567 /* Release the update stateblock */
568 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
569 if(This->updateStateBlock != This->stateBlock)
570 FIXME("(%p) Something's still holding the Update stateblock\n",This);
572 This->updateStateBlock = NULL;
573 { /* because were not doing proper internal refcounts releasing the primary state block
574 causes recursion with the extra checks in ResourceReleased, to avoid this we have
575 to set this->stateBlock = NULL; first */
576 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
577 This->stateBlock = NULL;
579 /* Release the stateblock */
580 if(IWineD3DStateBlock_Release(stateBlock) > 0){
581 FIXME("(%p) Something's still holding the Update stateblock\n",This);
585 if (This->resources != NULL ) {
586 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
587 dumpResources(This->resources);
591 IWineD3D_Release(This->wineD3D);
592 This->wineD3D = NULL;
593 HeapFree(GetProcessHeap(), 0, This);
594 TRACE("Freed device %p\n", This);
600 /**********************************************************
601 * IWineD3DDevice implementation follows
602 **********************************************************/
603 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
605 *pParent = This->parent;
606 IUnknown_AddRef(This->parent);
610 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
611 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
612 GLenum error, glUsage;
613 DWORD vboUsage = object->resource.usage;
614 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
617 /* Make sure that the gl error is cleared. Do not use checkGLcall
618 * here because checkGLcall just prints a fixme and continues. However,
619 * if an error during VBO creation occurs we can fall back to non-vbo operation
620 * with full functionality(but performance loss)
622 while(glGetError() != GL_NO_ERROR);
624 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
625 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
626 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
627 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
628 * to check if the rhw and color values are in the correct format.
631 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
632 error = glGetError();
633 if(object->vbo == 0 || error != GL_NO_ERROR) {
634 WARN("Failed to create a VBO with error %d\n", error);
638 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
639 error = glGetError();
640 if(error != GL_NO_ERROR) {
641 WARN("Failed to bind the VBO, error %d\n", error);
645 /* Transformed vertices are horribly inflexible. If the app specifies an
646 * vertex buffer with transformed vertices in default pool without DYNAMIC
647 * usage assume DYNAMIC usage and print a warning. The app will have to update
648 * the vertices regularily for them to be useful
650 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
651 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
652 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
653 vboUsage |= WINED3DUSAGE_DYNAMIC;
656 /* Don't use static, because dx apps tend to update the buffer
657 * quite often even if they specify 0 usage
659 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
660 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
661 TRACE("Gl usage = GL_STREAM_DRAW\n");
662 glUsage = GL_STREAM_DRAW_ARB;
664 case D3DUSAGE_WRITEONLY:
665 TRACE("Gl usage = GL_STATIC_DRAW\n");
666 glUsage = GL_DYNAMIC_DRAW_ARB;
668 case D3DUSAGE_DYNAMIC:
669 TRACE("Gl usage = GL_STREAM_COPY\n");
670 glUsage = GL_STREAM_COPY_ARB;
673 TRACE("Gl usage = GL_STATIC_COPY\n");
674 glUsage = GL_DYNAMIC_COPY_ARB;
678 /* Reserve memory for the buffer. The amount of data won't change
679 * so we are safe with calling glBufferData once with a NULL ptr and
680 * calling glBufferSubData on updates
682 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
683 error = glGetError();
684 if(error != GL_NO_ERROR) {
685 WARN("glBufferDataARB failed with error %d\n", error);
693 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
694 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
695 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
701 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
702 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
705 IWineD3DVertexBufferImpl *object;
706 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
707 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
709 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
711 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
712 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
714 if(Size == 0) return WINED3DERR_INVALIDCALL;
716 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
717 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
721 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
722 * drawStridedFast (half-life 2).
724 * Basically converting the vertices in the buffer is quite expensive, and observations
725 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
726 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
728 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
729 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
730 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
731 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
733 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
734 * more. In this call we can convert dx7 buffers too.
736 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
737 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
738 (dxVersion > 7 || !conv) ) {
741 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
742 if(dxVersion == 7 && object->vbo) {
743 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
744 object->resource.allocatedMemory = NULL;
751 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
752 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
753 HANDLE *sharedHandle, IUnknown *parent) {
754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
755 IWineD3DIndexBufferImpl *object;
756 TRACE("(%p) Creating index buffer\n", This);
758 /* Allocate the storage for the device */
759 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
762 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
763 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
766 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
767 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
768 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
773 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
776 IWineD3DStateBlockImpl *object;
780 D3DCREATEOBJECTINSTANCE(object, StateBlock)
781 object->blockType = Type;
783 /* Special case - Used during initialization to produce a placeholder stateblock
784 so other functions called can update a state block */
785 if (Type == WINED3DSBT_INIT) {
786 /* Don't bother increasing the reference count otherwise a device will never
787 be freed due to circular dependencies */
791 temp_result = allocate_shader_constants(object);
792 if (WINED3D_OK != temp_result)
795 /* Otherwise, might as well set the whole state block to the appropriate values */
796 if ( This->stateBlock != NULL) {
797 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
799 memset(object->streamFreq, 1, sizeof(object->streamFreq));
802 /* Reset the ref and type after kludging it */
803 object->wineD3DDevice = This;
805 object->blockType = Type;
807 TRACE("Updating changed flags appropriate for type %d\n", Type);
809 if (Type == WINED3DSBT_ALL) {
811 TRACE("ALL => Pretend everything has changed\n");
812 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
813 } else if (Type == WINED3DSBT_PIXELSTATE) {
815 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
816 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
818 object->changed.pixelShader = TRUE;
820 /* Pixel Shader Constants */
821 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
822 object->changed.pixelShaderConstantsF[i] = TRUE;
823 for (i = 0; i < MAX_CONST_B; ++i)
824 object->changed.pixelShaderConstantsB[i] = TRUE;
825 for (i = 0; i < MAX_CONST_I; ++i)
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 < GL_LIMITS(vshader_constantsF); ++i)
852 object->changed.vertexShaderConstantsF[i] = TRUE;
853 for (i = 0; i < MAX_CONST_B; ++i)
854 object->changed.vertexShaderConstantsB[i] = TRUE;
855 for (i = 0; i < MAX_CONST_I; ++i)
856 object->changed.vertexShaderConstantsI[i] = TRUE;
858 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
859 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
861 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
862 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
863 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
866 for (j = 0 ; j < 16; j++){
867 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
868 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
872 /* Duplicate light chain */
874 PLIGHTINFOEL *src = NULL;
875 PLIGHTINFOEL *dst = NULL;
876 PLIGHTINFOEL *newEl = NULL;
877 src = This->stateBlock->lights;
878 object->lights = NULL;
882 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
883 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
884 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
886 newEl->changed = TRUE;
887 newEl->enabledChanged = TRUE;
889 object->lights = newEl;
900 FIXME("Unrecognized state block type %d\n", Type);
903 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
908 /* ************************************
910 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
913 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
915 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.
917 ******************************** */
919 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) {
920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
921 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
922 unsigned int pow2Width, pow2Height;
923 unsigned int Size = 1;
924 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
925 TRACE("(%p) Create surface\n",This);
927 /** FIXME: Check ranges on the inputs are valid
930 * [in] Quality level. The valid range is between zero and one less than the level
931 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
932 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
933 * values of paired render targets, depth stencil surfaces, and the MultiSample type
935 *******************************/
940 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
942 * If this flag is set, the contents of the depth stencil buffer will be
943 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
944 * with a different depth surface.
946 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
947 ***************************/
949 if(MultisampleQuality < 0) {
950 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
951 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
954 if(MultisampleQuality > 0) {
955 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
956 MultisampleQuality=0;
959 /** FIXME: Check that the format is supported
961 *******************************/
963 /* Non-power2 support */
965 /* Find the nearest pow2 match */
966 pow2Width = pow2Height = 1;
967 while (pow2Width < Width) pow2Width <<= 1;
968 while (pow2Height < Height) pow2Height <<= 1;
970 if (pow2Width > Width || pow2Height > Height) {
971 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
972 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
973 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
974 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
975 This, Width, Height);
976 return WINED3DERR_NOTAVAILABLE;
980 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
981 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
983 *********************************/
984 if (WINED3DFMT_UNKNOWN == Format) {
986 } else if (Format == WINED3DFMT_DXT1) {
987 /* DXT1 is half byte per pixel */
988 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
990 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
991 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
992 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
994 Size = (pow2Width * tableEntry->bpp) * pow2Height;
997 /** Create and initialise the surface resource **/
998 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
999 /* "Standalone" surface */
1000 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1002 object->currentDesc.Width = Width;
1003 object->currentDesc.Height = Height;
1004 object->currentDesc.MultiSampleType = MultiSample;
1005 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1007 /* Setup some glformat defaults */
1008 object->glDescription.glFormat = tableEntry->glFormat;
1009 object->glDescription.glFormatInternal = tableEntry->glInternal;
1010 object->glDescription.glType = tableEntry->glType;
1012 object->glDescription.textureName = 0;
1013 object->glDescription.level = Level;
1014 object->glDescription.target = GL_TEXTURE_2D;
1017 object->pow2Width = pow2Width;
1018 object->pow2Height = pow2Height;
1021 object->Flags = 0; /* We start without flags set */
1022 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1023 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1024 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1025 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1028 if (WINED3DFMT_UNKNOWN != Format) {
1029 object->bytesPerPixel = tableEntry->bpp;
1030 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1032 object->bytesPerPixel = 0;
1033 object->pow2Size = 0;
1036 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1038 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1040 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1041 * this function is too deap to need to care about things like this.
1042 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1043 * ****************************************/
1045 case WINED3DPOOL_SCRATCH:
1046 if(Lockable == FALSE)
1047 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1048 which are mutually exclusive, setting lockable to true\n");
1051 case WINED3DPOOL_SYSTEMMEM:
1052 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1053 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1054 case WINED3DPOOL_MANAGED:
1055 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1056 Usage of DYNAMIC which are mutually exclusive, not doing \
1057 anything just telling you.\n");
1059 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1060 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1061 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1062 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1065 FIXME("(%p) Unknown pool %d\n", This, Pool);
1069 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1070 FIXME("Trying to create a render target that isn't in the default pool\n");
1073 /* mark the texture as dirty so that it get's loaded first time around*/
1074 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1075 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1076 This, Width, Height, Format, debug_d3dformat(Format),
1077 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1079 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1080 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1081 This->ddraw_primary = (IWineD3DSurface *) object;
1083 /* Look at the implementation and set the correct Vtable */
1085 case SURFACE_OPENGL:
1086 /* Nothing to do, it's set already */
1090 object->lpVtbl = &IWineGDISurface_Vtbl;
1094 /* To be sure to catch this */
1095 ERR("Unknown requested surface implementation %d!\n", Impl);
1096 IWineD3DSurface_Release((IWineD3DSurface *) object);
1097 return WINED3DERR_INVALIDCALL;
1100 /* Call the private setup routine */
1101 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1105 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1106 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1107 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1108 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1111 IWineD3DTextureImpl *object;
1116 unsigned int pow2Width = Width;
1117 unsigned int pow2Height = Height;
1120 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1122 /* TODO: It should only be possible to create textures for formats
1123 that are reported as supported */
1124 if (WINED3DFMT_UNKNOWN >= Format) {
1125 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1126 return WINED3DERR_INVALIDCALL;
1129 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1130 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1131 object->width = Width;
1132 object->height = Height;
1134 /** Non-power2 support **/
1135 /* Find the nearest pow2 match */
1136 pow2Width = pow2Height = 1;
1137 while (pow2Width < Width) pow2Width <<= 1;
1138 while (pow2Height < Height) pow2Height <<= 1;
1140 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1141 /* Precalculated scaling for 'faked' non power of two texture coords */
1142 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1143 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1144 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1146 /* Calculate levels for mip mapping */
1148 TRACE("calculating levels %d\n", object->baseTexture.levels);
1149 object->baseTexture.levels++;
1152 while (tmpW > 1 || tmpH > 1) {
1153 tmpW = max(1, tmpW >> 1);
1154 tmpH = max(1, tmpH >> 1);
1155 object->baseTexture.levels++;
1157 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1160 /* Generate all the surfaces */
1163 for (i = 0; i < object->baseTexture.levels; i++)
1165 /* use the callback to create the texture surface */
1166 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1167 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1168 FIXME("Failed to create surface %p\n", object);
1170 object->surfaces[i] = NULL;
1171 IWineD3DTexture_Release((IWineD3DTexture *)object);
1177 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1178 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1179 /* calculate the next mipmap level */
1180 tmpW = max(1, tmpW >> 1);
1181 tmpH = max(1, tmpH >> 1);
1184 TRACE("(%p) : Created texture %p\n", This, object);
1188 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1189 UINT Width, UINT Height, UINT Depth,
1190 UINT Levels, DWORD Usage,
1191 WINED3DFORMAT Format, WINED3DPOOL Pool,
1192 IWineD3DVolumeTexture **ppVolumeTexture,
1193 HANDLE *pSharedHandle, IUnknown *parent,
1194 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1197 IWineD3DVolumeTextureImpl *object;
1203 /* TODO: It should only be possible to create textures for formats
1204 that are reported as supported */
1205 if (WINED3DFMT_UNKNOWN >= Format) {
1206 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1207 return WINED3DERR_INVALIDCALL;
1210 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1211 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1213 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1214 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1216 object->width = Width;
1217 object->height = Height;
1218 object->depth = Depth;
1220 /* Calculate levels for mip mapping */
1222 object->baseTexture.levels++;
1226 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1227 tmpW = max(1, tmpW >> 1);
1228 tmpH = max(1, tmpH >> 1);
1229 tmpD = max(1, tmpD >> 1);
1230 object->baseTexture.levels++;
1232 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1235 /* Generate all the surfaces */
1240 for (i = 0; i < object->baseTexture.levels; i++)
1242 /* Create the volume */
1243 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1244 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1246 /* Set it's container to this object */
1247 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1249 /* calcualte the next mipmap level */
1250 tmpW = max(1, tmpW >> 1);
1251 tmpH = max(1, tmpH >> 1);
1252 tmpD = max(1, tmpD >> 1);
1255 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1256 TRACE("(%p) : Created volume texture %p\n", This, object);
1260 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1261 UINT Width, UINT Height, UINT Depth,
1263 WINED3DFORMAT Format, WINED3DPOOL Pool,
1264 IWineD3DVolume** ppVolume,
1265 HANDLE* pSharedHandle, IUnknown *parent) {
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1268 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1269 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1271 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1273 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1274 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1276 object->currentDesc.Width = Width;
1277 object->currentDesc.Height = Height;
1278 object->currentDesc.Depth = Depth;
1279 object->bytesPerPixel = formatDesc->bpp;
1281 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1282 object->lockable = TRUE;
1283 object->locked = FALSE;
1284 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1285 object->dirty = TRUE;
1287 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1290 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1291 UINT Levels, DWORD Usage,
1292 WINED3DFORMAT Format, WINED3DPOOL Pool,
1293 IWineD3DCubeTexture **ppCubeTexture,
1294 HANDLE *pSharedHandle, IUnknown *parent,
1295 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1302 unsigned int pow2EdgeLength = EdgeLength;
1304 /* TODO: It should only be possible to create textures for formats
1305 that are reported as supported */
1306 if (WINED3DFMT_UNKNOWN >= Format) {
1307 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1308 return WINED3DERR_INVALIDCALL;
1311 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1312 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1314 TRACE("(%p) Create Cube Texture\n", This);
1316 /** Non-power2 support **/
1318 /* Find the nearest pow2 match */
1320 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1322 object->edgeLength = EdgeLength;
1323 /* TODO: support for native non-power 2 */
1324 /* Precalculated scaling for 'faked' non power of two texture coords */
1325 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1327 /* Calculate levels for mip mapping */
1329 object->baseTexture.levels++;
1332 tmpW = max(1, tmpW >> 1);
1333 object->baseTexture.levels++;
1335 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1338 /* Generate all the surfaces */
1340 for (i = 0; i < object->baseTexture.levels; i++) {
1342 /* Create the 6 faces */
1343 for (j = 0; j < 6; j++) {
1345 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1346 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1348 if(hr!= WINED3D_OK) {
1352 for (l = 0; l < j; l++) {
1353 IWineD3DSurface_Release(object->surfaces[j][i]);
1355 for (k = 0; k < i; k++) {
1356 for (l = 0; l < 6; l++) {
1357 IWineD3DSurface_Release(object->surfaces[l][j]);
1361 FIXME("(%p) Failed to create surface\n",object);
1362 HeapFree(GetProcessHeap(),0,object);
1363 *ppCubeTexture = NULL;
1366 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1367 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1369 tmpW = max(1, tmpW >> 1);
1372 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1373 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1377 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1381 if (NULL == ppQuery) {
1382 /* Just a check to see if we support this type of query */
1383 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1385 case WINED3DQUERYTYPE_OCCLUSION:
1386 TRACE("(%p) occlusion query\n", This);
1387 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1390 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1392 case WINED3DQUERYTYPE_VCACHE:
1393 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1394 case WINED3DQUERYTYPE_VERTEXSTATS:
1395 case WINED3DQUERYTYPE_EVENT:
1396 case WINED3DQUERYTYPE_TIMESTAMP:
1397 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1398 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1399 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1400 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1401 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1402 case WINED3DQUERYTYPE_PIXELTIMINGS:
1403 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1404 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1406 FIXME("(%p) Unhandled query type %d\n", This, Type);
1411 D3DCREATEOBJECTINSTANCE(object, Query)
1412 object->type = Type;
1413 /* allocated the 'extended' data based on the type of query requested */
1415 case D3DQUERYTYPE_OCCLUSION:
1416 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1417 TRACE("(%p) Allocating data for an occlusion query\n", This);
1418 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1421 case D3DQUERYTYPE_VCACHE:
1422 case D3DQUERYTYPE_RESOURCEMANAGER:
1423 case D3DQUERYTYPE_VERTEXSTATS:
1424 case D3DQUERYTYPE_EVENT:
1425 case D3DQUERYTYPE_TIMESTAMP:
1426 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1427 case D3DQUERYTYPE_TIMESTAMPFREQ:
1428 case D3DQUERYTYPE_PIPELINETIMINGS:
1429 case D3DQUERYTYPE_INTERFACETIMINGS:
1430 case D3DQUERYTYPE_VERTEXTIMINGS:
1431 case D3DQUERYTYPE_PIXELTIMINGS:
1432 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1433 case D3DQUERYTYPE_CACHEUTILIZATION:
1435 object->extendedData = 0;
1436 FIXME("(%p) Unhandled query type %d\n",This , Type);
1438 TRACE("(%p) : Created Query %p\n", This, object);
1442 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1443 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1445 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1446 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1450 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1452 XVisualInfo template;
1453 GLXContext oldContext;
1454 Drawable oldDrawable;
1455 HRESULT hr = WINED3D_OK;
1457 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1459 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1460 * does a device hold a reference to a swap chain giving them a lifetime of the device
1461 * or does the swap chain notify the device of its destruction.
1462 *******************************/
1464 /* Check the params */
1465 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1466 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1467 return WINED3DERR_INVALIDCALL;
1468 } else if (*pPresentationParameters->BackBufferCount > 1) {
1469 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");
1472 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1474 /*********************
1475 * Lookup the window Handle and the relating X window handle
1476 ********************/
1478 /* Setup hwnd we are using, plus which display this equates to */
1479 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1480 if (!object->win_handle) {
1481 object->win_handle = This->createParms.hFocusWindow;
1484 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1485 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1486 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1487 return WINED3DERR_NOTAVAILABLE;
1489 hDc = GetDC(object->win_handle);
1490 object->display = get_display(hDc);
1491 ReleaseDC(object->win_handle, hDc);
1492 TRACE("Using a display of %p %p\n", object->display, hDc);
1494 if (NULL == object->display || NULL == hDc) {
1495 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1496 return WINED3DERR_NOTAVAILABLE;
1499 if (object->win == 0) {
1500 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1501 return WINED3DERR_NOTAVAILABLE;
1504 * Create an opengl context for the display visual
1505 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1506 * use different properties after that point in time. FIXME: How to handle when requested format
1507 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1508 * it chooses is identical to the one already being used!
1509 **********************************/
1511 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1514 /* Create a new context for this swapchain */
1515 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1516 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1517 (or the best possible if none is requested) */
1518 TRACE("Found x visual ID : %ld\n", template.visualid);
1520 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1521 if (NULL == object->visInfo) {
1522 ERR("cannot really get XVisual\n");
1524 return WINED3DERR_NOTAVAILABLE;
1527 /* Write out some debug info about the visual/s */
1528 TRACE("Using x visual ID : %ld\n", template.visualid);
1529 TRACE(" visual info: %p\n", object->visInfo);
1530 TRACE(" num items : %d\n", num);
1531 for (n = 0;n < num; n++) {
1532 TRACE("=====item=====: %d\n", n + 1);
1533 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1534 TRACE(" screen : %d\n", object->visInfo[n].screen);
1535 TRACE(" depth : %u\n", object->visInfo[n].depth);
1536 TRACE(" class : %d\n", object->visInfo[n].class);
1537 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1538 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1539 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1540 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1541 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1542 /* log some extra glx info */
1543 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1544 TRACE(" gl_aux_buffers : %d\n", value);
1545 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1546 TRACE(" gl_buffer_size : %d\n", value);
1547 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1548 TRACE(" gl_red_size : %d\n", value);
1549 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1550 TRACE(" gl_green_size : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1552 TRACE(" gl_blue_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1554 TRACE(" gl_alpha_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1556 TRACE(" gl_depth_size : %d\n", value);
1557 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1558 TRACE(" gl_stencil_size : %d\n", value);
1560 /* Now choose a simila visual ID*/
1562 #ifdef USE_CONTEXT_MANAGER
1564 /** TODO: use a context mamager **/
1568 IWineD3DSwapChain *implSwapChain;
1569 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1570 /* The first time around we create the context that is shared with all other swapchains and render targets */
1571 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1572 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1575 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1576 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1577 /* and create a new context with the implicit swapchains context as the shared context */
1578 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1579 IWineD3DSwapChain_Release(implSwapChain);
1584 XFree(object->visInfo);
1585 object->visInfo = NULL;
1589 if (!object->glCtx) {
1590 ERR("Failed to create GLX context\n");
1591 return WINED3DERR_NOTAVAILABLE;
1593 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1594 object->win_handle, object->glCtx, object->win, object->visInfo);
1597 /*********************
1598 * Windowed / Fullscreen
1599 *******************/
1602 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1603 * so we should really check to see if there is a fullscreen swapchain already
1604 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1605 **************************************/
1607 if (!*(pPresentationParameters->Windowed)) {
1613 /* Get info on the current display setup */
1614 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1615 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1618 /* Change the display settings */
1619 memset(&devmode, 0, sizeof(DEVMODEW));
1620 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1621 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1622 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1623 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1624 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1625 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1627 /* Make popup window */
1628 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1629 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1630 *(pPresentationParameters->BackBufferWidth),
1631 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1633 /* For GetDisplayMode */
1634 This->ddraw_width = devmode.dmPelsWidth;
1635 This->ddraw_height = devmode.dmPelsHeight;
1636 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1640 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1641 * then the corresponding dimension of the client area of the hDeviceWindow
1642 * (or the focus window, if hDeviceWindow is NULL) is taken.
1643 **********************/
1645 if (*(pPresentationParameters->Windowed) &&
1646 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1647 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1650 GetClientRect(object->win_handle, &Rect);
1652 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1653 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1654 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1656 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1657 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1658 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1662 /*********************
1663 * finish off parameter initialization
1664 *******************/
1666 /* Put the correct figures in the presentation parameters */
1667 TRACE("Coppying accross presentaion paraneters\n");
1668 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1669 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1670 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1671 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1672 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1673 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1674 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1675 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1676 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1677 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1678 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1679 object->presentParms.Flags = *(pPresentationParameters->Flags);
1680 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1681 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1684 /*********************
1685 * Create the back, front and stencil buffers
1686 *******************/
1688 TRACE("calling rendertarget CB\n");
1689 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1690 object->presentParms.BackBufferWidth,
1691 object->presentParms.BackBufferHeight,
1692 object->presentParms.BackBufferFormat,
1693 object->presentParms.MultiSampleType,
1694 object->presentParms.MultiSampleQuality,
1695 TRUE /* Lockable */,
1696 &object->frontBuffer,
1697 NULL /* pShared (always null)*/);
1698 if (object->frontBuffer != NULL)
1699 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1701 if(object->presentParms.BackBufferCount > 0) {
1704 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1705 if(!object->backBuffer) {
1706 ERR("Out of memory\n");
1708 if (object->frontBuffer) {
1709 IUnknown *bufferParent;
1710 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1711 IUnknown_Release(bufferParent); /* once for the get parent */
1712 if (IUnknown_Release(bufferParent) > 0) {
1713 FIXME("(%p) Something's still holding the front buffer\n",This);
1716 HeapFree(GetProcessHeap(), 0, object);
1717 return E_OUTOFMEMORY;
1720 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1721 TRACE("calling rendertarget CB\n");
1722 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1723 object->presentParms.BackBufferWidth,
1724 object->presentParms.BackBufferHeight,
1725 object->presentParms.BackBufferFormat,
1726 object->presentParms.MultiSampleType,
1727 object->presentParms.MultiSampleQuality,
1728 TRUE /* Lockable */,
1729 &object->backBuffer[i],
1730 NULL /* pShared (always null)*/);
1731 if(hr == WINED3D_OK && object->backBuffer[i]) {
1732 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1738 object->backBuffer = NULL;
1741 if (object->backBuffer != NULL) {
1743 glDrawBuffer(GL_BACK);
1744 checkGLcall("glDrawBuffer(GL_BACK)");
1747 /* Single buffering - draw to front buffer */
1749 glDrawBuffer(GL_FRONT);
1750 checkGLcall("glDrawBuffer(GL_FRONT)");
1754 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1755 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1756 TRACE("Creating depth stencil buffer\n");
1757 if (This->depthStencilBuffer == NULL ) {
1758 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1759 object->presentParms.BackBufferWidth,
1760 object->presentParms.BackBufferHeight,
1761 object->presentParms.AutoDepthStencilFormat,
1762 object->presentParms.MultiSampleType,
1763 object->presentParms.MultiSampleQuality,
1764 FALSE /* FIXME: Discard */,
1765 &This->depthStencilBuffer,
1766 NULL /* pShared (always null)*/ );
1767 if (This->depthStencilBuffer != NULL)
1768 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1771 /** TODO: A check on width, height and multisample types
1772 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1773 ****************************/
1774 object->wantsDepthStencilBuffer = TRUE;
1776 object->wantsDepthStencilBuffer = FALSE;
1779 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1782 /*********************
1783 * init the default renderTarget management
1784 *******************/
1785 object->drawable = object->win;
1786 object->render_ctx = object->glCtx;
1788 if (hr == WINED3D_OK) {
1789 /*********************
1790 * Setup some defaults and clear down the buffers
1791 *******************/
1793 /** save current context and drawable **/
1794 oldContext = glXGetCurrentContext();
1795 oldDrawable = glXGetCurrentDrawable();
1797 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1798 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1799 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1801 checkGLcall("glXMakeCurrent");
1803 TRACE("Setting up the screen\n");
1804 /* Clear the screen */
1805 glClearColor(1.0, 0.0, 0.0, 0.0);
1806 checkGLcall("glClearColor");
1809 glClearStencil(0xffff);
1811 checkGLcall("glClear");
1813 glColor3f(1.0, 1.0, 1.0);
1814 checkGLcall("glColor3f");
1816 glEnable(GL_LIGHTING);
1817 checkGLcall("glEnable");
1819 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1820 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1822 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1823 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1825 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1826 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1828 /* switch back to the original context (if there was one)*/
1829 if (This->swapchains) {
1830 /** TODO: restore the context and drawable **/
1831 glXMakeCurrent(object->display, oldDrawable, oldContext);
1836 TRACE("Set swapchain to %p\n", object);
1837 } else { /* something went wrong so clean up */
1838 IUnknown* bufferParent;
1839 if (object->frontBuffer) {
1841 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1842 IUnknown_Release(bufferParent); /* once for the get parent */
1843 if (IUnknown_Release(bufferParent) > 0) {
1844 FIXME("(%p) Something's still holding the front buffer\n",This);
1847 if (object->backBuffer) {
1849 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1850 if(object->backBuffer[i]) {
1851 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1852 IUnknown_Release(bufferParent); /* once for the get parent */
1853 if (IUnknown_Release(bufferParent) > 0) {
1854 FIXME("(%p) Something's still holding the back buffer\n",This);
1858 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1859 object->backBuffer = NULL;
1861 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1862 /* Clean up the context */
1863 /* check that we are the current context first (we shouldn't be though!) */
1864 if (object->glCtx != 0) {
1865 if(glXGetCurrentContext() == object->glCtx) {
1866 glXMakeCurrent(object->display, None, NULL);
1868 glXDestroyContext(object->display, object->glCtx);
1870 HeapFree(GetProcessHeap(), 0, object);
1877 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1878 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 TRACE("(%p)\n", This);
1882 return This->NumberOfSwapChains;
1885 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1889 if(iSwapChain < This->NumberOfSwapChains) {
1890 *pSwapChain = This->swapchains[iSwapChain];
1891 IWineD3DSwapChain_AddRef(*pSwapChain);
1892 TRACE("(%p) returning %p\n", This, *pSwapChain);
1895 TRACE("Swapchain out of range\n");
1897 return WINED3DERR_INVALIDCALL;
1902 * Vertex Declaration
1904 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1906 IWineD3DVertexDeclarationImpl *object = NULL;
1907 HRESULT hr = WINED3D_OK;
1908 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1909 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1912 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1917 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1920 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1921 HRESULT hr = WINED3D_OK;
1922 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1923 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1925 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1927 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1928 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1929 if (pDeclaration != NULL) {
1930 IWineD3DVertexDeclaration *vertexDeclaration;
1931 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1932 if (WINED3D_OK == hr) {
1933 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1934 object->vertexDeclaration = vertexDeclaration;
1936 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1937 IWineD3DVertexShader_Release(*ppVertexShader);
1938 return WINED3DERR_INVALIDCALL;
1942 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1944 if (WINED3D_OK != hr) {
1945 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1946 IWineD3DVertexShader_Release(*ppVertexShader);
1947 return WINED3DERR_INVALIDCALL;
1950 #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. */
1951 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1962 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1964 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1965 HRESULT hr = WINED3D_OK;
1967 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1968 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1969 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1970 if (WINED3D_OK == hr) {
1971 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1973 WARN("(%p) : Failed to create pixel shader\n", This);
1979 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1981 IWineD3DPaletteImpl *object;
1983 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1985 /* Create the new object */
1986 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1988 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1989 return E_OUTOFMEMORY;
1992 object->lpVtbl = &IWineD3DPalette_Vtbl;
1994 object->Flags = Flags;
1995 object->parent = Parent;
1996 object->wineD3DDevice = This;
1997 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1999 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2002 HeapFree( GetProcessHeap(), 0, object);
2003 return E_OUTOFMEMORY;
2006 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2008 IWineD3DPalette_Release((IWineD3DPalette *) object);
2012 *Palette = (IWineD3DPalette *) object;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2019 IWineD3DSwapChainImpl *swapchain;
2021 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2022 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 /* TODO: Test if OpenGL is compiled in and loaded */
2026 /* Setup the implicit swapchain */
2027 TRACE("Creating implicit swapchain\n");
2028 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2029 WARN("Failed to create implicit swapchain\n");
2030 return WINED3DERR_INVALIDCALL;
2033 This->NumberOfSwapChains = 1;
2034 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2035 if(!This->swapchains) {
2036 ERR("Out of memory!\n");
2037 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2038 return E_OUTOFMEMORY;
2040 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2042 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2043 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2044 This->renderTarget = swapchain->backBuffer[0];
2047 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2048 This->renderTarget = swapchain->frontBuffer;
2050 IWineD3DSurface_AddRef(This->renderTarget);
2051 /* Depth Stencil support */
2052 This->stencilBufferTarget = This->depthStencilBuffer;
2053 if (NULL != This->stencilBufferTarget) {
2054 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2057 /* Set up some starting GL setup */
2060 * Initialize openGL extension related variables
2061 * with Default values
2064 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2065 /* Setup all the devices defaults */
2066 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2068 IWineD3DImpl_CheckGraphicsMemory();
2072 /* Initialize our list of GLSL programs */
2073 list_init(&This->glsl_shader_progs);
2075 { /* Set a default viewport */
2079 vp.Width = *(pPresentationParameters->BackBufferWidth);
2080 vp.Height = *(pPresentationParameters->BackBufferHeight);
2083 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2086 /* Initialize the current view state */
2087 This->modelview_valid = 1;
2088 This->proj_valid = 0;
2089 This->view_ident = 1;
2090 This->last_was_rhw = 0;
2091 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2092 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2094 /* Clear the screen */
2095 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2097 This->d3d_initialized = TRUE;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2104 IUnknown* stencilBufferParent;
2105 IUnknown* swapChainParent;
2107 TRACE("(%p)\n", This);
2109 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2111 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2112 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2115 /* Release the buffers (with sanity checks)*/
2116 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2117 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2118 if(This->depthStencilBuffer != This->stencilBufferTarget)
2119 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2121 This->stencilBufferTarget = NULL;
2123 TRACE("Releasing the render target at %p\n", This->renderTarget);
2124 if(IWineD3DSurface_Release(This->renderTarget) >0){
2125 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2127 TRACE("Setting rendertarget to NULL\n");
2128 This->renderTarget = NULL;
2130 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2131 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2132 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2133 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2135 This->depthStencilBuffer = NULL;
2137 for(i=0; i < This->NumberOfSwapChains; i++) {
2138 TRACE("Releasing the implicit swapchain %d\n", i);
2139 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2140 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2141 IUnknown_Release(swapChainParent); /* once for the get parent */
2142 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2143 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2147 HeapFree(GetProcessHeap(), 0, This->swapchains);
2148 This->swapchains = NULL;
2149 This->NumberOfSwapChains = 0;
2151 This->d3d_initialized = FALSE;
2155 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2160 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2162 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2164 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2165 /* Ignore some modes if a description was passed */
2166 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2167 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2168 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2170 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2172 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2179 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2183 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2185 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2187 /* Resize the screen even without a window:
2188 * The app could have unset it with SetCooperativeLevel, but not called
2189 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2190 * but we don't have any hwnd
2193 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2194 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2195 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2196 devmode.dmPelsWidth = pMode->Width;
2197 devmode.dmPelsHeight = pMode->Height;
2199 devmode.dmDisplayFrequency = pMode->RefreshRate;
2200 if (pMode->RefreshRate != 0) {
2201 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2204 /* Only change the mode if necessary */
2205 if( (This->ddraw_width == pMode->Width) &&
2206 (This->ddraw_height == pMode->Height) &&
2207 (This->ddraw_format == pMode->Format) &&
2208 (pMode->RefreshRate == 0) ) {
2212 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2213 if (ret != DISP_CHANGE_SUCCESSFUL) {
2214 if(devmode.dmDisplayFrequency != 0) {
2215 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2216 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2217 devmode.dmDisplayFrequency = 0;
2218 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2220 if(ret != DISP_CHANGE_SUCCESSFUL) {
2221 return DDERR_INVALIDMODE;
2225 /* Store the new values */
2226 This->ddraw_width = pMode->Width;
2227 This->ddraw_height = pMode->Height;
2228 This->ddraw_format = pMode->Format;
2230 /* Only do this with a window of course */
2231 if(This->ddraw_window)
2232 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2237 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2239 *ppD3D= This->wineD3D;
2240 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2241 IWineD3D_AddRef(*ppD3D);
2245 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2246 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2247 * Into the video ram as possible and seeing how many fit
2248 * you can also get the correct initial value from via X and ATI's driver
2249 *******************/
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 static BOOL showfixmes = TRUE;
2253 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2254 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2257 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2258 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2259 /* videomemory is simulated videomemory + AGP memory left */
2260 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2268 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2270 HRESULT hr = WINED3D_OK;
2272 /* Update the current state block */
2273 This->updateStateBlock->fvf = fvf;
2274 This->updateStateBlock->changed.fvf = TRUE;
2275 This->updateStateBlock->set.fvf = TRUE;
2277 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2282 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2284 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2285 *pfvf = This->stateBlock->fvf;
2290 * Get / Set Stream Source
2292 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2294 IWineD3DVertexBuffer *oldSrc;
2296 /**TODO: instance and index data, see
2297 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2299 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2302 /* D3d9 only, but shouldn't hurt d3d8 */
2305 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2307 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2308 FIXME("stream index data not supported\n");
2310 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2311 FIXME("stream instance data not supported\n");
2315 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2317 if (StreamNumber >= MAX_STREAMS) {
2318 WARN("Stream out of range %d\n", StreamNumber);
2319 return WINED3DERR_INVALIDCALL;
2322 oldSrc = This->stateBlock->streamSource[StreamNumber];
2323 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2325 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2326 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2327 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2328 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2329 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2330 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2332 /* Handle recording of state blocks */
2333 if (This->isRecordingState) {
2334 TRACE("Recording... not performing anything\n");
2338 /* Same stream object: no action */
2339 if (oldSrc == pStreamData)
2342 /* Need to do a getParent and pass the reffs up */
2343 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2344 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2345 so for now, just count internally */
2346 if (pStreamData != NULL) {
2347 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2348 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2349 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2351 vbImpl->stream = StreamNumber;
2352 vbImpl->Flags |= VBFLAG_STREAM;
2353 IWineD3DVertexBuffer_AddRef(pStreamData);
2355 if (oldSrc != NULL) {
2356 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2357 IWineD3DVertexBuffer_Release(oldSrc);
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2368 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2371 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2373 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2374 FIXME("stream index data not supported\n");
2376 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2377 FIXME("stream instance data not supported\n");
2381 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2383 if (StreamNumber >= MAX_STREAMS) {
2384 WARN("Stream out of range %d\n", StreamNumber);
2385 return WINED3DERR_INVALIDCALL;
2387 *pStream = This->stateBlock->streamSource[StreamNumber];
2388 *pStride = This->stateBlock->streamStride[StreamNumber];
2389 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2391 if (*pStream == NULL) {
2392 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2393 return WINED3DERR_INVALIDCALL;
2396 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2400 /*Should be quite easy, just an extension of vertexdata
2402 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2404 The divider is a bit odd though
2406 VertexOffset = StartVertex / Divider * StreamStride +
2407 VertexIndex / Divider * StreamStride + StreamOffset
2410 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2414 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2416 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2417 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2418 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2420 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2421 FIXME("Stream indexing not fully supported\n");
2427 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2431 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2433 TRACE("(%p) : returning %d\n", This, *Divider);
2439 * Get / Set & Multiply Transform
2441 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 /* Most of this routine, comments included copied from ddraw tree initially: */
2445 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2447 /* Handle recording of state blocks */
2448 if (This->isRecordingState) {
2449 TRACE("Recording... not performing anything\n");
2450 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2451 This->updateStateBlock->set.transform[d3dts] = TRUE;
2452 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2457 * If the new matrix is the same as the current one,
2458 * we cut off any further processing. this seems to be a reasonable
2459 * optimization because as was noticed, some apps (warcraft3 for example)
2460 * tend towards setting the same matrix repeatedly for some reason.
2462 * From here on we assume that the new matrix is different, wherever it matters.
2464 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2465 TRACE("The app is setting the same matrix over again\n");
2468 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2472 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2473 where ViewMat = Camera space, WorldMat = world space.
2475 In OpenGL, camera and world space is combined into GL_MODELVIEW
2476 matrix. The Projection matrix stay projection matrix.
2479 /* Capture the times we can just ignore the change for now */
2480 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2481 This->modelview_valid = FALSE;
2484 } else if (d3dts == D3DTS_PROJECTION) {
2485 This->proj_valid = FALSE;
2488 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2489 /* Indexed Vertex Blending Matrices 256 -> 511 */
2490 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2491 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2495 /* Now we really are going to have to change a matrix */
2498 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2499 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2500 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2503 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2504 * NOTE: We have to reset the positions even if the light/plane is not currently
2505 * enabled, since the call to enable it will not reset the position.
2506 * NOTE2: Apparently texture transforms do NOT need reapplying
2509 PLIGHTINFOEL *lightChain = NULL;
2510 This->modelview_valid = FALSE;
2511 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2513 glMatrixMode(GL_MODELVIEW);
2514 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2516 glLoadMatrixf((float *)lpmatrix);
2517 checkGLcall("glLoadMatrixf(...)");
2520 lightChain = This->stateBlock->lights;
2521 while (lightChain && lightChain->glIndex != -1) {
2522 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2523 checkGLcall("glLightfv posn");
2524 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2525 checkGLcall("glLightfv dirn");
2526 lightChain = lightChain->next;
2529 /* Reset Clipping Planes if clipping is enabled */
2530 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2531 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2532 checkGLcall("glClipPlane");
2536 } else { /* What was requested!?? */
2537 WARN("invalid matrix specified: %i\n", d3dts);
2540 /* Release lock, all done */
2545 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 TRACE("(%p) : for Transform State %d\n", This, State);
2548 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2552 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2553 D3DMATRIX *mat = NULL;
2556 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2557 * below means it will be recorded in a state block change, but it
2558 * works regardless where it is recorded.
2559 * If this is found to be wrong, change to StateBlock.
2561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2562 TRACE("(%p) : For state %u\n", This, State);
2564 if (State < HIGHEST_TRANSFORMSTATE)
2566 mat = &This->updateStateBlock->transforms[State];
2568 FIXME("Unhandled transform state!!\n");
2571 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2573 /* Apply change via set transform - will reapply to eg. lights this way */
2574 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2579 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2581 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2582 you can reference any indexes you want as long as that number max are enabled at any
2583 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2584 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2585 but when recording, just build a chain pretty much of commands to be replayed. */
2587 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2589 PLIGHTINFOEL *object, *temp;
2591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2592 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2594 /* If recording state block, just add to end of lights chain */
2595 if (This->isRecordingState) {
2596 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2597 if (NULL == object) {
2598 return WINED3DERR_OUTOFVIDEOMEMORY;
2600 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2601 object->OriginalIndex = Index;
2602 object->glIndex = -1;
2603 object->changed = TRUE;
2605 /* Add to the END of the chain of lights changes to be replayed */
2606 if (This->updateStateBlock->lights == NULL) {
2607 This->updateStateBlock->lights = object;
2609 temp = This->updateStateBlock->lights;
2610 while (temp->next != NULL) temp=temp->next;
2611 temp->next = object;
2613 TRACE("Recording... not performing anything more\n");
2617 /* Ok, not recording any longer so do real work */
2618 object = This->stateBlock->lights;
2619 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2621 /* If we didn't find it in the list of lights, time to add it */
2622 if (object == NULL) {
2623 PLIGHTINFOEL *insertAt,*prevPos;
2625 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2626 if (NULL == object) {
2627 return WINED3DERR_OUTOFVIDEOMEMORY;
2629 object->OriginalIndex = Index;
2630 object->glIndex = -1;
2632 /* Add it to the front of list with the idea that lights will be changed as needed
2633 BUT after any lights currently assigned GL indexes */
2634 insertAt = This->stateBlock->lights;
2636 while (insertAt != NULL && insertAt->glIndex != -1) {
2638 insertAt = insertAt->next;
2641 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2642 This->stateBlock->lights = object;
2643 } else if (insertAt == NULL) { /* End of list */
2644 prevPos->next = object;
2645 object->prev = prevPos;
2646 } else { /* Middle of chain */
2647 if (prevPos == NULL) {
2648 This->stateBlock->lights = object;
2650 prevPos->next = object;
2652 object->prev = prevPos;
2653 object->next = insertAt;
2654 insertAt->prev = object;
2658 /* Initialize the object */
2659 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,
2660 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2661 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2662 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2663 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2664 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2665 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2667 /* Save away the information */
2668 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2670 switch (pLight->Type) {
2671 case D3DLIGHT_POINT:
2673 object->lightPosn[0] = pLight->Position.x;
2674 object->lightPosn[1] = pLight->Position.y;
2675 object->lightPosn[2] = pLight->Position.z;
2676 object->lightPosn[3] = 1.0f;
2677 object->cutoff = 180.0f;
2681 case D3DLIGHT_DIRECTIONAL:
2683 object->lightPosn[0] = -pLight->Direction.x;
2684 object->lightPosn[1] = -pLight->Direction.y;
2685 object->lightPosn[2] = -pLight->Direction.z;
2686 object->lightPosn[3] = 0.0;
2687 object->exponent = 0.0f;
2688 object->cutoff = 180.0f;
2693 object->lightPosn[0] = pLight->Position.x;
2694 object->lightPosn[1] = pLight->Position.y;
2695 object->lightPosn[2] = pLight->Position.z;
2696 object->lightPosn[3] = 1.0;
2699 object->lightDirn[0] = pLight->Direction.x;
2700 object->lightDirn[1] = pLight->Direction.y;
2701 object->lightDirn[2] = pLight->Direction.z;
2702 object->lightDirn[3] = 1.0;
2705 * opengl-ish and d3d-ish spot lights use too different models for the
2706 * light "intensity" as a function of the angle towards the main light direction,
2707 * so we only can approximate very roughly.
2708 * however spot lights are rather rarely used in games (if ever used at all).
2709 * furthermore if still used, probably nobody pays attention to such details.
2711 if (pLight->Falloff == 0) {
2714 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2716 if (rho < 0.0001) rho = 0.0001f;
2717 object->exponent = -0.3/log(cos(rho/2));
2718 object->cutoff = pLight->Phi*90/M_PI;
2724 FIXME("Unrecognized light type %d\n", pLight->Type);
2727 /* Update the live definitions if the light is currently assigned a glIndex */
2728 if (object->glIndex != -1) {
2729 setup_light(iface, object->glIndex, object);
2734 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2735 PLIGHTINFOEL *lightInfo = NULL;
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2739 /* Locate the light in the live lights */
2740 lightInfo = This->stateBlock->lights;
2741 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2743 if (lightInfo == NULL) {
2744 TRACE("Light information requested but light not defined\n");
2745 return WINED3DERR_INVALIDCALL;
2748 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2753 * Get / Set Light Enable
2754 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2756 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2757 PLIGHTINFOEL *lightInfo = NULL;
2758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2759 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2761 /* Tests show true = 128...not clear why */
2763 Enable = Enable? 128: 0;
2765 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2766 if (This->isRecordingState) {
2767 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2768 if (NULL == lightInfo) {
2769 return WINED3DERR_OUTOFVIDEOMEMORY;
2771 lightInfo->OriginalIndex = Index;
2772 lightInfo->glIndex = -1;
2773 lightInfo->enabledChanged = TRUE;
2774 lightInfo->lightEnabled = Enable;
2776 /* Add to the END of the chain of lights changes to be replayed */
2777 if (This->updateStateBlock->lights == NULL) {
2778 This->updateStateBlock->lights = lightInfo;
2780 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2781 while (temp->next != NULL) temp=temp->next;
2782 temp->next = lightInfo;
2784 TRACE("Recording... not performing anything more\n");
2788 /* Not recording... So, locate the light in the live lights */
2789 lightInfo = This->stateBlock->lights;
2790 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2792 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2793 if (lightInfo == NULL) {
2795 TRACE("Light enabled requested but light not defined, so defining one!\n");
2796 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2798 /* Search for it again! Should be fairly quick as near head of list */
2799 lightInfo = This->stateBlock->lights;
2800 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2801 if (lightInfo == NULL) {
2802 FIXME("Adding default lights has failed dismally\n");
2803 return WINED3DERR_INVALIDCALL;
2807 /* OK, we now have a light... */
2808 if (Enable == FALSE) {
2810 /* If we are disabling it, check it was enabled, and
2811 still only do something if it has assigned a glIndex (which it should have!) */
2812 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2813 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2815 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2816 checkGLcall("glDisable GL_LIGHT0+Index");
2819 TRACE("Nothing to do as light was not enabled\n");
2821 lightInfo->lightEnabled = Enable;
2824 /* We are enabling it. If it is enabled, it's really simple */
2825 if (lightInfo->lightEnabled) {
2827 TRACE("Nothing to do as light was enabled\n");
2829 /* If it already has a glIndex, it's still simple */
2830 } else if (lightInfo->glIndex != -1) {
2831 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2832 lightInfo->lightEnabled = Enable;
2834 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2835 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2838 /* Otherwise got to find space - lights are ordered gl indexes first */
2840 PLIGHTINFOEL *bsf = NULL;
2841 PLIGHTINFOEL *pos = This->stateBlock->lights;
2842 PLIGHTINFOEL *prev = NULL;
2846 /* Try to minimize changes as much as possible */
2847 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2849 /* Try to remember which index can be replaced if necessary */
2850 if (bsf==NULL && pos->lightEnabled == FALSE) {
2851 /* Found a light we can replace, save as best replacement */
2855 /* Step to next space */
2861 /* If we have too many active lights, fail the call */
2862 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2863 FIXME("Program requests too many concurrent lights\n");
2864 return WINED3DERR_INVALIDCALL;
2866 /* If we have allocated all lights, but not all are enabled,
2867 reuse one which is not enabled */
2868 } else if (Index == This->maxConcurrentLights) {
2869 /* use bsf - Simply swap the new light and the BSF one */
2870 PLIGHTINFOEL *bsfNext = bsf->next;
2871 PLIGHTINFOEL *bsfPrev = bsf->prev;
2874 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2875 if (bsf->prev != NULL) {
2876 bsf->prev->next = lightInfo;
2878 This->stateBlock->lights = lightInfo;
2881 /* If not side by side, lots of chains to update */
2882 if (bsf->next != lightInfo) {
2883 lightInfo->prev->next = bsf;
2884 bsf->next->prev = lightInfo;
2885 bsf->next = lightInfo->next;
2886 bsf->prev = lightInfo->prev;
2887 lightInfo->next = bsfNext;
2888 lightInfo->prev = bsfPrev;
2892 bsf->prev = lightInfo;
2893 bsf->next = lightInfo->next;
2894 lightInfo->next = bsf;
2895 lightInfo->prev = bsfPrev;
2900 glIndex = bsf->glIndex;
2902 lightInfo->glIndex = glIndex;
2903 lightInfo->lightEnabled = Enable;
2905 /* Finally set up the light in gl itself */
2906 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2908 setup_light(iface, glIndex, lightInfo);
2909 glEnable(GL_LIGHT0 + glIndex);
2910 checkGLcall("glEnable GL_LIGHT0 new setup");
2913 /* If we reached the end of the allocated lights, with space in the
2914 gl lights, setup a new light */
2915 } else if (pos->glIndex == -1) {
2917 /* We reached the end of the allocated gl lights, so already
2918 know the index of the next one! */
2920 lightInfo->glIndex = glIndex;
2921 lightInfo->lightEnabled = Enable;
2923 /* In an ideal world, it's already in the right place */
2924 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2925 /* No need to move it */
2927 /* Remove this light from the list */
2928 lightInfo->prev->next = lightInfo->next;
2929 if (lightInfo->next != NULL) {
2930 lightInfo->next->prev = lightInfo->prev;
2933 /* Add in at appropriate place (inbetween prev and pos) */
2934 lightInfo->prev = prev;
2935 lightInfo->next = pos;
2937 This->stateBlock->lights = lightInfo;
2939 prev->next = lightInfo;
2942 pos->prev = lightInfo;
2946 /* Finally set up the light in gl itself */
2947 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2949 setup_light(iface, glIndex, lightInfo);
2950 glEnable(GL_LIGHT0 + glIndex);
2951 checkGLcall("glEnable GL_LIGHT0 new setup");
2960 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2962 PLIGHTINFOEL *lightInfo = NULL;
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p) : for idx(%ld)\n", This, Index);
2966 /* Locate the light in the live lights */
2967 lightInfo = This->stateBlock->lights;
2968 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2970 if (lightInfo == NULL) {
2971 TRACE("Light enabled state requested but light not defined\n");
2972 return WINED3DERR_INVALIDCALL;
2974 *pEnable = lightInfo->lightEnabled;
2979 * Get / Set Clip Planes
2981 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2985 /* Validate Index */
2986 if (Index >= GL_LIMITS(clipplanes)) {
2987 TRACE("Application has requested clipplane this device doesn't support\n");
2988 return WINED3DERR_INVALIDCALL;
2991 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2992 This->updateStateBlock->set.clipplane[Index] = TRUE;
2993 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2994 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2995 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2996 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2998 /* Handle recording of state blocks */
2999 if (This->isRecordingState) {
3000 TRACE("Recording... not performing anything\n");
3008 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3009 glMatrixMode(GL_MODELVIEW);
3011 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3013 TRACE("Clipplane [%f,%f,%f,%f]\n",
3014 This->updateStateBlock->clipplane[Index][0],
3015 This->updateStateBlock->clipplane[Index][1],
3016 This->updateStateBlock->clipplane[Index][2],
3017 This->updateStateBlock->clipplane[Index][3]);
3018 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3019 checkGLcall("glClipPlane");
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 TRACE("(%p) : for idx %ld\n", This, Index);
3031 /* Validate Index */
3032 if (Index >= GL_LIMITS(clipplanes)) {
3033 TRACE("Application has requested clipplane this device doesn't support\n");
3034 return WINED3DERR_INVALIDCALL;
3037 pPlane[0] = This->stateBlock->clipplane[Index][0];
3038 pPlane[1] = This->stateBlock->clipplane[Index][1];
3039 pPlane[2] = This->stateBlock->clipplane[Index][2];
3040 pPlane[3] = This->stateBlock->clipplane[Index][3];
3045 * Get / Set Clip Plane Status
3046 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3048 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 FIXME("(%p) : stub\n", This);
3051 if (NULL == pClipStatus) {
3052 return WINED3DERR_INVALIDCALL;
3054 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3055 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3059 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 FIXME("(%p) : stub\n", This);
3062 if (NULL == pClipStatus) {
3063 return WINED3DERR_INVALIDCALL;
3065 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3066 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3071 * Get / Set Material
3072 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3074 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 This->updateStateBlock->changed.material = TRUE;
3078 This->updateStateBlock->set.material = TRUE;
3079 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3081 /* Handle recording of state blocks */
3082 if (This->isRecordingState) {
3083 TRACE("Recording... not performing anything\n");
3088 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3089 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3090 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3091 pMaterial->Ambient.b, pMaterial->Ambient.a);
3092 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3093 pMaterial->Specular.b, pMaterial->Specular.a);
3094 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3095 pMaterial->Emissive.b, pMaterial->Emissive.a);
3096 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3098 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3099 checkGLcall("glMaterialfv(GL_AMBIENT)");
3100 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3101 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3103 /* Only change material color if specular is enabled, otherwise it is set to black */
3104 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3105 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3106 checkGLcall("glMaterialfv(GL_SPECULAR");
3108 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3109 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3110 checkGLcall("glMaterialfv(GL_SPECULAR");
3112 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3113 checkGLcall("glMaterialfv(GL_EMISSION)");
3114 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3115 checkGLcall("glMaterialf(GL_SHININESS");
3121 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3124 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3125 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3126 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3127 pMaterial->Ambient.b, pMaterial->Ambient.a);
3128 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3129 pMaterial->Specular.b, pMaterial->Specular.a);
3130 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3131 pMaterial->Emissive.b, pMaterial->Emissive.a);
3132 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3141 UINT BaseVertexIndex) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 IWineD3DIndexBuffer *oldIdxs;
3145 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3146 oldIdxs = This->updateStateBlock->pIndexData;
3148 This->updateStateBlock->changed.indices = TRUE;
3149 This->updateStateBlock->set.indices = TRUE;
3150 This->updateStateBlock->pIndexData = pIndexData;
3151 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3159 if (NULL != pIndexData) {
3160 IWineD3DIndexBuffer_AddRef(pIndexData);
3162 if (NULL != oldIdxs) {
3163 IWineD3DIndexBuffer_Release(oldIdxs);
3168 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 *ppIndexData = This->stateBlock->pIndexData;
3173 /* up ref count on ppindexdata */
3175 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3176 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3177 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3179 TRACE("(%p) No index data set\n", This);
3181 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3187 * Get / Set Viewports
3189 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 TRACE("(%p)\n", This);
3193 This->updateStateBlock->changed.viewport = TRUE;
3194 This->updateStateBlock->set.viewport = TRUE;
3195 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3197 /* Handle recording of state blocks */
3198 if (This->isRecordingState) {
3199 TRACE("Recording... not performing anything\n");
3202 This->viewport_changed = TRUE;
3206 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3207 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3209 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3210 checkGLcall("glDepthRange");
3211 /* Note: GL requires lower left, DirectX supplies upper left */
3212 /* TODO: replace usage of renderTarget with context management */
3213 glViewport(pViewport->X,
3214 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3215 pViewport->Width, pViewport->Height);
3217 checkGLcall("glViewport");
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(%p)\n", This);
3228 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3232 static void renderstate_stencil_twosided(
3233 IWineD3DDeviceImpl *This,
3240 GLint stencilPass ) {
3241 #if 0 /* Don't use OpenGL 2.0 calls for now */
3242 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3243 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3244 checkGLcall("glStencilFuncSeparate(...)");
3245 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3246 checkGLcall("glStencilOpSeparate(...)");
3250 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3251 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3252 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3253 GL_EXTCALL(glActiveStencilFaceEXT(face));
3254 checkGLcall("glActiveStencilFaceEXT(...)");
3255 glStencilFunc(func, ref, mask);
3256 checkGLcall("glStencilFunc(...)");
3257 glStencilOp(stencilFail, depthFail, stencilPass);
3258 checkGLcall("glStencilOp(...)");
3259 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3260 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3261 checkGLcall("glStencilFuncSeparateATI(...)");
3262 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3263 checkGLcall("glStencilOpSeparateATI(...)");
3265 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3269 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3270 DWORD onesided_enable = FALSE;
3271 DWORD twosided_enable = FALSE;
3272 GLint func = GL_ALWAYS;
3273 GLint func_ccw = GL_ALWAYS;
3276 GLint stencilFail = GL_KEEP;
3277 GLint depthFail = GL_KEEP;
3278 GLint stencilPass = GL_KEEP;
3279 GLint stencilFail_ccw = GL_KEEP;
3280 GLint depthFail_ccw = GL_KEEP;
3281 GLint stencilPass_ccw = GL_KEEP;
3283 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3284 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3285 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3286 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3287 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3288 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3289 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3290 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3291 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3292 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3293 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3294 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3295 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3296 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3297 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3298 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3299 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3300 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3301 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3302 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3303 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3304 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3305 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3306 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3309 case WINED3DRS_STENCILENABLE :
3310 onesided_enable = Value;
3312 case WINED3DRS_TWOSIDEDSTENCILMODE :
3313 twosided_enable = Value;
3315 case WINED3DRS_STENCILFUNC :
3316 func = StencilFunc(Value);
3318 case WINED3DRS_CCW_STENCILFUNC :
3319 func_ccw = StencilFunc(Value);
3321 case WINED3DRS_STENCILREF :
3324 case WINED3DRS_STENCILMASK :
3327 case WINED3DRS_STENCILFAIL :
3328 stencilFail = StencilOp(Value);
3330 case WINED3DRS_STENCILZFAIL :
3331 depthFail = StencilOp(Value);
3333 case WINED3DRS_STENCILPASS :
3334 stencilPass = StencilOp(Value);
3336 case WINED3DRS_CCW_STENCILFAIL :
3337 stencilFail_ccw = StencilOp(Value);
3339 case WINED3DRS_CCW_STENCILZFAIL :
3340 depthFail_ccw = StencilOp(Value);
3342 case WINED3DRS_CCW_STENCILPASS :
3343 stencilPass_ccw = StencilOp(Value);
3346 ERR("This should not happen!");
3349 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3350 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3351 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3352 onesided_enable, twosided_enable, ref, mask,
3353 func, stencilFail, depthFail, stencilPass,
3354 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3356 if (twosided_enable) {
3357 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3358 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3360 if (onesided_enable) {
3361 glEnable(GL_STENCIL_TEST);
3362 checkGLcall("glEnable GL_STENCIL_TEST");
3363 glStencilFunc(func, ref, mask);
3364 checkGLcall("glStencilFunc(...)");
3365 glStencilOp(stencilFail, depthFail, stencilPass);
3366 checkGLcall("glStencilOp(...)");
3368 glDisable(GL_STENCIL_TEST);
3369 checkGLcall("glDisable GL_STENCIL_TEST");
3375 * Get / Set Render States
3376 * TODO: Verify against dx9 definitions
3378 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 DWORD OldValue = This->stateBlock->renderState[State];
3383 /* Simple way of referring to either a DWORD or a 4 byte float */
3389 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3390 This->updateStateBlock->changed.renderState[State] = TRUE;
3391 This->updateStateBlock->set.renderState[State] = TRUE;
3392 This->updateStateBlock->renderState[State] = Value;
3394 /* Handle recording of state blocks */
3395 if (This->isRecordingState) {
3396 TRACE("Recording... not performing anything\n");
3403 case WINED3DRS_FILLMODE :
3404 switch ((D3DFILLMODE) Value) {
3405 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3406 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3407 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3409 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3411 checkGLcall("glPolygonMode (fillmode)");
3414 case WINED3DRS_LIGHTING :
3416 glEnable(GL_LIGHTING);
3417 checkGLcall("glEnable GL_LIGHTING");
3419 glDisable(GL_LIGHTING);
3420 checkGLcall("glDisable GL_LIGHTING");
3424 case WINED3DRS_ZENABLE :
3425 switch ((D3DZBUFFERTYPE) Value) {
3427 glDisable(GL_DEPTH_TEST);
3428 checkGLcall("glDisable GL_DEPTH_TEST");
3431 glEnable(GL_DEPTH_TEST);
3432 checkGLcall("glEnable GL_DEPTH_TEST");
3435 glEnable(GL_DEPTH_TEST);
3436 checkGLcall("glEnable GL_DEPTH_TEST");
3437 FIXME("W buffer is not well handled\n");
3440 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3444 case WINED3DRS_CULLMODE :
3446 /* If we are culling "back faces with clockwise vertices" then
3447 set front faces to be counter clockwise and enable culling
3449 switch ((D3DCULL) Value) {
3451 glDisable(GL_CULL_FACE);
3452 checkGLcall("glDisable GL_CULL_FACE");
3455 glEnable(GL_CULL_FACE);
3456 checkGLcall("glEnable GL_CULL_FACE");
3457 if (This->renderUpsideDown) {
3459 checkGLcall("glFrontFace GL_CW");
3461 glFrontFace(GL_CCW);
3462 checkGLcall("glFrontFace GL_CCW");
3464 glCullFace(GL_BACK);
3467 glEnable(GL_CULL_FACE);
3468 checkGLcall("glEnable GL_CULL_FACE");
3469 if (This->renderUpsideDown) {
3470 glFrontFace(GL_CCW);
3471 checkGLcall("glFrontFace GL_CCW");
3474 checkGLcall("glFrontFace GL_CW");
3476 glCullFace(GL_BACK);
3479 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3483 case WINED3DRS_SHADEMODE :
3484 switch ((D3DSHADEMODE) Value) {
3486 glShadeModel(GL_FLAT);
3487 checkGLcall("glShadeModel");
3489 case D3DSHADE_GOURAUD:
3490 glShadeModel(GL_SMOOTH);
3491 checkGLcall("glShadeModel");
3493 case D3DSHADE_PHONG:
3494 FIXME("D3DSHADE_PHONG isn't supported\n");
3497 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3501 case WINED3DRS_DITHERENABLE :
3503 glEnable(GL_DITHER);
3504 checkGLcall("glEnable GL_DITHER");
3506 glDisable(GL_DITHER);
3507 checkGLcall("glDisable GL_DITHER");
3511 case WINED3DRS_ZWRITEENABLE :
3514 checkGLcall("glDepthMask");
3517 checkGLcall("glDepthMask");
3521 case WINED3DRS_ZFUNC :
3523 int glParm = GL_LESS;
3525 switch ((D3DCMPFUNC) Value) {
3526 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3527 case D3DCMP_LESS: glParm=GL_LESS; break;
3528 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3529 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3530 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3531 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3532 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3533 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3535 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3537 glDepthFunc(glParm);
3538 checkGLcall("glDepthFunc");
3542 case WINED3DRS_AMBIENT :
3545 D3DCOLORTOGLFLOAT4(Value, col);
3546 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3547 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3548 checkGLcall("glLightModel for MODEL_AMBIENT");
3553 case WINED3DRS_ALPHABLENDENABLE :
3556 checkGLcall("glEnable GL_BLEND");
3558 glDisable(GL_BLEND);
3559 checkGLcall("glDisable GL_BLEND");
3563 case WINED3DRS_SRCBLEND :
3564 case WINED3DRS_DESTBLEND :
3566 int newVal = GL_ZERO;
3568 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3569 case D3DBLEND_ONE : newVal = GL_ONE; break;
3570 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3571 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3572 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3573 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3574 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3575 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3576 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3577 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3578 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3580 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3581 This->srcBlend = newVal;
3582 This->dstBlend = newVal;
3585 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3586 This->srcBlend = newVal;
3587 This->dstBlend = newVal;
3590 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3593 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3594 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3595 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3596 glBlendFunc(This->srcBlend, This->dstBlend);
3598 checkGLcall("glBlendFunc");
3602 case WINED3DRS_ALPHATESTENABLE :
3603 case WINED3DRS_ALPHAFUNC :
3604 case WINED3DRS_ALPHAREF :
3605 case WINED3DRS_COLORKEYENABLE :
3608 float ref = GL_LESS;
3609 BOOL enable_ckey = FALSE;
3611 IWineD3DSurfaceImpl *surf;
3613 /* Find out if the texture on the first stage has a ckey set */
3614 if(This->stateBlock->textures[0]) {
3615 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3616 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3619 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3620 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3621 glEnable(GL_ALPHA_TEST);
3622 checkGLcall("glEnable GL_ALPHA_TEST");
3624 glDisable(GL_ALPHA_TEST);
3625 checkGLcall("glDisable GL_ALPHA_TEST");
3626 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3632 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3633 glParm = GL_NOTEQUAL;
3636 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3638 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3639 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3640 case D3DCMP_LESS: glParm = GL_LESS; break;
3641 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3642 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3643 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3644 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3645 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3646 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3648 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3651 This->alphafunc = glParm;
3652 glAlphaFunc(glParm, ref);
3653 checkGLcall("glAlphaFunc");
3657 case WINED3DRS_CLIPPLANEENABLE :
3658 case WINED3DRS_CLIPPING :
3660 /* Ensure we only do the changed clip planes */
3661 DWORD enable = 0xFFFFFFFF;
3662 DWORD disable = 0x00000000;
3664 /* If enabling / disabling all */
3665 if (State == WINED3DRS_CLIPPING) {
3667 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3670 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3674 enable = Value & ~OldValue;
3675 disable = ~Value & OldValue;
3678 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3679 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3680 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3681 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3682 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3683 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3685 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3686 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3687 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3688 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3689 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3690 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3692 /** update clipping status */
3694 This->stateBlock->clip_status.ClipUnion = 0;
3695 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3697 This->stateBlock->clip_status.ClipUnion = 0;
3698 This->stateBlock->clip_status.ClipIntersection = 0;
3703 case WINED3DRS_BLENDOP :
3705 int glParm = GL_FUNC_ADD;
3707 switch ((D3DBLENDOP) Value) {
3708 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3709 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3710 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3711 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3712 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3714 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3717 if(GL_SUPPORT(ARB_IMAGING)) {
3718 TRACE("glBlendEquation(%x)\n", glParm);
3719 GL_EXTCALL(glBlendEquation(glParm));
3720 checkGLcall("glBlendEquation");
3722 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3727 case WINED3DRS_TEXTUREFACTOR :
3731 /* Note the texture color applies to all textures whereas
3732 GL_TEXTURE_ENV_COLOR applies to active only */
3734 D3DCOLORTOGLFLOAT4(Value, col);
3735 /* Set the default alpha blend color */
3736 if (GL_SUPPORT(ARB_IMAGING)) {
3737 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3738 checkGLcall("glBlendColor");
3740 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3743 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3744 /* And now the default texture color as well */
3745 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3746 /* Note the D3DRS value applies to all textures, but GL has one
3747 per texture, so apply it now ready to be used! */
3748 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3749 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3750 checkGLcall("glActiveTextureARB");
3752 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3755 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3756 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3762 case WINED3DRS_SPECULARENABLE :
3764 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3765 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3766 specular color. This is wrong:
3767 Separate specular color means the specular colour is maintained separately, whereas
3768 single color means it is merged in. However in both cases they are being used to
3770 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3771 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3775 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3776 * Instead, we need to setup the FinalCombiner properly.
3778 * The default setup for the FinalCombiner is:
3780 * <variable> <input> <mapping> <usage>
3781 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3782 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3783 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3784 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3785 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3786 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3787 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3789 * That's pretty much fine as it is, except for variable B, which needs to take
3790 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3791 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3795 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3796 checkGLcall("glMaterialfv");
3797 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3798 glEnable(GL_COLOR_SUM_EXT);
3800 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3802 checkGLcall("glEnable(GL_COLOR_SUM)");
3804 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3805 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3806 checkGLcall("glFinalCombinerInputNV()");
3809 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3811 /* for the case of enabled lighting: */
3812 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3813 checkGLcall("glMaterialfv");
3815 /* for the case of disabled lighting: */
3816 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3817 glDisable(GL_COLOR_SUM_EXT);
3819 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3821 checkGLcall("glDisable(GL_COLOR_SUM)");
3823 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3824 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3825 checkGLcall("glFinalCombinerInputNV()");
3831 case WINED3DRS_STENCILENABLE :
3832 case WINED3DRS_TWOSIDEDSTENCILMODE :
3833 case WINED3DRS_STENCILFUNC :
3834 case WINED3DRS_CCW_STENCILFUNC :
3835 case WINED3DRS_STENCILREF :
3836 case WINED3DRS_STENCILMASK :
3837 case WINED3DRS_STENCILFAIL :
3838 case WINED3DRS_STENCILZFAIL :
3839 case WINED3DRS_STENCILPASS :
3840 case WINED3DRS_CCW_STENCILFAIL :
3841 case WINED3DRS_CCW_STENCILZFAIL :
3842 case WINED3DRS_CCW_STENCILPASS :
3843 renderstate_stencil(This, State, Value);
3845 case WINED3DRS_STENCILWRITEMASK :
3847 glStencilMask(Value);
3848 TRACE("glStencilMask(%lu)\n", Value);
3849 checkGLcall("glStencilMask");
3853 case WINED3DRS_FOGENABLE :
3857 checkGLcall("glEnable GL_FOG");
3860 checkGLcall("glDisable GL_FOG");
3865 case WINED3DRS_RANGEFOGENABLE :
3868 TRACE("Enabled RANGEFOG");
3870 TRACE("Disabled RANGEFOG");
3875 case WINED3DRS_FOGCOLOR :
3878 D3DCOLORTOGLFLOAT4(Value, col);
3879 /* Set the default alpha blend color */
3880 glFogfv(GL_FOG_COLOR, &col[0]);
3881 checkGLcall("glFog GL_FOG_COLOR");
3885 case WINED3DRS_FOGTABLEMODE :
3886 case WINED3DRS_FOGVERTEXMODE :
3888 /* 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." */
3889 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3890 glHint(GL_FOG_HINT, GL_FASTEST);
3891 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3892 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3893 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3894 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3897 if(!This->last_was_rhw) {
3898 glFogi(GL_FOG_MODE, GL_EXP);
3899 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3900 if(GL_SUPPORT(EXT_FOG_COORD)) {
3901 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3902 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3903 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3904 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3910 if(!This->last_was_rhw) {
3911 glFogi(GL_FOG_MODE, GL_EXP2);
3912 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3913 if(GL_SUPPORT(EXT_FOG_COORD)) {
3914 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3915 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3916 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3917 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3922 case D3DFOG_LINEAR: {
3923 if(!This->last_was_rhw) {
3924 glFogi(GL_FOG_MODE, GL_LINEAR);
3925 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3926 if(GL_SUPPORT(EXT_FOG_COORD)) {
3927 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3928 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3929 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3930 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3936 /* Both are none? According to msdn the alpha channel of the specular
3937 * color contains a fog factor. Set it in drawStridedSlow.
3938 * Same happens with Vertexfog on transformed vertices
3940 if(GL_SUPPORT(EXT_FOG_COORD)) {
3941 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3942 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3943 glFogi(GL_FOG_MODE, GL_LINEAR);
3944 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3945 glFogf(GL_FOG_START, (float) 0xff);
3946 checkGLcall("glFogfv GL_FOG_START");
3947 glFogf(GL_FOG_END, 0.0);
3948 checkGLcall("glFogfv GL_FOG_END");
3950 /* Disable GL fog, handle this in software in drawStridedSlow */
3952 checkGLcall("glDisable(GL_FOG)");
3956 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3959 glHint(GL_FOG_HINT, GL_NICEST);
3960 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3961 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3962 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3963 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3964 if(GL_SUPPORT(EXT_FOG_COORD)) {
3965 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3966 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3967 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3968 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3971 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3972 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3973 if(GL_SUPPORT(EXT_FOG_COORD)) {
3974 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3975 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3976 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3977 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3980 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3981 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3982 if(GL_SUPPORT(EXT_FOG_COORD)) {
3983 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3984 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3985 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3986 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3989 case D3DFOG_NONE: /* Won't happen */
3990 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3993 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3994 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3999 case WINED3DRS_FOGSTART :
4002 glFogfv(GL_FOG_START, &tmpvalue.f);
4003 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4004 TRACE("Fog Start == %f\n", tmpvalue.f);
4008 case WINED3DRS_FOGEND :
4011 glFogfv(GL_FOG_END, &tmpvalue.f);
4012 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4013 TRACE("Fog End == %f\n", tmpvalue.f);
4017 case WINED3DRS_FOGDENSITY :
4020 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4021 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4025 case WINED3DRS_VERTEXBLEND :
4027 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4028 TRACE("Vertex Blending state to %ld\n", Value);
4032 case WINED3DRS_TWEENFACTOR :
4035 This->updateStateBlock->tween_factor = tmpvalue.f;
4036 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4040 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4042 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4046 case WINED3DRS_COLORVERTEX :
4047 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4048 case WINED3DRS_SPECULARMATERIALSOURCE :
4049 case WINED3DRS_AMBIENTMATERIALSOURCE :
4050 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4052 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4054 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4055 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4056 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4057 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4058 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4059 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4061 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4062 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4063 Parm = GL_AMBIENT_AND_DIFFUSE;
4067 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4069 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4071 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4078 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4080 This->tracking_color = NEEDS_TRACKING;
4081 This->tracking_parm = Parm;
4085 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4090 case WINED3DRS_LINEPATTERN :
4096 tmppattern.d = Value;
4098 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4100 if (tmppattern.lp.wRepeatFactor) {
4101 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4102 checkGLcall("glLineStipple(repeat, linepattern)");
4103 glEnable(GL_LINE_STIPPLE);
4104 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4106 glDisable(GL_LINE_STIPPLE);
4107 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4112 case WINED3DRS_ZBIAS : /* D3D8 only */
4116 TRACE("ZBias value %f\n", tmpvalue.f);
4117 glPolygonOffset(0, -tmpvalue.f);
4118 checkGLcall("glPolygonOffset(0, -Value)");
4119 glEnable(GL_POLYGON_OFFSET_FILL);
4120 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4121 glEnable(GL_POLYGON_OFFSET_LINE);
4122 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4123 glEnable(GL_POLYGON_OFFSET_POINT);
4124 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4126 glDisable(GL_POLYGON_OFFSET_FILL);
4127 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4128 glDisable(GL_POLYGON_OFFSET_LINE);
4129 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4130 glDisable(GL_POLYGON_OFFSET_POINT);
4131 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4136 case WINED3DRS_NORMALIZENORMALS :
4138 glEnable(GL_NORMALIZE);
4139 checkGLcall("glEnable(GL_NORMALIZE);");
4141 glDisable(GL_NORMALIZE);
4142 checkGLcall("glDisable(GL_NORMALIZE);");
4146 case WINED3DRS_POINTSIZE :
4147 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4149 TRACE("Set point size to %f\n", tmpvalue.f);
4150 glPointSize(tmpvalue.f);
4151 checkGLcall("glPointSize(...);");
4154 case WINED3DRS_POINTSIZE_MIN :
4155 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4157 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4158 checkGLcall("glPointParameterfEXT(...);");
4160 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4164 case WINED3DRS_POINTSIZE_MAX :
4165 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4167 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4168 checkGLcall("glPointParameterfEXT(...);");
4170 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4174 case WINED3DRS_POINTSCALE_A :
4175 case WINED3DRS_POINTSCALE_B :
4176 case WINED3DRS_POINTSCALE_C :
4177 case WINED3DRS_POINTSCALEENABLE :
4180 * POINTSCALEENABLE controls how point size value is treated. If set to
4181 * true, the point size is scaled with respect to height of viewport.
4182 * When set to false point size is in pixels.
4184 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4187 /* Default values */
4188 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4191 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4192 * This means that OpenGL will clamp really small point sizes to 1.0f.
4193 * To correct for this we need to multiply by the scale factor when sizes
4194 * are less than 1.0f. scale_factor = 1.0f / point_size.
4196 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4197 if(pointSize > 0.0f) {
4198 GLfloat scaleFactor;
4200 if(pointSize < 1.0f) {
4201 scaleFactor = pointSize * pointSize;
4206 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4207 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4208 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4209 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4210 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4211 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4212 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4216 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4217 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4218 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4220 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4221 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4222 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4224 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4228 case WINED3DRS_COLORWRITEENABLE :
4230 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4231 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4232 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4233 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4234 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4235 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4236 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4237 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4238 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4239 checkGLcall("glColorMask(...)");
4243 case WINED3DRS_LOCALVIEWER :
4245 GLint state = (Value) ? 1 : 0;
4246 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4247 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4251 case WINED3DRS_LASTPIXEL :
4254 TRACE("Last Pixel Drawing Enabled\n");
4256 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4261 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4264 TRACE("Software Processing Enabled\n");
4266 TRACE("Software Processing Disabled\n");
4271 /** not supported */
4272 case WINED3DRS_ZVISIBLE :
4275 return WINED3DERR_INVALIDCALL;
4277 case WINED3DRS_POINTSPRITEENABLE :
4279 /* TODO: NV_POINT_SPRITE */
4280 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4281 TRACE("Point sprites not supported\n");
4286 * Point sprites are always enabled. Value controls texture coordinate
4287 * replacement mode. Must be set true for point sprites to use
4290 glEnable(GL_POINT_SPRITE_ARB);
4291 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4294 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4295 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4297 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4298 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4302 case WINED3DRS_EDGEANTIALIAS :
4305 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4307 checkGLcall("glEnable(GL_BLEND)");
4308 glEnable(GL_LINE_SMOOTH);
4309 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4311 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4312 glDisable(GL_BLEND);
4313 checkGLcall("glDisable(GL_BLEND)");
4315 glDisable(GL_LINE_SMOOTH);
4316 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4320 case WINED3DRS_WRAP0 :
4321 case WINED3DRS_WRAP1 :
4322 case WINED3DRS_WRAP2 :
4323 case WINED3DRS_WRAP3 :
4324 case WINED3DRS_WRAP4 :
4325 case WINED3DRS_WRAP5 :
4326 case WINED3DRS_WRAP6 :
4327 case WINED3DRS_WRAP7 :
4328 case WINED3DRS_WRAP8 :
4329 case WINED3DRS_WRAP9 :
4330 case WINED3DRS_WRAP10 :
4331 case WINED3DRS_WRAP11 :
4332 case WINED3DRS_WRAP12 :
4333 case WINED3DRS_WRAP13 :
4334 case WINED3DRS_WRAP14 :
4335 case WINED3DRS_WRAP15 :
4337 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4338 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4339 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4340 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4341 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4343 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4345 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4347 case WINED3DRS_MULTISAMPLEANTIALIAS :
4349 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4350 TRACE("Multisample antialiasing not supported\n");
4355 glEnable(GL_MULTISAMPLE_ARB);
4356 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4358 glDisable(GL_MULTISAMPLE_ARB);
4359 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4363 case WINED3DRS_SCISSORTESTENABLE :
4366 glEnable(GL_SCISSOR_TEST);
4367 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4369 glDisable(GL_SCISSOR_TEST);
4370 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4374 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4378 glEnable(GL_POLYGON_OFFSET_FILL);
4379 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4380 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4381 checkGLcall("glPolygonOffset(...)");
4383 glDisable(GL_POLYGON_OFFSET_FILL);
4384 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4388 case WINED3DRS_ANTIALIASEDLINEENABLE :
4391 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4393 checkGLcall("glEnable(GL_BLEND)");
4394 glEnable(GL_LINE_SMOOTH);
4395 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4397 glDisable(GL_BLEND);
4398 checkGLcall("glDisable(GL_BLEND)");
4399 glDisable(GL_LINE_SMOOTH);
4400 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4404 case WINED3DRS_DEPTHBIAS :
4408 glEnable(GL_POLYGON_OFFSET_FILL);
4409 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4410 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4411 checkGLcall("glPolygonOffset(...)");
4413 glDisable(GL_POLYGON_OFFSET_FILL);
4414 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4419 case WINED3DRS_TEXTUREPERSPECTIVE :
4422 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4424 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4428 case WINED3DRS_STIPPLEDALPHA :
4431 ERR(" Stippled Alpha not supported yet.\n");
4434 case WINED3DRS_ANTIALIAS :
4437 ERR(" Antialias not supported yet.\n");
4441 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4449 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4452 *pValue = This->stateBlock->renderState[State];
4457 * Get / Set Sampler States
4458 * TODO: Verify against dx9 definitions
4461 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4464 * SetSampler is designed to allow for more than the standard up to 8 textures
4465 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4466 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4468 * http://developer.nvidia.com/object/General_FAQ.html#t6
4470 * There are two new settings for GForce
4472 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4473 * and the texture one:
4474 * GL_MAX_TEXTURE_COORDS_ARB.
4475 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4477 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4478 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4479 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4480 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4481 return WINED3DERR_INVALIDCALL;
4484 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4485 debug_d3dsamplerstate(Type), Type, Value);
4486 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4487 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4488 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4490 /* Handle recording of state blocks */
4491 if (This->isRecordingState) {
4492 TRACE("Recording... not performing anything\n");
4499 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4501 /** TODO: check that sampler is in range **/
4502 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4503 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4508 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4512 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4513 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4514 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4520 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 GLint scissorBox[4];
4525 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4526 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4527 pRect->left = scissorBox[0];
4528 pRect->top = scissorBox[1];
4529 pRect->right = scissorBox[0] + scissorBox[2];
4530 pRect->bottom = scissorBox[1] + scissorBox[3];
4531 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4536 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4538 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4540 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4542 This->updateStateBlock->vertexDecl = pDecl;
4543 This->updateStateBlock->changed.vertexDecl = TRUE;
4544 This->updateStateBlock->set.vertexDecl = TRUE;
4546 if (This->isRecordingState) {
4547 TRACE("Recording... not performing anything\n");
4550 if (NULL != pDecl) {
4551 IWineD3DVertexDeclaration_AddRef(pDecl);
4553 if (NULL != oldDecl) {
4554 IWineD3DVertexDeclaration_Release(oldDecl);
4559 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4564 *ppDecl = This->stateBlock->vertexDecl;
4565 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4569 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4571 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4573 This->updateStateBlock->vertexShader = pShader;
4574 This->updateStateBlock->changed.vertexShader = TRUE;
4575 This->updateStateBlock->set.vertexShader = TRUE;
4577 if (This->isRecordingState) {
4578 TRACE("Recording... not performing anything\n");
4581 if (NULL != pShader) {
4582 IWineD3DVertexShader_AddRef(pShader);
4584 if (NULL != oldShader) {
4585 IWineD3DVertexShader_Release(oldShader);
4588 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4590 * TODO: merge HAL shaders context switching from prototype
4595 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 if (NULL == ppShader) {
4599 return WINED3DERR_INVALIDCALL;
4601 *ppShader = This->stateBlock->vertexShader;
4602 if( NULL != *ppShader)
4603 IWineD3DVertexShader_AddRef(*ppShader);
4605 TRACE("(%p) : returning %p\n", This, *ppShader);
4609 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4610 IWineD3DDevice *iface,
4612 CONST BOOL *srcData,
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 int i, cnt = min(count, MAX_CONST_B - start);
4618 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4619 iface, srcData, start, count);
4621 if (srcData == NULL || cnt < 0)
4622 return WINED3DERR_INVALIDCALL;
4624 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4625 for (i = 0; i < cnt; i++)
4626 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4628 for (i = start; i < cnt + start; ++i) {
4629 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4630 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4636 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4637 IWineD3DDevice *iface,
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4643 int cnt = min(count, MAX_CONST_B - start);
4645 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4646 iface, dstData, start, count);
4648 if (dstData == NULL || cnt < 0)
4649 return WINED3DERR_INVALIDCALL;
4651 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4655 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4656 IWineD3DDevice *iface,
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 int i, cnt = min(count, MAX_CONST_I - start);
4664 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4665 iface, srcData, start, count);
4667 if (srcData == NULL || cnt < 0)
4668 return WINED3DERR_INVALIDCALL;
4670 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4671 for (i = 0; i < cnt; i++)
4672 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4673 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4675 for (i = start; i < cnt + start; ++i) {
4676 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4677 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4683 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4684 IWineD3DDevice *iface,
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4690 int cnt = min(count, MAX_CONST_I - start);
4692 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4693 iface, dstData, start, count);
4695 if (dstData == NULL || cnt < 0)
4696 return WINED3DERR_INVALIDCALL;
4698 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4702 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4703 IWineD3DDevice *iface,
4705 CONST float *srcData,
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4709 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4711 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4712 iface, srcData, start, count);
4714 if (srcData == NULL || cnt < 0)
4715 return WINED3DERR_INVALIDCALL;
4717 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4718 for (i = 0; i < cnt; i++)
4719 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4720 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4722 for (i = start; i < cnt + start; ++i) {
4723 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4724 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4731 IWineD3DDevice *iface,
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4739 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4740 iface, dstData, start, count);
4742 if (dstData == NULL || cnt < 0)
4743 return WINED3DERR_INVALIDCALL;
4745 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4749 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4752 This->updateStateBlock->pixelShader = pShader;
4753 This->updateStateBlock->changed.pixelShader = TRUE;
4754 This->updateStateBlock->set.pixelShader = TRUE;
4756 /* Handle recording of state blocks */
4757 if (This->isRecordingState) {
4758 TRACE("Recording... not performing anything\n");
4761 if (NULL != pShader) {
4762 IWineD3DPixelShader_AddRef(pShader);
4764 if (NULL != oldShader) {
4765 IWineD3DPixelShader_Release(oldShader);
4768 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4770 * TODO: merge HAL shaders context switching from prototype
4775 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 if (NULL == ppShader) {
4779 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4780 return WINED3DERR_INVALIDCALL;
4783 *ppShader = This->stateBlock->pixelShader;
4784 if (NULL != *ppShader) {
4785 IWineD3DPixelShader_AddRef(*ppShader);
4787 TRACE("(%p) : returning %p\n", This, *ppShader);
4791 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4792 IWineD3DDevice *iface,
4794 CONST BOOL *srcData,
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 int i, cnt = min(count, MAX_CONST_B - start);
4800 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4801 iface, srcData, start, count);
4803 if (srcData == NULL || cnt < 0)
4804 return WINED3DERR_INVALIDCALL;
4806 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4807 for (i = 0; i < cnt; i++)
4808 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4810 for (i = start; i < cnt + start; ++i) {
4811 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4812 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4818 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4819 IWineD3DDevice *iface,
4824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 int cnt = min(count, MAX_CONST_B - start);
4827 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4828 iface, dstData, start, count);
4830 if (dstData == NULL || cnt < 0)
4831 return WINED3DERR_INVALIDCALL;
4833 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4837 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4838 IWineD3DDevice *iface,
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4844 int i, cnt = min(count, MAX_CONST_I - start);
4846 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4847 iface, srcData, start, count);
4849 if (srcData == NULL || cnt < 0)
4850 return WINED3DERR_INVALIDCALL;
4852 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4853 for (i = 0; i < cnt; i++)
4854 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4855 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4857 for (i = start; i < cnt + start; ++i) {
4858 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4859 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4866 IWineD3DDevice *iface,
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4872 int cnt = min(count, MAX_CONST_I - start);
4874 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4875 iface, dstData, start, count);
4877 if (dstData == NULL || cnt < 0)
4878 return WINED3DERR_INVALIDCALL;
4880 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4884 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4885 IWineD3DDevice *iface,
4887 CONST float *srcData,
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4893 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4894 iface, srcData, start, count);
4896 if (srcData == NULL || cnt < 0)
4897 return WINED3DERR_INVALIDCALL;
4899 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4900 for (i = 0; i < cnt; i++)
4901 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4902 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4904 for (i = start; i < cnt + start; ++i) {
4905 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4906 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4912 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4913 IWineD3DDevice *iface,
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4921 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4922 iface, dstData, start, count);
4924 if (dstData == NULL || cnt < 0)
4925 return WINED3DERR_INVALIDCALL;
4927 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4931 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4933 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4934 char *dest_ptr, *dest_conv = NULL;
4936 DWORD DestFVF = dest->fvf;
4938 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4942 if (SrcFVF & D3DFVF_NORMAL) {
4943 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4946 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4947 ERR("Source has no position mask\n");
4948 return WINED3DERR_INVALIDCALL;
4951 /* We might access VBOs from this code, so hold the lock */
4954 if (dest->resource.allocatedMemory == NULL) {
4955 /* This may happen if we do direct locking into a vbo. Unlikely,
4956 * but theoretically possible(ddraw processvertices test)
4958 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4959 if(!dest->resource.allocatedMemory) {
4961 ERR("Out of memory\n");
4962 return E_OUTOFMEMORY;
4966 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4967 checkGLcall("glBindBufferARB");
4968 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4970 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4972 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4973 checkGLcall("glUnmapBufferARB");
4977 /* Get a pointer into the destination vbo(create one if none exists) and
4978 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4980 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4985 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4986 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4988 ERR("glMapBuffer failed\n");
4989 /* Continue without storing converted vertices */
4994 * a) D3DRS_CLIPPING is enabled
4995 * b) WINED3DVOP_CLIP is passed
4997 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4998 static BOOL warned = FALSE;
5000 * The clipping code is not quite correct. Some things need
5001 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5002 * so disable clipping for now.
5003 * (The graphics in Half-Life are broken, and my processvertices
5004 * test crashes with IDirect3DDevice3)
5010 FIXME("Clipping is broken and disabled for now\n");
5012 } else doClip = FALSE;
5013 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5015 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5018 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5021 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5024 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5025 D3DTS_WORLDMATRIX(0),
5028 TRACE("View mat:\n");
5029 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); \
5030 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); \
5031 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); \
5032 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); \
5034 TRACE("Proj mat:\n");
5035 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); \
5036 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); \
5037 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); \
5038 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); \
5040 TRACE("World mat:\n");
5041 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); \
5042 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); \
5043 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); \
5044 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); \
5046 /* Get the viewport */
5047 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5048 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5049 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5051 multiply_matrix(&mat,&view_mat,&world_mat);
5052 multiply_matrix(&mat,&proj_mat,&mat);
5054 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5056 for (i = 0; i < dwCount; i+= 1) {
5057 unsigned int tex_index;
5059 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5060 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5061 /* The position first */
5063 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5065 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5067 /* Multiplication with world, view and projection matrix */
5068 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);
5069 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);
5070 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);
5071 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);
5073 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5075 /* WARNING: The following things are taken from d3d7 and were not yet checked
5076 * against d3d8 or d3d9!
5079 /* Clipping conditions: From
5080 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5082 * A vertex is clipped if it does not match the following requirements
5086 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5088 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5089 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5093 if( doClip == FALSE ||
5094 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5095 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5098 /* "Normal" viewport transformation (not clipped)
5099 * 1) The values are divided by rhw
5100 * 2) The y axis is negative, so multiply it with -1
5101 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5102 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5103 * 4) Multiply x with Width/2 and add Width/2
5104 * 5) The same for the height
5105 * 6) Add the viewpoint X and Y to the 2D coordinates and
5106 * The minimum Z value to z
5107 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5109 * Well, basically it's simply a linear transformation into viewport
5121 z *= vp.MaxZ - vp.MinZ;
5123 x += vp.Width / 2 + vp.X;
5124 y += vp.Height / 2 + vp.Y;
5129 /* That vertex got clipped
5130 * Contrary to OpenGL it is not dropped completely, it just
5131 * undergoes a different calculation.
5133 TRACE("Vertex got clipped\n");
5140 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5141 * outside of the main vertex buffer memory. That needs some more
5146 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5149 ( (float *) dest_ptr)[0] = x;
5150 ( (float *) dest_ptr)[1] = y;
5151 ( (float *) dest_ptr)[2] = z;
5152 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5154 dest_ptr += 3 * sizeof(float);
5156 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5157 dest_ptr += sizeof(float);
5162 ( (float *) dest_conv)[0] = x * w;
5163 ( (float *) dest_conv)[1] = y * w;
5164 ( (float *) dest_conv)[2] = z * w;
5165 ( (float *) dest_conv)[3] = w;
5167 dest_conv += 3 * sizeof(float);
5169 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5170 dest_conv += sizeof(float);
5174 if (DestFVF & D3DFVF_PSIZE) {
5175 dest_ptr += sizeof(DWORD);
5176 if(dest_conv) dest_conv += sizeof(DWORD);
5178 if (DestFVF & D3DFVF_NORMAL) {
5180 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5181 /* AFAIK this should go into the lighting information */
5182 FIXME("Didn't expect the destination to have a normal\n");
5183 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5185 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5189 if (DestFVF & D3DFVF_DIFFUSE) {
5191 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5193 static BOOL warned = FALSE;
5195 if(warned == FALSE) {
5196 ERR("No diffuse color in source, but destination has one\n");
5200 *( (DWORD *) dest_ptr) = 0xffffffff;
5201 dest_ptr += sizeof(DWORD);
5204 *( (DWORD *) dest_conv) = 0xffffffff;
5205 dest_conv += sizeof(DWORD);
5209 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5211 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5212 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5213 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5214 dest_conv += sizeof(DWORD);
5219 if (DestFVF & D3DFVF_SPECULAR) {
5220 /* What's the color value in the feedback buffer? */
5222 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5224 static BOOL warned = FALSE;
5226 if(warned == FALSE) {
5227 ERR("No specular color in source, but destination has one\n");
5231 *( (DWORD *) dest_ptr) = 0xFF000000;
5232 dest_ptr += sizeof(DWORD);
5235 *( (DWORD *) dest_conv) = 0xFF000000;
5236 dest_conv += sizeof(DWORD);
5240 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5242 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5243 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5244 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5245 dest_conv += sizeof(DWORD);
5250 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5252 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5253 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5255 ERR("No source texture, but destination requests one\n");
5256 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5257 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5260 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5262 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5269 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5270 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5277 #undef copy_and_next
5279 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5281 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5282 WineDirect3DVertexStridedData strided;
5283 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5285 /* We don't need the source vbo because this buffer is only used as
5286 * a source for ProcessVertices. Avoid wasting resources by converting the
5287 * buffer and loading the VBO
5290 TRACE("Releaseing the source vbo, it won't be needed\n");
5292 if(!SrcImpl->resource.allocatedMemory) {
5293 /* Rescue the data from the buffer */
5295 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5296 if(!SrcImpl->resource.allocatedMemory) {
5297 ERR("Out of memory\n");
5298 return E_OUTOFMEMORY;
5302 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5303 checkGLcall("glBindBufferARB");
5305 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5307 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5310 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5311 checkGLcall("glUnmapBufferARB");
5316 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5317 checkGLcall("glBindBufferARB");
5318 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5319 checkGLcall("glDeleteBuffersARB");
5325 memset(&strided, 0, sizeof(strided));
5326 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5328 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5332 * Apply / Get / Set Texture Stage States
5333 * TODO: Verify against dx9 definitions
5336 /* 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 */
5337 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5340 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5342 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5344 /* Check that the stage is within limits */
5345 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5346 TRACE("Attempt to access invalid texture rejected\n");
5353 case WINED3DTSS_ALPHAOP :
5354 case WINED3DTSS_COLOROP :
5355 /* nothing to do as moved to drawprim for now */
5357 case WINED3DTSS_ADDRESSW :
5358 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5359 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5360 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5363 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5364 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5365 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5366 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5369 case WINED3DTSS_TEXCOORDINDEX :
5371 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5373 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5374 one flag, you can still specify an index value, which the system uses to
5375 determine the texture wrapping mode.
5376 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5377 means use the vertex position (camera-space) as the input texture coordinates
5378 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5379 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5380 to the TEXCOORDINDEX value */
5383 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5385 switch (Value & 0xFFFF0000) {
5386 case D3DTSS_TCI_PASSTHRU:
5387 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5388 glDisable(GL_TEXTURE_GEN_S);
5389 glDisable(GL_TEXTURE_GEN_T);
5390 glDisable(GL_TEXTURE_GEN_R);
5391 glDisable(GL_TEXTURE_GEN_Q);
5392 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5395 case D3DTSS_TCI_CAMERASPACEPOSITION:
5396 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5397 as the input texture coordinates for this stage's texture transformation. This
5398 equates roughly to EYE_LINEAR */
5400 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5401 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5402 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5403 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5404 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5406 glMatrixMode(GL_MODELVIEW);
5409 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5410 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5411 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5412 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5415 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5416 glEnable(GL_TEXTURE_GEN_S);
5417 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5418 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5419 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5420 glEnable(GL_TEXTURE_GEN_T);
5421 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5422 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5423 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5424 glEnable(GL_TEXTURE_GEN_R);
5425 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5426 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5427 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5431 case D3DTSS_TCI_CAMERASPACENORMAL:
5433 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5434 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5435 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5436 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5437 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5438 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5440 glMatrixMode(GL_MODELVIEW);
5443 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5444 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5445 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5446 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5449 glEnable(GL_TEXTURE_GEN_S);
5450 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5451 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5452 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5453 glEnable(GL_TEXTURE_GEN_T);
5454 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5455 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5456 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5457 glEnable(GL_TEXTURE_GEN_R);
5458 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5459 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5460 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5465 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5467 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5468 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5469 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5470 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5471 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5472 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5474 glMatrixMode(GL_MODELVIEW);
5477 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5478 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5479 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5480 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5483 glEnable(GL_TEXTURE_GEN_S);
5484 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5485 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5486 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5487 glEnable(GL_TEXTURE_GEN_T);
5488 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5489 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5490 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5491 glEnable(GL_TEXTURE_GEN_R);
5492 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5493 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5494 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5499 /* Unhandled types: */
5502 /* ? disable GL_TEXTURE_GEN_n ? */
5503 glDisable(GL_TEXTURE_GEN_S);
5504 glDisable(GL_TEXTURE_GEN_T);
5505 glDisable(GL_TEXTURE_GEN_R);
5506 glDisable(GL_TEXTURE_GEN_Q);
5507 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5514 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5515 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);
5518 case WINED3DTSS_BUMPENVMAT00 :
5519 case WINED3DTSS_BUMPENVMAT01 :
5520 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5522 case WINED3DTSS_BUMPENVMAT10 :
5523 case WINED3DTSS_BUMPENVMAT11 :
5524 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5527 case WINED3DTSS_BUMPENVLSCALE :
5528 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5531 case WINED3DTSS_BUMPENVLOFFSET :
5532 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5535 case WINED3DTSS_RESULTARG :
5536 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5540 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5541 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5550 * Get / Set Texture Stage States
5551 * TODO: Verify against dx9 definitions
5553 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5556 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5558 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5560 /* Reject invalid texture units */
5561 if (Stage >= GL_LIMITS(texture_stages)) {
5562 TRACE("Attempt to access invalid texture rejected\n");
5563 return WINED3DERR_INVALIDCALL;
5566 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5567 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5568 This->updateStateBlock->textureState[Stage][Type] = Value;
5573 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5576 *pValue = This->updateStateBlock->textureState[Stage][Type];
5583 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5586 IWineD3DBaseTexture *oldTexture;
5588 oldTexture = This->updateStateBlock->textures[Stage];
5589 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5591 #if 0 /* TODO: check so vertex textures */
5592 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5593 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5598 /* Reject invalid texture units */
5599 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5600 WARN("Attempt to access invalid texture rejected\n");
5601 return WINED3DERR_INVALIDCALL;
5604 if(pTexture != NULL) {
5605 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5607 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5608 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5609 return WINED3DERR_INVALIDCALL;
5613 oldTexture = This->updateStateBlock->textures[Stage];
5614 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5615 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5617 This->updateStateBlock->set.textures[Stage] = TRUE;
5618 This->updateStateBlock->changed.textures[Stage] = TRUE;
5619 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5620 This->updateStateBlock->textures[Stage] = pTexture;
5622 /* Handle recording of state blocks */
5623 if (This->isRecordingState) {
5624 TRACE("Recording... not performing anything\n");
5628 /** NOTE: MSDN says that setTexture increases the reference count,
5629 * and the the application nust set the texture back to null (or have a leaky application),
5630 * This means we should pass the refcount up to the parent
5631 *******************************/
5632 if (NULL != This->updateStateBlock->textures[Stage]) {
5633 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5636 if (NULL != oldTexture) {
5637 IWineD3DBaseTexture_Release(oldTexture);
5640 /* Reset color keying */
5641 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5642 BOOL enable_ckey = FALSE;
5645 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5646 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5650 glAlphaFunc(GL_NOTEQUAL, 0.0);
5651 checkGLcall("glAlphaFunc");
5658 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5660 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5662 /* Reject invalid texture units */
5663 if (Stage >= GL_LIMITS(sampler_stages)) {
5664 TRACE("Attempt to access invalid texture rejected\n");
5665 return WINED3DERR_INVALIDCALL;
5667 *ppTexture=This->updateStateBlock->textures[Stage];
5669 IWineD3DBaseTexture_AddRef(*ppTexture);
5671 return WINED3DERR_INVALIDCALL;
5678 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5679 IWineD3DSurface **ppBackBuffer) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 IWineD3DSwapChain *swapChain;
5684 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5686 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5687 if (hr == WINED3D_OK) {
5688 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5689 IWineD3DSwapChain_Release(swapChain);
5691 *ppBackBuffer = NULL;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 WARN("(%p) : stub, calling idirect3d for now\n", This);
5699 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5702 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 IWineD3DSwapChain *swapChain;
5707 if(iSwapChain > 0) {
5708 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5709 if (hr == WINED3D_OK) {
5710 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5711 IWineD3DSwapChain_Release(swapChain);
5713 FIXME("(%p) Error getting display mode\n", This);
5716 /* Don't read the real display mode,
5717 but return the stored mode instead. X11 can't change the color
5718 depth, and some apps are pretty angry if they SetDisplayMode from
5719 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5721 Also don't relay to the swapchain because with ddraw it's possible
5722 that there isn't a swapchain at all */
5723 pMode->Width = This->ddraw_width;
5724 pMode->Height = This->ddraw_height;
5725 pMode->Format = This->ddraw_format;
5726 pMode->RefreshRate = 0;
5733 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5735 TRACE("(%p)->(%p)\n", This, hWnd);
5737 This->ddraw_window = hWnd;
5741 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5743 TRACE("(%p)->(%p)\n", This, hWnd);
5745 *hWnd = This->ddraw_window;
5750 * Stateblock related functions
5753 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5755 IWineD3DStateBlockImpl *object;
5756 HRESULT temp_result;
5758 TRACE("(%p)", This);
5760 if (This->isRecordingState) {
5761 return WINED3DERR_INVALIDCALL;
5764 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5765 if (NULL == object ) {
5766 FIXME("(%p)Error allocating memory for stateblock\n", This);
5767 return E_OUTOFMEMORY;
5769 TRACE("(%p) created object %p\n", This, object);
5770 object->wineD3DDevice= This;
5771 /** FIXME: object->parent = parent; **/
5772 object->parent = NULL;
5773 object->blockType = WINED3DSBT_ALL;
5775 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5777 temp_result = allocate_shader_constants(object);
5778 if (WINED3D_OK != temp_result)
5781 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5782 This->updateStateBlock = object;
5783 This->isRecordingState = TRUE;
5785 TRACE("(%p) recording stateblock %p\n",This , object);
5789 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5792 if (!This->isRecordingState) {
5793 FIXME("(%p) not recording! returning error\n", This);
5794 *ppStateBlock = NULL;
5795 return WINED3DERR_INVALIDCALL;
5798 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5799 This->isRecordingState = FALSE;
5800 This->updateStateBlock = This->stateBlock;
5801 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5802 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5803 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5808 * Scene related functions
5810 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5811 /* At the moment we have no need for any functionality at the beginning
5813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5814 TRACE("(%p) : stub\n", This);
5818 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5820 TRACE("(%p)\n", This);
5822 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5824 checkGLcall("glFlush");
5826 TRACE("End Scene\n");
5827 if(This->renderTarget != NULL) {
5829 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5830 IUnknown *targetContainer = NULL;
5831 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5832 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5833 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5834 /** always dirtify for now. we must find a better way to see that surface have been modified
5835 (Modifications should will only occur via draw-primitive, but we do need better locking
5836 switching to render-to-texture should remove the overhead though.
5838 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5839 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5840 IWineD3DSurface_PreLoad(This->renderTarget);
5841 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5842 IUnknown_Release(targetContainer);
5845 This->sceneEnded = TRUE;
5850 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5851 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5852 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 IWineD3DSwapChain *swapChain = NULL;
5856 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5858 TRACE("(%p) Presenting the frame\n", This);
5860 for(i = 0 ; i < swapchains ; i ++) {
5862 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5863 TRACE("presentinng chain %d, %p\n", i, swapChain);
5864 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5865 IWineD3DSwapChain_Release(swapChain);
5871 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5872 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5875 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5876 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5877 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5878 GLbitfield glMask = 0;
5879 GLboolean old_ztest;
5880 GLfloat old_z_clear_value;
5881 GLint old_stencil_clear_value;
5882 GLfloat old_color_clear_value[4];
5884 CONST D3DRECT* curRect;
5886 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5887 Count, pRects, Flags, Z, Stencil);
5891 glEnable(GL_SCISSOR_TEST);
5892 checkGLcall("glEnable GL_SCISSOR_TEST");
5894 if (Count > 0 && pRects) {
5900 /* Only set the values up once, as they are not changing */
5901 if (Flags & D3DCLEAR_STENCIL) {
5902 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5903 glClearStencil(Stencil);
5904 checkGLcall("glClearStencil");
5905 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5906 glStencilMask(0xFFFFFFFF);
5909 if (Flags & D3DCLEAR_ZBUFFER) {
5910 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5911 glDepthMask(GL_TRUE);
5912 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5914 checkGLcall("glClearDepth");
5915 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5918 if (Flags & D3DCLEAR_TARGET) {
5919 TRACE("Clearing screen with glClear to color %lx\n", Color);
5920 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5921 glClearColor(D3DCOLOR_R(Color),
5925 checkGLcall("glClearColor");
5927 /* Clear ALL colors! */
5928 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5929 glMask = glMask | GL_COLOR_BUFFER_BIT;
5932 /* Now process each rect in turn */
5933 for (i = 0; i < Count || i == 0; i++) {
5936 /* Note gl uses lower left, width/height */
5937 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5938 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5939 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5940 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5941 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5942 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5943 checkGLcall("glScissor");
5945 glScissor(This->stateBlock->viewport.X,
5946 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5947 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5948 This->stateBlock->viewport.Width,
5949 This->stateBlock->viewport.Height);
5950 checkGLcall("glScissor");
5953 /* Clear the selected rectangle (or full screen) */
5955 checkGLcall("glClear");
5957 /* Step to the next rectangle */
5958 if (curRect) curRect = curRect + sizeof(D3DRECT);
5961 /* Restore the old values (why..?) */
5962 if (Flags & D3DCLEAR_STENCIL) {
5963 glClearStencil(old_stencil_clear_value);
5964 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5966 if (Flags & D3DCLEAR_ZBUFFER) {
5967 glDepthMask(old_ztest);
5968 glClearDepth(old_z_clear_value);
5970 if (Flags & D3DCLEAR_TARGET) {
5971 glClearColor(old_color_clear_value[0],
5972 old_color_clear_value[1],
5973 old_color_clear_value[2],
5974 old_color_clear_value[3]);
5975 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5976 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5977 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5978 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5981 glDisable(GL_SCISSOR_TEST);
5982 checkGLcall("glDisable");
5991 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5992 UINT PrimitiveCount) {
5994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5995 This->stateBlock->streamIsUP = FALSE;
5997 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5998 debug_d3dprimitivetype(PrimitiveType),
5999 StartVertex, PrimitiveCount);
6000 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6001 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6007 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6008 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6009 D3DPRIMITIVETYPE PrimitiveType,
6010 INT baseVIndex, UINT minIndex,
6011 UINT NumVertices, UINT startIndex, UINT primCount) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6015 IWineD3DIndexBuffer *pIB;
6016 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6018 pIB = This->stateBlock->pIndexData;
6019 This->stateBlock->streamIsUP = FALSE;
6021 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6022 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6023 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6025 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6026 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6032 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6033 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6038 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6039 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6040 UINT VertexStreamZeroStride) {
6041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6043 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6044 debug_d3dprimitivetype(PrimitiveType),
6045 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6047 /* release the stream source */
6048 if (This->stateBlock->streamSource[0] != NULL) {
6049 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6052 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6053 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6054 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6055 This->stateBlock->streamIsUP = TRUE;
6057 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6058 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6060 /* MSDN specifies stream zero settings must be set to NULL */
6061 This->stateBlock->streamStride[0] = 0;
6062 This->stateBlock->streamSource[0] = NULL;
6064 /*stream zero settings set to null at end, as per the msdn */
6068 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6069 UINT MinVertexIndex, UINT NumVertices,
6070 UINT PrimitiveCount, CONST void* pIndexData,
6071 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6072 UINT VertexStreamZeroStride) {
6074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6076 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6077 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6078 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6079 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6081 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6087 /* release the stream and index data */
6088 if (This->stateBlock->streamSource[0] != NULL) {
6089 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6091 if (This->stateBlock->pIndexData) {
6092 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6095 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6096 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6097 This->stateBlock->streamIsUP = TRUE;
6098 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6100 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6102 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6103 This->stateBlock->streamSource[0] = NULL;
6104 This->stateBlock->streamStride[0] = 0;
6105 This->stateBlock->pIndexData = NULL;
6110 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6112 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6115 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6116 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6118 HRESULT hr = WINED3D_OK;
6119 WINED3DRESOURCETYPE sourceType;
6120 WINED3DRESOURCETYPE destinationType;
6123 /* TODO: think about moving the code into IWineD3DBaseTexture */
6125 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6127 /* verify that the source and destination textures aren't NULL */
6128 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6129 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6130 This, pSourceTexture, pDestinationTexture);
6131 hr = WINED3DERR_INVALIDCALL;
6134 if (pSourceTexture == pDestinationTexture) {
6135 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6136 This, pSourceTexture, pDestinationTexture);
6137 hr = WINED3DERR_INVALIDCALL;
6139 /* Verify that the source and destination textures are the same type */
6140 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6141 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6143 if (sourceType != destinationType) {
6144 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6146 hr = WINED3DERR_INVALIDCALL;
6149 /* check that both textures have the identical numbers of levels */
6150 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6151 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6152 hr = WINED3DERR_INVALIDCALL;
6155 if (WINED3D_OK == hr) {
6157 /* Make sure that the destination texture is loaded */
6158 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6160 /* Update every surface level of the texture */
6161 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6163 switch (sourceType) {
6164 case WINED3DRTYPE_TEXTURE:
6166 IWineD3DSurface *srcSurface;
6167 IWineD3DSurface *destSurface;
6169 for (i = 0 ; i < levels ; ++i) {
6170 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6171 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6172 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6173 IWineD3DSurface_Release(srcSurface);
6174 IWineD3DSurface_Release(destSurface);
6175 if (WINED3D_OK != hr) {
6176 WARN("(%p) : Call to update surface failed\n", This);
6182 case WINED3DRTYPE_CUBETEXTURE:
6184 IWineD3DSurface *srcSurface;
6185 IWineD3DSurface *destSurface;
6186 WINED3DCUBEMAP_FACES faceType;
6188 for (i = 0 ; i < levels ; ++i) {
6189 /* Update each cube face */
6190 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6191 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6192 if (WINED3D_OK != hr) {
6193 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6195 TRACE("Got srcSurface %p\n", srcSurface);
6197 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6198 if (WINED3D_OK != hr) {
6199 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6201 TRACE("Got desrSurface %p\n", destSurface);
6203 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6204 IWineD3DSurface_Release(srcSurface);
6205 IWineD3DSurface_Release(destSurface);
6206 if (WINED3D_OK != hr) {
6207 WARN("(%p) : Call to update surface failed\n", This);
6214 #if 0 /* TODO: Add support for volume textures */
6215 case WINED3DRTYPE_VOLUMETEXTURE:
6217 IWineD3DVolume srcVolume = NULL;
6218 IWineD3DSurface destVolume = NULL;
6220 for (i = 0 ; i < levels ; ++i) {
6221 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6222 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6223 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6224 IWineD3DVolume_Release(srcSurface);
6225 IWineD3DVolume_Release(destSurface);
6226 if (WINED3D_OK != hr) {
6227 WARN("(%p) : Call to update volume failed\n", This);
6235 FIXME("(%p) : Unsupported source and destination type\n", This);
6236 hr = WINED3DERR_INVALIDCALL;
6243 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6244 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6245 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6248 TRACE("(%p) : stub\n", This);
6251 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6253 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6254 * NOTE It may be best to move the code into surface to occomplish this
6255 ****************************************/
6257 WINED3DSURFACE_DESC surfaceDesc;
6258 unsigned int surfaceWidth, surfaceHeight;
6259 glDescriptor *targetGlDescription = NULL;
6260 glDescriptor *surfaceGlDescription = NULL;
6261 IWineD3DSwapChainImpl *container = NULL;
6263 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6264 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6265 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6267 surfaceDesc.Width = &surfaceWidth;
6268 surfaceDesc.Height = &surfaceHeight;
6269 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6270 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6272 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6273 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6275 /* TODO: opengl Context switching for swapchains etc... */
6276 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6277 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6278 glReadBuffer(GL_BACK);
6279 vcheckGLcall("glReadBuffer(GL_BACK)");
6280 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6281 glReadBuffer(GL_FRONT);
6282 vcheckGLcall("glReadBuffer(GL_FRONT)");
6283 } else if (pRenderTarget == This->depthStencilBuffer) {
6284 FIXME("Reading of depthstencil not yet supported\n");
6287 glReadPixels(surfaceGlDescription->target,
6288 surfaceGlDescription->level,
6291 surfaceGlDescription->glFormat,
6292 surfaceGlDescription->glType,
6293 (void *)IWineD3DSurface_GetData(pSurface));
6294 vcheckGLcall("glReadPixels(...)");
6295 if(NULL != container ){
6296 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6299 IWineD3DBaseTexture *container;
6300 GLenum textureDimensions = GL_TEXTURE_2D;
6302 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6303 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6304 IWineD3DBaseTexture_Release(container);
6306 /* TODO: 2D -> Cube surface coppies etc.. */
6307 if (surfaceGlDescription->target != textureDimensions) {
6308 FIXME("(%p) : Texture dimension mismatch\n", This);
6310 glEnable(textureDimensions);
6311 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6312 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6313 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6314 vcheckGLcall("glBindTexture");
6315 glGetTexImage(surfaceGlDescription->target,
6316 surfaceGlDescription->level,
6317 surfaceGlDescription->glFormat,
6318 surfaceGlDescription->glType,
6319 (void *)IWineD3DSurface_GetData(pSurface));
6320 glDisable(textureDimensions);
6321 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6328 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6329 IWineD3DSwapChain *swapChain;
6331 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6332 if(hr == WINED3D_OK) {
6333 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6334 IWineD3DSwapChain_Release(swapChain);
6339 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6341 /* return a sensible default */
6343 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6344 FIXME("(%p) : stub\n", This);
6348 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6351 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6352 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6353 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6354 return WINED3DERR_INVALIDCALL;
6356 for (j = 0; j < 256; ++j) {
6357 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6358 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6359 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6360 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6362 TRACE("(%p) : returning\n", This);
6366 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6369 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6370 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6371 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6372 return WINED3DERR_INVALIDCALL;
6374 for (j = 0; j < 256; ++j) {
6375 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6376 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6377 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6378 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6380 TRACE("(%p) : returning\n", This);
6384 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6387 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6388 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6389 return WINED3DERR_INVALIDCALL;
6391 /*TODO: stateblocks */
6392 This->currentPalette = PaletteNumber;
6393 TRACE("(%p) : returning\n", This);
6397 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6399 if (PaletteNumber == NULL) {
6400 WARN("(%p) : returning Invalid Call\n", This);
6401 return WINED3DERR_INVALIDCALL;
6403 /*TODO: stateblocks */
6404 *PaletteNumber = This->currentPalette;
6405 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6409 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6411 static BOOL showFixmes = TRUE;
6413 FIXME("(%p) : stub\n", This);
6417 This->softwareVertexProcessing = bSoftware;
6422 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6424 static BOOL showFixmes = TRUE;
6426 FIXME("(%p) : stub\n", This);
6429 return This->softwareVertexProcessing;
6433 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6435 IWineD3DSwapChain *swapChain;
6438 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6440 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6441 if(hr == WINED3D_OK){
6442 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6443 IWineD3DSwapChain_Release(swapChain);
6445 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6451 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6453 static BOOL showfixmes = TRUE;
6454 if(nSegments != 0.0f) {
6456 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6463 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6465 static BOOL showfixmes = TRUE;
6467 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6473 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6475 /** TODO: remove casts to IWineD3DSurfaceImpl
6476 * NOTE: move code to surface to accomplish this
6477 ****************************************/
6478 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6479 int srcWidth, srcHeight;
6480 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6481 WINED3DFORMAT destFormat, srcFormat;
6483 int destLeft, destTop;
6484 WINED3DPOOL srcPool, destPool;
6486 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6487 glDescriptor *glDescription = NULL;
6488 GLenum textureDimensions = GL_TEXTURE_2D;
6489 IWineD3DBaseTexture *baseTexture;
6491 WINED3DSURFACE_DESC winedesc;
6493 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6494 memset(&winedesc, 0, sizeof(winedesc));
6495 winedesc.Width = &srcSurfaceWidth;
6496 winedesc.Height = &srcSurfaceHeight;
6497 winedesc.Pool = &srcPool;
6498 winedesc.Format = &srcFormat;
6500 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6502 winedesc.Width = &destSurfaceWidth;
6503 winedesc.Height = &destSurfaceHeight;
6504 winedesc.Pool = &destPool;
6505 winedesc.Format = &destFormat;
6506 winedesc.Size = &destSize;
6508 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6510 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6511 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6512 return WINED3DERR_INVALIDCALL;
6515 if (destFormat == WINED3DFMT_UNKNOWN) {
6516 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6517 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6519 /* Get the update surface description */
6520 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6523 /* Make sure the surface is loaded and up to date */
6524 IWineD3DSurface_PreLoad(pDestinationSurface);
6526 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6530 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6531 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6532 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6533 destLeft = pDestPoint ? pDestPoint->x : 0;
6534 destTop = pDestPoint ? pDestPoint->y : 0;
6537 /* This function doesn't support compressed textures
6538 the pitch is just bytesPerPixel * width */
6539 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6540 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6541 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6542 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6544 /* TODO DXT formats */
6546 if(pSourceRect != NULL && pSourceRect->top != 0){
6547 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6549 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6551 ,glDescription->level
6556 ,glDescription->glFormat
6557 ,glDescription->glType
6558 ,IWineD3DSurface_GetData(pSourceSurface)
6562 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6564 /* need to lock the surface to get the data */
6565 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6568 /* TODO: Cube and volume support */
6570 /* not a whole row so we have to do it a line at a time */
6573 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6574 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6576 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6578 glTexSubImage2D(glDescription->target
6579 ,glDescription->level
6584 ,glDescription->glFormat
6585 ,glDescription->glType
6586 ,data /* could be quicker using */
6591 } else { /* Full width, so just write out the whole texture */
6593 if (WINED3DFMT_DXT1 == destFormat ||
6594 WINED3DFMT_DXT2 == destFormat ||
6595 WINED3DFMT_DXT3 == destFormat ||
6596 WINED3DFMT_DXT4 == destFormat ||
6597 WINED3DFMT_DXT5 == destFormat) {
6598 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6599 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6600 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6601 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6602 } if (destFormat != srcFormat) {
6603 FIXME("Updating mixed format compressed texture is not curretly support\n");
6605 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6606 glDescription->level,
6607 glDescription->glFormatInternal,
6612 IWineD3DSurface_GetData(pSourceSurface));
6615 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6620 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6622 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6623 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6624 data returned by GetData non-power2 width/height with hardware non-power2
6625 pow2Width/height are set to surface width height, repacking isn't needed so it
6626 doesn't matter which function gets called. */
6627 glTexSubImage2D(glDescription->target
6628 ,glDescription->level
6633 ,glDescription->glFormat
6634 ,glDescription->glType
6635 ,IWineD3DSurface_GetData(pSourceSurface)
6639 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6640 glTexSubImage2D(glDescription->target
6641 ,glDescription->level
6644 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6645 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6646 ,glDescription->glFormat
6647 ,glDescription->glType
6648 ,IWineD3DSurface_GetData(pSourceSurface)
6654 checkGLcall("glTexSubImage2D");
6656 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6657 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6658 * surface bigger than it needs to be hmm.. */
6659 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6660 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6661 IWineD3DBaseTexture_Release(baseTexture);
6664 glDisable(textureDimensions); /* This needs to be managed better.... */
6670 /* Used by DirectX 8 */
6671 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6672 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6673 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6676 HRESULT hr = WINED3D_OK;
6677 WINED3DFORMAT srcFormat, destFormat;
6678 UINT srcWidth, destWidth;
6679 UINT srcHeight, destHeight;
6681 WINED3DSURFACE_DESC winedesc;
6683 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6684 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6687 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6688 memset(&winedesc, 0, sizeof(winedesc));
6690 winedesc.Format = &srcFormat;
6691 winedesc.Width = &srcWidth;
6692 winedesc.Height = &srcHeight;
6693 winedesc.Size = &srcSize;
6694 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6696 winedesc.Format = &destFormat;
6697 winedesc.Width = &destWidth;
6698 winedesc.Height = &destHeight;
6699 winedesc.Size = NULL;
6700 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6702 /* Check that the source and destination formats match */
6703 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6704 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6705 return WINED3DERR_INVALIDCALL;
6706 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6707 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6708 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6709 destFormat = srcFormat;
6712 /* Quick if complete copy ... */
6713 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6715 if (srcWidth == destWidth && srcHeight == destHeight) {
6716 WINED3DLOCKED_RECT lrSrc;
6717 WINED3DLOCKED_RECT lrDst;
6718 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6719 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6720 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6722 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6724 IWineD3DSurface_UnlockRect(pSourceSurface);
6725 IWineD3DSurface_UnlockRect(pDestinationSurface);
6726 TRACE("Unlocked src and dst\n");
6730 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6731 hr = WINED3DERR_INVALIDCALL;
6736 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6738 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6741 /* Copy rect by rect */
6742 for (i = 0; i < cRects; ++i) {
6743 CONST RECT* r = &pSourceRectsArray[i];
6744 CONST POINT* p = &pDestPointsArray[i];
6747 WINED3DLOCKED_RECT lrSrc;
6748 WINED3DLOCKED_RECT lrDst;
6751 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6752 if (srcFormat == WINED3DFMT_DXT1) {
6753 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6755 copyperline = ((r->right - r->left) * bytesPerPixel);
6758 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6759 dest_rect.left = p->x;
6760 dest_rect.top = p->y;
6761 dest_rect.right = p->x + (r->right - r->left);
6762 dest_rect.bottom= p->y + (r->bottom - r->top);
6763 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6764 TRACE("Locked src and dst\n");
6766 /* Find where to start */
6767 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6768 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6770 IWineD3DSurface_UnlockRect(pSourceSurface);
6771 IWineD3DSurface_UnlockRect(pDestinationSurface);
6772 TRACE("Unlocked src and dst\n");
6775 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6776 hr = WINED3DERR_INVALIDCALL;
6783 /* Implementation details at http://developer.nvidia.com/attach/6494
6785 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6786 hmm.. no longer supported use
6787 OpenGL evaluators or tessellate surfaces within your application.
6790 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6791 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6793 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6794 FIXME("(%p) : Stub\n", This);
6799 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6800 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6802 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6803 FIXME("(%p) : Stub\n", This);
6807 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6809 TRACE("(%p) Handle(%d)\n", This, Handle);
6810 FIXME("(%p) : Stub\n", This);
6814 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6815 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6816 fill a surface with a block of color! */
6817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6818 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6819 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6820 IWineD3DSwapChainImpl *container = NULL;
6821 BOOL isRenderTarget = FALSE;
6822 unsigned int width, height;
6823 unsigned int top, left;
6826 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6828 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6829 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6830 return WINED3DERR_INVALIDCALL;
6833 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6834 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6835 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6836 /* TODO: make sure we set everything back to the way it was, and context management!
6837 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6838 vcheckGLcall("glIntegerv");
6839 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6840 vcheckGLcall("glIntegerv");
6842 TRACE("Color fill to render targets may cause some graphics issues\n");
6843 if (pSurface == container->frontBuffer) {
6844 glDrawBuffer(GL_FRONT);
6846 glDrawBuffer(GL_BACK);
6849 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6850 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6852 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6854 if (container != NULL) {
6855 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6857 /* we can use GL_STENCIL_INDEX etc...*/
6860 if (container != NULL) {
6861 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6863 isRenderTarget = TRUE;
6865 /* TODO: drawing to GL_FRONT and GL_BACK */
6866 /* TODO: see if things can be speeded up by using the correct
6867 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6868 if (pRect == NULL) {
6871 width = surface->currentDesc.Width;
6872 height = surface->currentDesc.Height;
6876 width = pRect->x2 - left;
6877 height = pRect->y2 - top;
6880 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6881 /* Create a 'line' of color color, in the correct format for the surface */
6882 for (u = 0 ; u < width ; u ++) {
6887 if (isRenderTarget == FALSE) {
6888 glDescriptor *glDesc;
6889 IWineD3DSurface_PreLoad(pSurface);
6891 /* draw a block of the coloured line on the sufrace */
6892 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6893 for (v = 0 ; v< height;v++) {
6894 glTexSubImage2D(glDesc->target
6895 ,glDesc->level /* level */
6905 checkGLcall("glTexSubImage2D");
6907 glDisable(glDesc->target);
6909 /** FIXME: Using GLClear may be faster **/
6910 glRasterPos2i(left, top);
6911 glPixelZoom((float)width ,(float)height);
6912 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6913 checkGLcall("glDrawPixels");
6915 HeapFree(GetProcessHeap(), 0, data);
6921 /* rendertarget and deptth stencil functions */
6922 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6925 /* FIXME: Implelent RenderTargetIndex >0 */
6926 if(RenderTargetIndex > 0)
6927 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6929 *ppRenderTarget = This->renderTarget;
6930 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6931 /* Note inc ref on returned surface */
6932 if(*ppRenderTarget != NULL)
6933 IWineD3DSurface_AddRef(*ppRenderTarget);
6937 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6939 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6940 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6941 IWineD3DSwapChainImpl *Swapchain;
6944 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6946 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6947 if(hr != WINED3D_OK) {
6948 ERR("Can't get the swapchain\n");
6952 /* Make sure to release the swapchain */
6953 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6955 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6956 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6957 return WINED3DERR_INVALIDCALL;
6959 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6960 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6961 return WINED3DERR_INVALIDCALL;
6964 if(Swapchain->frontBuffer != Front) {
6965 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6967 if(Swapchain->frontBuffer)
6968 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6969 Swapchain->frontBuffer = Front;
6971 if(Swapchain->frontBuffer) {
6972 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6976 if(Back && !Swapchain->backBuffer) {
6977 /* We need memory for the back buffer array - only one back buffer this way */
6978 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6979 if(!Swapchain->backBuffer) {
6980 ERR("Out of memory\n");
6981 return E_OUTOFMEMORY;
6985 if(Swapchain->backBuffer[0] != Back) {
6986 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6988 if(!Swapchain->backBuffer[0]) {
6989 /* GL was told to draw to the front buffer at creation,
6992 glDrawBuffer(GL_BACK);
6993 checkGLcall("glDrawBuffer(GL_BACK)");
6994 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6995 Swapchain->presentParms.BackBufferCount = 1;
6997 /* That makes problems - disable for now */
6998 /* glDrawBuffer(GL_FRONT); */
6999 checkGLcall("glDrawBuffer(GL_FRONT)");
7000 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7001 Swapchain->presentParms.BackBufferCount = 0;
7005 if(Swapchain->backBuffer[0])
7006 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7007 Swapchain->backBuffer[0] = Back;
7009 if(Swapchain->backBuffer[0]) {
7010 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7012 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7020 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7022 *ppZStencilSurface = This->depthStencilBuffer;
7023 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7025 if(*ppZStencilSurface != NULL) {
7026 /* Note inc ref on returned surface */
7027 IWineD3DSurface_AddRef(*ppZStencilSurface);
7032 /* internal static helper functions */
7033 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7034 IWineD3DSurface *RenderSurface);
7036 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7038 HRESULT hr = WINED3D_OK;
7039 WINED3DVIEWPORT viewport;
7041 TRACE("(%p) Swapping rendertarget\n",This);
7042 if (RenderTargetIndex > 0) {
7043 FIXME("(%p) Render targets other than the first are not supported\n",This);
7044 RenderTargetIndex = 0;
7047 /* MSDN says that null disables the render target
7048 but a device must always be associated with a render target
7049 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7051 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7054 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7055 FIXME("Trying to set render target 0 to NULL\n");
7056 return WINED3DERR_INVALIDCALL;
7058 /* TODO: replace Impl* usage with interface usage */
7059 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7060 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);
7061 return WINED3DERR_INVALIDCALL;
7063 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7064 * builds, but I think wine counts as a 'debug' build for now.
7065 ******************************/
7066 /* If we are trying to set what we already have, don't bother */
7067 if (pRenderTarget == This->renderTarget) {
7068 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7070 /* Otherwise, set the render target up */
7072 if (FALSE == This->sceneEnded) {
7073 IWineD3DDevice_EndScene(iface);
7075 TRACE("clearing renderer\n");
7076 /* IWineD3DDeviceImpl_CleanRender(iface); */
7077 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7078 depending on the renter target implementation being used.
7079 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7080 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7081 stencil buffer and incure an extra memory overhead */
7082 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7085 if (SUCCEEDED(hr)) {
7086 /* Finally, reset the viewport as the MSDN states. */
7087 /* TODO: Replace impl usage */
7088 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7089 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7092 viewport.MaxZ = 1.0f;
7093 viewport.MinZ = 0.0f;
7094 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7096 FIXME("Unknown error setting the render target\n");
7098 This->sceneEnded = FALSE;
7102 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7104 HRESULT hr = WINED3D_OK;
7105 IWineD3DSurface *tmp;
7107 TRACE("(%p) Swapping z-buffer\n",This);
7109 if (pNewZStencil == This->stencilBufferTarget) {
7110 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7112 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7113 * depending on the renter target implementation being used.
7114 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7115 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7116 * stencil buffer and incure an extra memory overhead
7117 ******************************************************/
7120 tmp = This->stencilBufferTarget;
7121 This->stencilBufferTarget = pNewZStencil;
7122 /* should we be calling the parent or the wined3d surface? */
7123 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7124 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7126 /** TODO: glEnable/glDisable on depth/stencil depending on
7127 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7128 **********************************************************/
7135 #ifdef GL_VERSION_1_3
7136 /* Internal functions not in DirectX */
7137 /** TODO: move this off to the opengl context manager
7138 *(the swapchain doesn't need to know anything about offscreen rendering!)
7139 ****************************************************/
7141 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7145 TRACE("(%p), %p\n", This, swapchain);
7147 if (swapchain->win != swapchain->drawable) {
7148 /* Set everything back the way it ws */
7149 swapchain->render_ctx = swapchain->glCtx;
7150 swapchain->drawable = swapchain->win;
7155 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7156 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7160 unsigned int height;
7161 WINED3DFORMAT format;
7162 WINED3DSURFACE_DESC surfaceDesc;
7163 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7164 surfaceDesc.Width = &width;
7165 surfaceDesc.Height = &height;
7166 surfaceDesc.Format = &format;
7167 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7169 /* I need a get width/height function (and should do something with the format) */
7170 for (i = 0; i < CONTEXT_CACHE; ++i) {
7171 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7172 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7173 the pSurface can be set to 0 allowing it to be reused from cache **/
7174 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7175 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7176 *context = &This->contextCache[i];
7179 if (This->contextCache[i].Width == 0) {
7180 This->contextCache[i].pSurface = pSurface;
7181 This->contextCache[i].Width = width;
7182 This->contextCache[i].Height = height;
7183 *context = &This->contextCache[i];
7187 if (i == CONTEXT_CACHE) {
7188 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7189 glContext *dropContext = 0;
7190 for (i = 0; i < CONTEXT_CACHE; i++) {
7191 if (This->contextCache[i].usedcount < minUsage) {
7192 dropContext = &This->contextCache[i];
7193 minUsage = This->contextCache[i].usedcount;
7196 /* clean up the context (this doesn't work for ATI at the moment */
7198 glXDestroyContext(swapchain->display, dropContext->context);
7199 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7202 dropContext->Width = 0;
7203 dropContext->pSurface = pSurface;
7204 *context = dropContext;
7206 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7207 for (i = 0; i < CONTEXT_CACHE; i++) {
7208 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7212 if (*context != NULL)
7215 return E_OUTOFMEMORY;
7219 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7220 * the functionality needs splitting up so that we don't do more than we should do.
7221 * this only seems to impact performance a little.
7222 ******************************/
7223 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7224 IWineD3DSurface *RenderSurface) {
7225 HRESULT ret = WINED3DERR_INVALIDCALL;
7227 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7230 * Currently only active for GLX >= 1.3
7231 * for others versions we'll have to use GLXPixmaps
7233 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7234 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7235 * so only check OpenGL version
7236 * ..........................
7237 * I don't believe that it is a problem with NVidia headers,
7238 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7239 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7241 * Your application will report GLX version 1.2 on glXQueryVersion.
7242 * However, it is safe to call the GLX 1.3 functions as described below.
7244 #if defined(GL_VERSION_1_3)
7246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7247 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7248 IWineD3DSurface *tmp;
7249 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7250 GLXFBConfig* cfgs = NULL;
7254 IWineD3DSwapChain *currentSwapchain;
7255 IWineD3DSwapChainImpl *swapchain;
7256 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7257 * but switch them off if the StencilSurface is set to NULL
7258 ** *********************************************************/
7259 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7260 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7263 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7264 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7267 #define PUSH1(att) attribs[nAttribs++] = (att);
7268 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7270 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7272 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7273 IWineD3DSwapChainImpl *impSwapChain;
7274 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7275 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7276 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7281 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7282 PUSH2(GLX_X_RENDERABLE, TRUE);
7283 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7284 TRACE("calling makeglcfg\n");
7285 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7288 TRACE("calling chooseFGConfig\n");
7289 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7292 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7293 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7294 why we failed and only show this message once! */
7295 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"); /**/
7297 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7298 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7299 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7300 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7301 TRACE("calling makeglcfg\n");
7302 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7304 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7311 for (i = 0; i < nCfgs; ++i) {
7312 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7313 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7314 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7317 if (NULL != This->renderTarget) {
7319 vcheckGLcall("glFlush");
7320 /** This is only useful if the old render target was a swapchain,
7321 * we need to supercede this with a function that displays
7322 * the current buffer on the screen. This is easy to do in glx1.3 but
7323 * we need to do copy-write pixels in glx 1.2.
7324 ************************************************/
7325 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7327 printf("Hit Enter to get next frame ...\n");
7333 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain) != WINED3D_OK) {
7334 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7335 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
7339 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7340 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7341 **********************************************************************/
7342 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7343 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7344 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7345 TRACE("making swapchain active\n");
7346 if (RenderSurface != This->renderTarget) {
7347 BOOL backbuf = FALSE;
7350 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7351 if(RenderSurface == swapchain->backBuffer[i]) {
7359 /* This could be flagged so that some operations work directly with the front buffer */
7360 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7362 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7364 TRACE("Error in setting current context: context %p drawable %ld !\n",
7365 impSwapChain->glCtx, impSwapChain->win);
7368 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7370 checkGLcall("glXMakeContextCurrent");
7372 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7374 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7376 /** ********************************************************************
7377 * This is a quickly hacked out implementation of offscreen textures.
7378 * It will work in most cases but there may be problems if the client
7379 * modifies the texture directly, or expects the contents of the rendertarget
7382 * There are some real speed vs compatibility issues here:
7383 * we should really use a new context for every texture, but that eats ram.
7384 * we should also be restoring the texture to the pbuffer but that eats CPU
7385 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7386 * but if this means reusing the display backbuffer then we need to make sure that
7387 * states are correctly preserved.
7388 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7389 * and gain a good performance increase at the cost of compatibility.
7390 * I would suggest that, when this is the case, a user configurable flag be made
7391 * available, allowing the user to choose the best emulated experience for them.
7392 *********************************************************************/
7394 XVisualInfo *visinfo;
7395 glContext *newContext;
7397 /* Here were using a shared context model */
7398 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7399 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7402 /* If the context doesn't exist then create a new one */
7403 /* TODO: This should really be part of findGlContext */
7404 if (NULL == newContext->context) {
7406 TRACE("making new buffer\n");
7408 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7409 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7412 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7414 /** ****************************************
7415 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7417 * In future releases, we may provide the calls glXCreateNewContext,
7418 * glXQueryDrawable and glXMakeContextCurrent.
7419 * so until then we have to use glXGetVisualFromFBConfig &co..
7420 ********************************************/
7423 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7425 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7427 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7431 if (NULL == newContext || NULL == newContext->context) {
7432 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7434 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7435 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7436 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7439 /* Clean up the old context */
7440 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7441 /* Set the current context of the swapchain to the new context */
7442 impSwapChain->drawable = newContext->drawable;
7443 impSwapChain->render_ctx = newContext->context;
7447 /* Disable recording, and apply the stateblock to the new context
7448 * FIXME: This is a bit of a hack, each context should know it's own state,
7449 * the directX current directX state should then be applied to the context */
7450 oldUpdateStateBlock = This->updateStateBlock;
7451 oldRecording= This->isRecordingState;
7452 This->isRecordingState = FALSE;
7453 This->updateStateBlock = This->stateBlock;
7454 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7456 /* clean up the current rendertargets swapchain (if it belonged to one) */
7457 if (currentSwapchain != NULL) {
7458 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7461 /* Were done with the opengl context management, setup the rendertargets */
7463 tmp = This->renderTarget;
7464 This->renderTarget = RenderSurface;
7465 IWineD3DSurface_AddRef(This->renderTarget);
7466 IWineD3DSurface_Release(tmp);
7471 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7472 /* Check that the container is not a swapchain member */
7474 IWineD3DSwapChain *tmpSwapChain;
7475 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7476 This->renderUpsideDown = TRUE;
7478 This->renderUpsideDown = FALSE;
7479 IWineD3DSwapChain_Release(tmpSwapChain);
7481 /* Force updating the cull mode */
7482 TRACE("setting render state\n");
7483 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7484 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7486 /* Force updating projection matrix */
7487 This->last_was_rhw = FALSE;
7488 This->proj_valid = FALSE;
7491 /* Restore recording state */
7492 This->isRecordingState = oldRecording;
7493 This->updateStateBlock = oldUpdateStateBlock;
7500 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7501 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7506 if ( NULL != impSwapChain) {
7507 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7515 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7516 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7518 /* TODO: the use of Impl is deprecated. */
7519 /* some basic validation checks */
7520 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7522 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7524 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7525 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7526 return WINED3DERR_INVALIDCALL;
7528 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7529 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7530 return WINED3DERR_INVALIDCALL;
7532 /* TODO: make the cursor 'real' */
7534 This->xHotSpot = XHotSpot;
7535 This->yHotSpot = YHotSpot;
7540 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7542 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7544 This->xScreenSpace = XScreenSpace;
7545 This->yScreenSpace = YScreenSpace;
7551 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7553 TRACE("(%p) : visible(%d)\n", This, bShow);
7555 This->bCursorVisible = bShow;
7560 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7562 TRACE("(%p) : state (%lu)\n", This, This->state);
7563 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7564 switch (This->state) {
7567 case WINED3DERR_DEVICELOST:
7569 ResourceList *resourceList = This->resources;
7570 while (NULL != resourceList) {
7571 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7572 return WINED3DERR_DEVICENOTRESET;
7573 resourceList = resourceList->next;
7575 return WINED3DERR_DEVICELOST;
7577 case WINED3DERR_DRIVERINTERNALERROR:
7578 return WINED3DERR_DRIVERINTERNALERROR;
7582 return WINED3DERR_DRIVERINTERNALERROR;
7586 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7588 /** FIXME: Resource tracking needs to be done,
7589 * The closes we can do to this is set the priorities of all managed textures low
7590 * and then reset them.
7591 ***********************************************************/
7592 FIXME("(%p) : stub\n", This);
7596 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7598 /** FIXME: Resource trascking needs to be done.
7599 * in effect this pulls all non only default
7600 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7601 * and should clear down the context and set it up according to pPresentationParameters
7602 ***********************************************************/
7603 FIXME("(%p) : stub\n", This);
7607 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7609 /** FIXME: always true at the moment **/
7610 if(bEnableDialogs == FALSE) {
7611 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7617 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7619 TRACE("(%p) : pParameters %p\n", This, pParameters);
7621 *pParameters = This->createParms;
7625 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7626 IWineD3DSwapChain *swapchain;
7627 HRESULT hrc = WINED3D_OK;
7629 TRACE("Relaying to swapchain\n");
7631 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7632 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7633 IWineD3DSwapChain_Release(swapchain);
7638 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7639 IWineD3DSwapChain *swapchain;
7640 HRESULT hrc = WINED3D_OK;
7642 TRACE("Relaying to swapchain\n");
7644 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7645 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7646 IWineD3DSwapChain_Release(swapchain);
7652 /** ********************************************************
7653 * Notification functions
7654 ** ********************************************************/
7655 /** This function must be called in the release of a resource when ref == 0,
7656 * the contents of resource must still be correct,
7657 * any handels to other resource held by the caller must be closed
7658 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7659 *****************************************************/
7660 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7662 ResourceList* resourceList;
7664 TRACE("(%p) : resource %p\n", This, resource);
7666 EnterCriticalSection(&resourceStoreCriticalSection);
7668 /* add a new texture to the frot of the linked list */
7669 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7670 resourceList->resource = resource;
7672 /* Get the old head */
7673 resourceList->next = This->resources;
7675 This->resources = resourceList;
7676 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7679 LeaveCriticalSection(&resourceStoreCriticalSection);
7684 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7686 ResourceList* resourceList = NULL;
7687 ResourceList* previousResourceList = NULL;
7689 TRACE("(%p) : resource %p\n", This, resource);
7692 EnterCriticalSection(&resourceStoreCriticalSection);
7694 resourceList = This->resources;
7696 while (resourceList != NULL) {
7697 if(resourceList->resource == resource) break;
7698 previousResourceList = resourceList;
7699 resourceList = resourceList->next;
7702 if (resourceList == NULL) {
7703 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7705 LeaveCriticalSection(&resourceStoreCriticalSection);
7709 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7711 /* make sure we don't leave a hole in the list */
7712 if (previousResourceList != NULL) {
7713 previousResourceList->next = resourceList->next;
7715 This->resources = resourceList->next;
7719 LeaveCriticalSection(&resourceStoreCriticalSection);
7725 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7729 TRACE("(%p) : resource %p\n", This, resource);
7730 switch(IWineD3DResource_GetType(resource)){
7731 case WINED3DRTYPE_SURFACE:
7732 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7734 case WINED3DRTYPE_TEXTURE:
7735 case WINED3DRTYPE_CUBETEXTURE:
7736 case WINED3DRTYPE_VOLUMETEXTURE:
7737 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7738 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7739 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7740 This->stateBlock->textures[counter] = NULL;
7742 if (This->updateStateBlock != This->stateBlock ){
7743 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7744 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7745 This->updateStateBlock->textures[counter] = NULL;
7750 case WINED3DRTYPE_VOLUME:
7751 /* TODO: nothing really? */
7753 case WINED3DRTYPE_VERTEXBUFFER:
7754 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7757 TRACE("Cleaning up stream pointers\n");
7759 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7760 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7761 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7763 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7764 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7765 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7766 This->updateStateBlock->streamSource[streamNumber] = 0;
7767 /* Set changed flag? */
7770 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) */
7771 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7772 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7773 This->stateBlock->streamSource[streamNumber] = 0;
7776 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7777 else { /* This shouldn't happen */
7778 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7785 case WINED3DRTYPE_INDEXBUFFER:
7786 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7787 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7788 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7789 This->updateStateBlock->pIndexData = NULL;
7792 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7793 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7794 This->stateBlock->pIndexData = NULL;
7800 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7805 /* Remove the resoruce from the resourceStore */
7806 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7808 TRACE("Resource released\n");
7812 /**********************************************************
7813 * IWineD3DDevice VTbl follows
7814 **********************************************************/
7816 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7818 /*** IUnknown methods ***/
7819 IWineD3DDeviceImpl_QueryInterface,
7820 IWineD3DDeviceImpl_AddRef,
7821 IWineD3DDeviceImpl_Release,
7822 /*** IWineD3DDevice methods ***/
7823 IWineD3DDeviceImpl_GetParent,
7824 /*** Creation methods**/
7825 IWineD3DDeviceImpl_CreateVertexBuffer,
7826 IWineD3DDeviceImpl_CreateIndexBuffer,
7827 IWineD3DDeviceImpl_CreateStateBlock,
7828 IWineD3DDeviceImpl_CreateSurface,
7829 IWineD3DDeviceImpl_CreateTexture,
7830 IWineD3DDeviceImpl_CreateVolumeTexture,
7831 IWineD3DDeviceImpl_CreateVolume,
7832 IWineD3DDeviceImpl_CreateCubeTexture,
7833 IWineD3DDeviceImpl_CreateQuery,
7834 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7835 IWineD3DDeviceImpl_CreateVertexDeclaration,
7836 IWineD3DDeviceImpl_CreateVertexShader,
7837 IWineD3DDeviceImpl_CreatePixelShader,
7838 IWineD3DDeviceImpl_CreatePalette,
7839 /*** Odd functions **/
7840 IWineD3DDeviceImpl_Init3D,
7841 IWineD3DDeviceImpl_Uninit3D,
7842 IWineD3DDeviceImpl_EnumDisplayModes,
7843 IWineD3DDeviceImpl_EvictManagedResources,
7844 IWineD3DDeviceImpl_GetAvailableTextureMem,
7845 IWineD3DDeviceImpl_GetBackBuffer,
7846 IWineD3DDeviceImpl_GetCreationParameters,
7847 IWineD3DDeviceImpl_GetDeviceCaps,
7848 IWineD3DDeviceImpl_GetDirect3D,
7849 IWineD3DDeviceImpl_GetDisplayMode,
7850 IWineD3DDeviceImpl_SetDisplayMode,
7851 IWineD3DDeviceImpl_GetHWND,
7852 IWineD3DDeviceImpl_SetHWND,
7853 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7854 IWineD3DDeviceImpl_GetRasterStatus,
7855 IWineD3DDeviceImpl_GetSwapChain,
7856 IWineD3DDeviceImpl_Reset,
7857 IWineD3DDeviceImpl_SetDialogBoxMode,
7858 IWineD3DDeviceImpl_SetCursorProperties,
7859 IWineD3DDeviceImpl_SetCursorPosition,
7860 IWineD3DDeviceImpl_ShowCursor,
7861 IWineD3DDeviceImpl_TestCooperativeLevel,
7862 /*** Getters and setters **/
7863 IWineD3DDeviceImpl_SetClipPlane,
7864 IWineD3DDeviceImpl_GetClipPlane,
7865 IWineD3DDeviceImpl_SetClipStatus,
7866 IWineD3DDeviceImpl_GetClipStatus,
7867 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7868 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7869 IWineD3DDeviceImpl_SetDepthStencilSurface,
7870 IWineD3DDeviceImpl_GetDepthStencilSurface,
7871 IWineD3DDeviceImpl_SetFVF,
7872 IWineD3DDeviceImpl_GetFVF,
7873 IWineD3DDeviceImpl_SetGammaRamp,
7874 IWineD3DDeviceImpl_GetGammaRamp,
7875 IWineD3DDeviceImpl_SetIndices,
7876 IWineD3DDeviceImpl_GetIndices,
7877 IWineD3DDeviceImpl_SetLight,
7878 IWineD3DDeviceImpl_GetLight,
7879 IWineD3DDeviceImpl_SetLightEnable,
7880 IWineD3DDeviceImpl_GetLightEnable,
7881 IWineD3DDeviceImpl_SetMaterial,
7882 IWineD3DDeviceImpl_GetMaterial,
7883 IWineD3DDeviceImpl_SetNPatchMode,
7884 IWineD3DDeviceImpl_GetNPatchMode,
7885 IWineD3DDeviceImpl_SetPaletteEntries,
7886 IWineD3DDeviceImpl_GetPaletteEntries,
7887 IWineD3DDeviceImpl_SetPixelShader,
7888 IWineD3DDeviceImpl_GetPixelShader,
7889 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7890 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7891 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7892 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7893 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7894 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7895 IWineD3DDeviceImpl_SetRenderState,
7896 IWineD3DDeviceImpl_GetRenderState,
7897 IWineD3DDeviceImpl_SetRenderTarget,
7898 IWineD3DDeviceImpl_GetRenderTarget,
7899 IWineD3DDeviceImpl_SetFrontBackBuffers,
7900 IWineD3DDeviceImpl_SetSamplerState,
7901 IWineD3DDeviceImpl_GetSamplerState,
7902 IWineD3DDeviceImpl_SetScissorRect,
7903 IWineD3DDeviceImpl_GetScissorRect,
7904 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7905 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7906 IWineD3DDeviceImpl_SetStreamSource,
7907 IWineD3DDeviceImpl_GetStreamSource,
7908 IWineD3DDeviceImpl_SetStreamSourceFreq,
7909 IWineD3DDeviceImpl_GetStreamSourceFreq,
7910 IWineD3DDeviceImpl_SetTexture,
7911 IWineD3DDeviceImpl_GetTexture,
7912 IWineD3DDeviceImpl_SetTextureStageState,
7913 IWineD3DDeviceImpl_GetTextureStageState,
7914 IWineD3DDeviceImpl_SetTransform,
7915 IWineD3DDeviceImpl_GetTransform,
7916 IWineD3DDeviceImpl_SetVertexDeclaration,
7917 IWineD3DDeviceImpl_GetVertexDeclaration,
7918 IWineD3DDeviceImpl_SetVertexShader,
7919 IWineD3DDeviceImpl_GetVertexShader,
7920 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7921 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7922 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7923 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7924 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7925 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7926 IWineD3DDeviceImpl_SetViewport,
7927 IWineD3DDeviceImpl_GetViewport,
7928 IWineD3DDeviceImpl_MultiplyTransform,
7929 IWineD3DDeviceImpl_ValidateDevice,
7930 IWineD3DDeviceImpl_ProcessVertices,
7931 /*** State block ***/
7932 IWineD3DDeviceImpl_BeginStateBlock,
7933 IWineD3DDeviceImpl_EndStateBlock,
7934 /*** Scene management ***/
7935 IWineD3DDeviceImpl_BeginScene,
7936 IWineD3DDeviceImpl_EndScene,
7937 IWineD3DDeviceImpl_Present,
7938 IWineD3DDeviceImpl_Clear,
7940 IWineD3DDeviceImpl_DrawPrimitive,
7941 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7942 IWineD3DDeviceImpl_DrawPrimitiveUP,
7943 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7944 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7945 IWineD3DDeviceImpl_DrawRectPatch,
7946 IWineD3DDeviceImpl_DrawTriPatch,
7947 IWineD3DDeviceImpl_DeletePatch,
7948 IWineD3DDeviceImpl_ColorFill,
7949 IWineD3DDeviceImpl_UpdateTexture,
7950 IWineD3DDeviceImpl_UpdateSurface,
7951 IWineD3DDeviceImpl_CopyRects,
7952 IWineD3DDeviceImpl_StretchRect,
7953 IWineD3DDeviceImpl_GetRenderTargetData,
7954 IWineD3DDeviceImpl_GetFrontBufferData,
7955 /*** Internal use IWineD3DDevice methods ***/
7956 IWineD3DDeviceImpl_SetupTextureStates,
7957 /*** object tracking ***/
7958 IWineD3DDeviceImpl_ResourceReleased
7962 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7963 WINED3DRS_ALPHABLENDENABLE ,
7964 WINED3DRS_ALPHAFUNC ,
7965 WINED3DRS_ALPHAREF ,
7966 WINED3DRS_ALPHATESTENABLE ,
7968 WINED3DRS_COLORWRITEENABLE ,
7969 WINED3DRS_DESTBLEND ,
7970 WINED3DRS_DITHERENABLE ,
7971 WINED3DRS_FILLMODE ,
7972 WINED3DRS_FOGDENSITY ,
7974 WINED3DRS_FOGSTART ,
7975 WINED3DRS_LASTPIXEL ,
7976 WINED3DRS_SHADEMODE ,
7977 WINED3DRS_SRCBLEND ,
7978 WINED3DRS_STENCILENABLE ,
7979 WINED3DRS_STENCILFAIL ,
7980 WINED3DRS_STENCILFUNC ,
7981 WINED3DRS_STENCILMASK ,
7982 WINED3DRS_STENCILPASS ,
7983 WINED3DRS_STENCILREF ,
7984 WINED3DRS_STENCILWRITEMASK ,
7985 WINED3DRS_STENCILZFAIL ,
7986 WINED3DRS_TEXTUREFACTOR ,
7997 WINED3DRS_ZWRITEENABLE
8000 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8001 WINED3DTSS_ADDRESSW ,
8002 WINED3DTSS_ALPHAARG0 ,
8003 WINED3DTSS_ALPHAARG1 ,
8004 WINED3DTSS_ALPHAARG2 ,
8005 WINED3DTSS_ALPHAOP ,
8006 WINED3DTSS_BUMPENVLOFFSET ,
8007 WINED3DTSS_BUMPENVLSCALE ,
8008 WINED3DTSS_BUMPENVMAT00 ,
8009 WINED3DTSS_BUMPENVMAT01 ,
8010 WINED3DTSS_BUMPENVMAT10 ,
8011 WINED3DTSS_BUMPENVMAT11 ,
8012 WINED3DTSS_COLORARG0 ,
8013 WINED3DTSS_COLORARG1 ,
8014 WINED3DTSS_COLORARG2 ,
8015 WINED3DTSS_COLOROP ,
8016 WINED3DTSS_RESULTARG ,
8017 WINED3DTSS_TEXCOORDINDEX ,
8018 WINED3DTSS_TEXTURETRANSFORMFLAGS
8021 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8022 WINED3DSAMP_ADDRESSU ,
8023 WINED3DSAMP_ADDRESSV ,
8024 WINED3DSAMP_ADDRESSW ,
8025 WINED3DSAMP_BORDERCOLOR ,
8026 WINED3DSAMP_MAGFILTER ,
8027 WINED3DSAMP_MINFILTER ,
8028 WINED3DSAMP_MIPFILTER ,
8029 WINED3DSAMP_MIPMAPLODBIAS ,
8030 WINED3DSAMP_MAXMIPLEVEL ,
8031 WINED3DSAMP_MAXANISOTROPY ,
8032 WINED3DSAMP_SRGBTEXTURE ,
8033 WINED3DSAMP_ELEMENTINDEX
8036 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8038 WINED3DRS_AMBIENTMATERIALSOURCE ,
8039 WINED3DRS_CLIPPING ,
8040 WINED3DRS_CLIPPLANEENABLE ,
8041 WINED3DRS_COLORVERTEX ,
8042 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8043 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8044 WINED3DRS_FOGDENSITY ,
8046 WINED3DRS_FOGSTART ,
8047 WINED3DRS_FOGTABLEMODE ,
8048 WINED3DRS_FOGVERTEXMODE ,
8049 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8050 WINED3DRS_LIGHTING ,
8051 WINED3DRS_LOCALVIEWER ,
8052 WINED3DRS_MULTISAMPLEANTIALIAS ,
8053 WINED3DRS_MULTISAMPLEMASK ,
8054 WINED3DRS_NORMALIZENORMALS ,
8055 WINED3DRS_PATCHEDGESTYLE ,
8056 WINED3DRS_POINTSCALE_A ,
8057 WINED3DRS_POINTSCALE_B ,
8058 WINED3DRS_POINTSCALE_C ,
8059 WINED3DRS_POINTSCALEENABLE ,
8060 WINED3DRS_POINTSIZE ,
8061 WINED3DRS_POINTSIZE_MAX ,
8062 WINED3DRS_POINTSIZE_MIN ,
8063 WINED3DRS_POINTSPRITEENABLE ,
8064 WINED3DRS_RANGEFOGENABLE ,
8065 WINED3DRS_SPECULARMATERIALSOURCE ,
8066 WINED3DRS_TWEENFACTOR ,
8067 WINED3DRS_VERTEXBLEND
8070 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8071 WINED3DTSS_TEXCOORDINDEX ,
8072 WINED3DTSS_TEXTURETRANSFORMFLAGS
8075 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8076 WINED3DSAMP_DMAPOFFSET