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 return WINED3DERR_INVALIDCALL;
3499 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3503 case WINED3DRS_DITHERENABLE :
3505 glEnable(GL_DITHER);
3506 checkGLcall("glEnable GL_DITHER");
3508 glDisable(GL_DITHER);
3509 checkGLcall("glDisable GL_DITHER");
3513 case WINED3DRS_ZWRITEENABLE :
3516 checkGLcall("glDepthMask");
3519 checkGLcall("glDepthMask");
3523 case WINED3DRS_ZFUNC :
3525 int glParm = GL_LESS;
3527 switch ((D3DCMPFUNC) Value) {
3528 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3529 case D3DCMP_LESS: glParm=GL_LESS; break;
3530 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3531 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3532 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3533 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3534 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3535 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3537 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3539 glDepthFunc(glParm);
3540 checkGLcall("glDepthFunc");
3544 case WINED3DRS_AMBIENT :
3547 D3DCOLORTOGLFLOAT4(Value, col);
3548 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3549 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3550 checkGLcall("glLightModel for MODEL_AMBIENT");
3555 case WINED3DRS_ALPHABLENDENABLE :
3558 checkGLcall("glEnable GL_BLEND");
3560 glDisable(GL_BLEND);
3561 checkGLcall("glDisable GL_BLEND");
3565 case WINED3DRS_SRCBLEND :
3566 case WINED3DRS_DESTBLEND :
3568 int newVal = GL_ZERO;
3570 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3571 case D3DBLEND_ONE : newVal = GL_ONE; break;
3572 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3573 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3574 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3575 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3576 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3577 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3578 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3579 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3580 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3582 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3583 This->srcBlend = newVal;
3584 This->dstBlend = newVal;
3587 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3588 This->srcBlend = newVal;
3589 This->dstBlend = newVal;
3592 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3595 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3596 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3597 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3598 glBlendFunc(This->srcBlend, This->dstBlend);
3600 checkGLcall("glBlendFunc");
3604 case WINED3DRS_ALPHATESTENABLE :
3605 case WINED3DRS_ALPHAFUNC :
3606 case WINED3DRS_ALPHAREF :
3607 case WINED3DRS_COLORKEYENABLE :
3610 float ref = GL_LESS;
3611 BOOL enable_ckey = FALSE;
3613 IWineD3DSurfaceImpl *surf;
3615 /* Find out if the texture on the first stage has a ckey set */
3616 if(This->stateBlock->textures[0]) {
3617 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3618 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3621 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3622 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3623 glEnable(GL_ALPHA_TEST);
3624 checkGLcall("glEnable GL_ALPHA_TEST");
3626 glDisable(GL_ALPHA_TEST);
3627 checkGLcall("glDisable GL_ALPHA_TEST");
3628 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3634 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3635 glParm = GL_NOTEQUAL;
3638 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3640 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3641 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3642 case D3DCMP_LESS: glParm = GL_LESS; break;
3643 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3644 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3645 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3646 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3647 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3648 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3650 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3653 This->alphafunc = glParm;
3654 glAlphaFunc(glParm, ref);
3655 checkGLcall("glAlphaFunc");
3659 case WINED3DRS_CLIPPLANEENABLE :
3660 case WINED3DRS_CLIPPING :
3662 /* Ensure we only do the changed clip planes */
3663 DWORD enable = 0xFFFFFFFF;
3664 DWORD disable = 0x00000000;
3666 /* If enabling / disabling all */
3667 if (State == WINED3DRS_CLIPPING) {
3669 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3672 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3676 enable = Value & ~OldValue;
3677 disable = ~Value & OldValue;
3680 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3681 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3682 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3683 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3684 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3685 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3687 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3688 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3689 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3690 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3691 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3692 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3694 /** update clipping status */
3696 This->stateBlock->clip_status.ClipUnion = 0;
3697 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3699 This->stateBlock->clip_status.ClipUnion = 0;
3700 This->stateBlock->clip_status.ClipIntersection = 0;
3705 case WINED3DRS_BLENDOP :
3707 int glParm = GL_FUNC_ADD;
3709 switch ((D3DBLENDOP) Value) {
3710 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3711 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3712 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3713 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3714 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3716 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3719 if(GL_SUPPORT(ARB_IMAGING)) {
3720 TRACE("glBlendEquation(%x)\n", glParm);
3721 GL_EXTCALL(glBlendEquation(glParm));
3722 checkGLcall("glBlendEquation");
3724 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3729 case WINED3DRS_TEXTUREFACTOR :
3733 /* Note the texture color applies to all textures whereas
3734 GL_TEXTURE_ENV_COLOR applies to active only */
3736 D3DCOLORTOGLFLOAT4(Value, col);
3737 /* Set the default alpha blend color */
3738 if (GL_SUPPORT(ARB_IMAGING)) {
3739 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3740 checkGLcall("glBlendColor");
3742 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3745 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3746 /* And now the default texture color as well */
3747 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3748 /* Note the D3DRS value applies to all textures, but GL has one
3749 per texture, so apply it now ready to be used! */
3750 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3751 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3752 checkGLcall("glActiveTextureARB");
3754 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3757 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3758 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3764 case WINED3DRS_SPECULARENABLE :
3766 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3767 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3768 specular color. This is wrong:
3769 Separate specular color means the specular colour is maintained separately, whereas
3770 single color means it is merged in. However in both cases they are being used to
3772 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3773 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3777 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3778 * Instead, we need to setup the FinalCombiner properly.
3780 * The default setup for the FinalCombiner is:
3782 * <variable> <input> <mapping> <usage>
3783 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3784 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3785 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3786 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3787 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3788 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3789 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3791 * That's pretty much fine as it is, except for variable B, which needs to take
3792 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3793 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3797 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3798 checkGLcall("glMaterialfv");
3799 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3800 glEnable(GL_COLOR_SUM_EXT);
3802 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3804 checkGLcall("glEnable(GL_COLOR_SUM)");
3806 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3807 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3808 checkGLcall("glFinalCombinerInputNV()");
3811 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3813 /* for the case of enabled lighting: */
3814 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3815 checkGLcall("glMaterialfv");
3817 /* for the case of disabled lighting: */
3818 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3819 glDisable(GL_COLOR_SUM_EXT);
3821 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3823 checkGLcall("glDisable(GL_COLOR_SUM)");
3825 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3826 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3827 checkGLcall("glFinalCombinerInputNV()");
3833 case WINED3DRS_STENCILENABLE :
3834 case WINED3DRS_TWOSIDEDSTENCILMODE :
3835 case WINED3DRS_STENCILFUNC :
3836 case WINED3DRS_CCW_STENCILFUNC :
3837 case WINED3DRS_STENCILREF :
3838 case WINED3DRS_STENCILMASK :
3839 case WINED3DRS_STENCILFAIL :
3840 case WINED3DRS_STENCILZFAIL :
3841 case WINED3DRS_STENCILPASS :
3842 case WINED3DRS_CCW_STENCILFAIL :
3843 case WINED3DRS_CCW_STENCILZFAIL :
3844 case WINED3DRS_CCW_STENCILPASS :
3845 renderstate_stencil(This, State, Value);
3847 case WINED3DRS_STENCILWRITEMASK :
3849 glStencilMask(Value);
3850 TRACE("glStencilMask(%lu)\n", Value);
3851 checkGLcall("glStencilMask");
3855 case WINED3DRS_FOGENABLE :
3859 checkGLcall("glEnable GL_FOG");
3862 checkGLcall("glDisable GL_FOG");
3867 case WINED3DRS_RANGEFOGENABLE :
3870 TRACE("Enabled RANGEFOG");
3872 TRACE("Disabled RANGEFOG");
3877 case WINED3DRS_FOGCOLOR :
3880 D3DCOLORTOGLFLOAT4(Value, col);
3881 /* Set the default alpha blend color */
3882 glFogfv(GL_FOG_COLOR, &col[0]);
3883 checkGLcall("glFog GL_FOG_COLOR");
3887 case WINED3DRS_FOGTABLEMODE :
3888 case WINED3DRS_FOGVERTEXMODE :
3890 /* 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." */
3891 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3892 glHint(GL_FOG_HINT, GL_FASTEST);
3893 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3894 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3895 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3896 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3899 if(!This->last_was_rhw) {
3900 glFogi(GL_FOG_MODE, GL_EXP);
3901 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3902 if(GL_SUPPORT(EXT_FOG_COORD)) {
3903 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3904 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3905 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3906 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3912 if(!This->last_was_rhw) {
3913 glFogi(GL_FOG_MODE, GL_EXP2);
3914 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3915 if(GL_SUPPORT(EXT_FOG_COORD)) {
3916 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3917 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3918 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3919 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3924 case D3DFOG_LINEAR: {
3925 if(!This->last_was_rhw) {
3926 glFogi(GL_FOG_MODE, GL_LINEAR);
3927 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3928 if(GL_SUPPORT(EXT_FOG_COORD)) {
3929 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3930 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3931 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3932 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3938 /* Both are none? According to msdn the alpha channel of the specular
3939 * color contains a fog factor. Set it in drawStridedSlow.
3940 * Same happens with Vertexfog on transformed vertices
3942 if(GL_SUPPORT(EXT_FOG_COORD)) {
3943 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3944 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3945 glFogi(GL_FOG_MODE, GL_LINEAR);
3946 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3947 glFogf(GL_FOG_START, (float) 0xff);
3948 checkGLcall("glFogfv GL_FOG_START");
3949 glFogf(GL_FOG_END, 0.0);
3950 checkGLcall("glFogfv GL_FOG_END");
3952 /* Disable GL fog, handle this in software in drawStridedSlow */
3954 checkGLcall("glDisable(GL_FOG)");
3958 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3961 glHint(GL_FOG_HINT, GL_NICEST);
3962 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3963 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3964 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3965 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3966 if(GL_SUPPORT(EXT_FOG_COORD)) {
3967 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3968 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3969 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3970 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3973 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3974 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3975 if(GL_SUPPORT(EXT_FOG_COORD)) {
3976 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3977 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3978 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3979 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3982 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3983 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3984 if(GL_SUPPORT(EXT_FOG_COORD)) {
3985 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3986 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3987 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3991 case D3DFOG_NONE: /* Won't happen */
3992 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3995 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3996 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4001 case WINED3DRS_FOGSTART :
4004 glFogfv(GL_FOG_START, &tmpvalue.f);
4005 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4006 TRACE("Fog Start == %f\n", tmpvalue.f);
4010 case WINED3DRS_FOGEND :
4013 glFogfv(GL_FOG_END, &tmpvalue.f);
4014 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4015 TRACE("Fog End == %f\n", tmpvalue.f);
4019 case WINED3DRS_FOGDENSITY :
4022 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4023 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4027 case WINED3DRS_VERTEXBLEND :
4029 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4030 TRACE("Vertex Blending state to %ld\n", Value);
4034 case WINED3DRS_TWEENFACTOR :
4037 This->updateStateBlock->tween_factor = tmpvalue.f;
4038 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4042 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4044 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4048 case WINED3DRS_COLORVERTEX :
4049 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4050 case WINED3DRS_SPECULARMATERIALSOURCE :
4051 case WINED3DRS_AMBIENTMATERIALSOURCE :
4052 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4054 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4056 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4057 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4058 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4059 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4060 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4061 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4063 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4064 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4065 Parm = GL_AMBIENT_AND_DIFFUSE;
4069 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4071 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4073 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4080 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4082 This->tracking_color = NEEDS_TRACKING;
4083 This->tracking_parm = Parm;
4087 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4092 case WINED3DRS_LINEPATTERN :
4098 tmppattern.d = Value;
4100 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4102 if (tmppattern.lp.wRepeatFactor) {
4103 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4104 checkGLcall("glLineStipple(repeat, linepattern)");
4105 glEnable(GL_LINE_STIPPLE);
4106 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4108 glDisable(GL_LINE_STIPPLE);
4109 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4114 case WINED3DRS_ZBIAS : /* D3D8 only */
4118 TRACE("ZBias value %f\n", tmpvalue.f);
4119 glPolygonOffset(0, -tmpvalue.f);
4120 checkGLcall("glPolygonOffset(0, -Value)");
4121 glEnable(GL_POLYGON_OFFSET_FILL);
4122 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4123 glEnable(GL_POLYGON_OFFSET_LINE);
4124 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4125 glEnable(GL_POLYGON_OFFSET_POINT);
4126 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4128 glDisable(GL_POLYGON_OFFSET_FILL);
4129 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4130 glDisable(GL_POLYGON_OFFSET_LINE);
4131 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4132 glDisable(GL_POLYGON_OFFSET_POINT);
4133 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4138 case WINED3DRS_NORMALIZENORMALS :
4140 glEnable(GL_NORMALIZE);
4141 checkGLcall("glEnable(GL_NORMALIZE);");
4143 glDisable(GL_NORMALIZE);
4144 checkGLcall("glDisable(GL_NORMALIZE);");
4148 case WINED3DRS_POINTSIZE :
4149 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4151 TRACE("Set point size to %f\n", tmpvalue.f);
4152 glPointSize(tmpvalue.f);
4153 checkGLcall("glPointSize(...);");
4156 case WINED3DRS_POINTSIZE_MIN :
4157 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4159 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4160 checkGLcall("glPointParameterfEXT(...);");
4162 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4166 case WINED3DRS_POINTSIZE_MAX :
4167 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4169 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4170 checkGLcall("glPointParameterfEXT(...);");
4172 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4176 case WINED3DRS_POINTSCALE_A :
4177 case WINED3DRS_POINTSCALE_B :
4178 case WINED3DRS_POINTSCALE_C :
4179 case WINED3DRS_POINTSCALEENABLE :
4182 * POINTSCALEENABLE controls how point size value is treated. If set to
4183 * true, the point size is scaled with respect to height of viewport.
4184 * When set to false point size is in pixels.
4186 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4189 /* Default values */
4190 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4193 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4194 * This means that OpenGL will clamp really small point sizes to 1.0f.
4195 * To correct for this we need to multiply by the scale factor when sizes
4196 * are less than 1.0f. scale_factor = 1.0f / point_size.
4198 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4199 if(pointSize > 0.0f) {
4200 GLfloat scaleFactor;
4202 if(pointSize < 1.0f) {
4203 scaleFactor = pointSize * pointSize;
4208 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4209 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4210 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4211 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4212 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4213 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4214 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4218 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4219 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4220 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4222 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4223 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4224 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4226 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4230 case WINED3DRS_COLORWRITEENABLE :
4232 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4233 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4234 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4235 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4236 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4237 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4238 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4239 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4240 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4241 checkGLcall("glColorMask(...)");
4245 case WINED3DRS_LOCALVIEWER :
4247 GLint state = (Value) ? 1 : 0;
4248 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4249 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4253 case WINED3DRS_LASTPIXEL :
4256 TRACE("Last Pixel Drawing Enabled\n");
4258 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4263 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4266 TRACE("Software Processing Enabled\n");
4268 TRACE("Software Processing Disabled\n");
4273 /** not supported */
4274 case WINED3DRS_ZVISIBLE :
4277 return WINED3DERR_INVALIDCALL;
4279 case WINED3DRS_POINTSPRITEENABLE :
4281 /* TODO: NV_POINT_SPRITE */
4282 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4283 TRACE("Point sprites not supported\n");
4288 * Point sprites are always enabled. Value controls texture coordinate
4289 * replacement mode. Must be set true for point sprites to use
4292 glEnable(GL_POINT_SPRITE_ARB);
4293 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4296 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4297 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4299 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4300 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4304 case WINED3DRS_EDGEANTIALIAS :
4307 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4309 checkGLcall("glEnable(GL_BLEND)");
4310 glEnable(GL_LINE_SMOOTH);
4311 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4313 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4314 glDisable(GL_BLEND);
4315 checkGLcall("glDisable(GL_BLEND)");
4317 glDisable(GL_LINE_SMOOTH);
4318 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4322 case WINED3DRS_WRAP0 :
4323 case WINED3DRS_WRAP1 :
4324 case WINED3DRS_WRAP2 :
4325 case WINED3DRS_WRAP3 :
4326 case WINED3DRS_WRAP4 :
4327 case WINED3DRS_WRAP5 :
4328 case WINED3DRS_WRAP6 :
4329 case WINED3DRS_WRAP7 :
4330 case WINED3DRS_WRAP8 :
4331 case WINED3DRS_WRAP9 :
4332 case WINED3DRS_WRAP10 :
4333 case WINED3DRS_WRAP11 :
4334 case WINED3DRS_WRAP12 :
4335 case WINED3DRS_WRAP13 :
4336 case WINED3DRS_WRAP14 :
4337 case WINED3DRS_WRAP15 :
4339 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4340 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4341 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4342 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4343 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4345 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4347 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4349 case WINED3DRS_MULTISAMPLEANTIALIAS :
4351 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4352 TRACE("Multisample antialiasing not supported\n");
4357 glEnable(GL_MULTISAMPLE_ARB);
4358 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4360 glDisable(GL_MULTISAMPLE_ARB);
4361 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4365 case WINED3DRS_SCISSORTESTENABLE :
4368 glEnable(GL_SCISSOR_TEST);
4369 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4371 glDisable(GL_SCISSOR_TEST);
4372 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4376 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4380 glEnable(GL_POLYGON_OFFSET_FILL);
4381 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4382 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4383 checkGLcall("glPolygonOffset(...)");
4385 glDisable(GL_POLYGON_OFFSET_FILL);
4386 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4390 case WINED3DRS_ANTIALIASEDLINEENABLE :
4393 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4395 checkGLcall("glEnable(GL_BLEND)");
4396 glEnable(GL_LINE_SMOOTH);
4397 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4399 glDisable(GL_BLEND);
4400 checkGLcall("glDisable(GL_BLEND)");
4401 glDisable(GL_LINE_SMOOTH);
4402 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4406 case WINED3DRS_DEPTHBIAS :
4410 glEnable(GL_POLYGON_OFFSET_FILL);
4411 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4412 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4413 checkGLcall("glPolygonOffset(...)");
4415 glDisable(GL_POLYGON_OFFSET_FILL);
4416 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4421 case WINED3DRS_TEXTUREPERSPECTIVE :
4424 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4426 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4430 case WINED3DRS_STIPPLEDALPHA :
4433 ERR(" Stippled Alpha not supported yet.\n");
4436 case WINED3DRS_ANTIALIAS :
4439 ERR(" Antialias not supported yet.\n");
4443 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4451 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4453 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4454 *pValue = This->stateBlock->renderState[State];
4459 * Get / Set Sampler States
4460 * TODO: Verify against dx9 definitions
4463 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4466 * SetSampler is designed to allow for more than the standard up to 8 textures
4467 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4468 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4470 * http://developer.nvidia.com/object/General_FAQ.html#t6
4472 * There are two new settings for GForce
4474 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4475 * and the texture one:
4476 * GL_MAX_TEXTURE_COORDS_ARB.
4477 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4479 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4480 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4481 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4482 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4483 return WINED3DERR_INVALIDCALL;
4486 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4487 debug_d3dsamplerstate(Type), Type, Value);
4488 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4489 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4490 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4492 /* Handle recording of state blocks */
4493 if (This->isRecordingState) {
4494 TRACE("Recording... not performing anything\n");
4501 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 /** TODO: check that sampler is in range **/
4504 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4505 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4510 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4514 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4515 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4516 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4522 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 GLint scissorBox[4];
4527 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4528 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4529 pRect->left = scissorBox[0];
4530 pRect->top = scissorBox[1];
4531 pRect->right = scissorBox[0] + scissorBox[2];
4532 pRect->bottom = scissorBox[1] + scissorBox[3];
4533 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4538 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4540 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4542 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4544 This->updateStateBlock->vertexDecl = pDecl;
4545 This->updateStateBlock->changed.vertexDecl = TRUE;
4546 This->updateStateBlock->set.vertexDecl = TRUE;
4548 if (This->isRecordingState) {
4549 TRACE("Recording... not performing anything\n");
4552 if (NULL != pDecl) {
4553 IWineD3DVertexDeclaration_AddRef(pDecl);
4555 if (NULL != oldDecl) {
4556 IWineD3DVertexDeclaration_Release(oldDecl);
4561 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4566 *ppDecl = This->stateBlock->vertexDecl;
4567 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4571 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4575 This->updateStateBlock->vertexShader = pShader;
4576 This->updateStateBlock->changed.vertexShader = TRUE;
4577 This->updateStateBlock->set.vertexShader = TRUE;
4579 if (This->isRecordingState) {
4580 TRACE("Recording... not performing anything\n");
4583 if (NULL != pShader) {
4584 IWineD3DVertexShader_AddRef(pShader);
4586 if (NULL != oldShader) {
4587 IWineD3DVertexShader_Release(oldShader);
4590 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4592 * TODO: merge HAL shaders context switching from prototype
4597 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4600 if (NULL == ppShader) {
4601 return WINED3DERR_INVALIDCALL;
4603 *ppShader = This->stateBlock->vertexShader;
4604 if( NULL != *ppShader)
4605 IWineD3DVertexShader_AddRef(*ppShader);
4607 TRACE("(%p) : returning %p\n", This, *ppShader);
4611 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4612 IWineD3DDevice *iface,
4614 CONST BOOL *srcData,
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 int i, cnt = min(count, MAX_CONST_B - start);
4620 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4621 iface, srcData, start, count);
4623 if (srcData == NULL || cnt < 0)
4624 return WINED3DERR_INVALIDCALL;
4626 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4627 for (i = 0; i < cnt; i++)
4628 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4630 for (i = start; i < cnt + start; ++i) {
4631 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4632 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4639 IWineD3DDevice *iface,
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 int cnt = min(count, MAX_CONST_B - start);
4647 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4648 iface, dstData, start, count);
4650 if (dstData == NULL || cnt < 0)
4651 return WINED3DERR_INVALIDCALL;
4653 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4657 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4658 IWineD3DDevice *iface,
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 int i, cnt = min(count, MAX_CONST_I - start);
4666 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4667 iface, srcData, start, count);
4669 if (srcData == NULL || cnt < 0)
4670 return WINED3DERR_INVALIDCALL;
4672 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4673 for (i = 0; i < cnt; i++)
4674 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4675 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4677 for (i = start; i < cnt + start; ++i) {
4678 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4679 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4686 IWineD3DDevice *iface,
4691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4692 int cnt = min(count, MAX_CONST_I - start);
4694 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4695 iface, dstData, start, count);
4697 if (dstData == NULL || cnt < 0)
4698 return WINED3DERR_INVALIDCALL;
4700 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4704 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4705 IWineD3DDevice *iface,
4707 CONST float *srcData,
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4713 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4714 iface, srcData, start, count);
4716 if (srcData == NULL || cnt < 0)
4717 return WINED3DERR_INVALIDCALL;
4719 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4720 for (i = 0; i < cnt; i++)
4721 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4722 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4724 for (i = start; i < cnt + start; ++i) {
4725 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4726 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4733 IWineD3DDevice *iface,
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4741 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4742 iface, dstData, start, count);
4744 if (dstData == NULL || cnt < 0)
4745 return WINED3DERR_INVALIDCALL;
4747 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4751 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4754 This->updateStateBlock->pixelShader = pShader;
4755 This->updateStateBlock->changed.pixelShader = TRUE;
4756 This->updateStateBlock->set.pixelShader = TRUE;
4758 /* Handle recording of state blocks */
4759 if (This->isRecordingState) {
4760 TRACE("Recording... not performing anything\n");
4763 if (NULL != pShader) {
4764 IWineD3DPixelShader_AddRef(pShader);
4766 if (NULL != oldShader) {
4767 IWineD3DPixelShader_Release(oldShader);
4770 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4772 * TODO: merge HAL shaders context switching from prototype
4777 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 if (NULL == ppShader) {
4781 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 *ppShader = This->stateBlock->pixelShader;
4786 if (NULL != *ppShader) {
4787 IWineD3DPixelShader_AddRef(*ppShader);
4789 TRACE("(%p) : returning %p\n", This, *ppShader);
4793 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4794 IWineD3DDevice *iface,
4796 CONST BOOL *srcData,
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 int i, cnt = min(count, MAX_CONST_B - start);
4802 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4803 iface, srcData, start, count);
4805 if (srcData == NULL || cnt < 0)
4806 return WINED3DERR_INVALIDCALL;
4808 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4809 for (i = 0; i < cnt; i++)
4810 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4812 for (i = start; i < cnt + start; ++i) {
4813 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4814 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4820 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4821 IWineD3DDevice *iface,
4826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4827 int cnt = min(count, MAX_CONST_B - start);
4829 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4830 iface, dstData, start, count);
4832 if (dstData == NULL || cnt < 0)
4833 return WINED3DERR_INVALIDCALL;
4835 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4839 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4840 IWineD3DDevice *iface,
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 int i, cnt = min(count, MAX_CONST_I - start);
4848 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4849 iface, srcData, start, count);
4851 if (srcData == NULL || cnt < 0)
4852 return WINED3DERR_INVALIDCALL;
4854 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4855 for (i = 0; i < cnt; i++)
4856 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4857 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4859 for (i = start; i < cnt + start; ++i) {
4860 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4861 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4867 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4868 IWineD3DDevice *iface,
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4874 int cnt = min(count, MAX_CONST_I - start);
4876 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4877 iface, dstData, start, count);
4879 if (dstData == NULL || cnt < 0)
4880 return WINED3DERR_INVALIDCALL;
4882 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4886 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4887 IWineD3DDevice *iface,
4889 CONST float *srcData,
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4895 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4896 iface, srcData, start, count);
4898 if (srcData == NULL || cnt < 0)
4899 return WINED3DERR_INVALIDCALL;
4901 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4902 for (i = 0; i < cnt; i++)
4903 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4904 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4906 for (i = start; i < cnt + start; ++i) {
4907 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4908 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4914 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4915 IWineD3DDevice *iface,
4920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4921 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4923 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4924 iface, dstData, start, count);
4926 if (dstData == NULL || cnt < 0)
4927 return WINED3DERR_INVALIDCALL;
4929 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4933 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4935 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4936 char *dest_ptr, *dest_conv = NULL;
4938 DWORD DestFVF = dest->fvf;
4940 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4944 if (SrcFVF & D3DFVF_NORMAL) {
4945 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4948 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4949 ERR("Source has no position mask\n");
4950 return WINED3DERR_INVALIDCALL;
4953 /* We might access VBOs from this code, so hold the lock */
4956 if (dest->resource.allocatedMemory == NULL) {
4957 /* This may happen if we do direct locking into a vbo. Unlikely,
4958 * but theoretically possible(ddraw processvertices test)
4960 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4961 if(!dest->resource.allocatedMemory) {
4963 ERR("Out of memory\n");
4964 return E_OUTOFMEMORY;
4968 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4969 checkGLcall("glBindBufferARB");
4970 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4972 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4974 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4975 checkGLcall("glUnmapBufferARB");
4979 /* Get a pointer into the destination vbo(create one if none exists) and
4980 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4982 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4987 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4988 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4990 ERR("glMapBuffer failed\n");
4991 /* Continue without storing converted vertices */
4996 * a) D3DRS_CLIPPING is enabled
4997 * b) WINED3DVOP_CLIP is passed
4999 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5000 static BOOL warned = FALSE;
5002 * The clipping code is not quite correct. Some things need
5003 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5004 * so disable clipping for now.
5005 * (The graphics in Half-Life are broken, and my processvertices
5006 * test crashes with IDirect3DDevice3)
5012 FIXME("Clipping is broken and disabled for now\n");
5014 } else doClip = FALSE;
5015 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5017 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5020 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5023 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5026 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5027 D3DTS_WORLDMATRIX(0),
5030 TRACE("View mat:\n");
5031 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); \
5032 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); \
5033 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); \
5034 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); \
5036 TRACE("Proj mat:\n");
5037 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); \
5038 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); \
5039 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); \
5040 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); \
5042 TRACE("World mat:\n");
5043 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); \
5044 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); \
5045 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); \
5046 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); \
5048 /* Get the viewport */
5049 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5050 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5051 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5053 multiply_matrix(&mat,&view_mat,&world_mat);
5054 multiply_matrix(&mat,&proj_mat,&mat);
5056 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5058 for (i = 0; i < dwCount; i+= 1) {
5059 unsigned int tex_index;
5061 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5062 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5063 /* The position first */
5065 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5067 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5069 /* Multiplication with world, view and projection matrix */
5070 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);
5071 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);
5072 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);
5073 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);
5075 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5077 /* WARNING: The following things are taken from d3d7 and were not yet checked
5078 * against d3d8 or d3d9!
5081 /* Clipping conditions: From
5082 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5084 * A vertex is clipped if it does not match the following requirements
5088 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5090 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5091 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5095 if( doClip == FALSE ||
5096 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5097 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5100 /* "Normal" viewport transformation (not clipped)
5101 * 1) The values are divided by rhw
5102 * 2) The y axis is negative, so multiply it with -1
5103 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5104 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5105 * 4) Multiply x with Width/2 and add Width/2
5106 * 5) The same for the height
5107 * 6) Add the viewpoint X and Y to the 2D coordinates and
5108 * The minimum Z value to z
5109 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5111 * Well, basically it's simply a linear transformation into viewport
5123 z *= vp.MaxZ - vp.MinZ;
5125 x += vp.Width / 2 + vp.X;
5126 y += vp.Height / 2 + vp.Y;
5131 /* That vertex got clipped
5132 * Contrary to OpenGL it is not dropped completely, it just
5133 * undergoes a different calculation.
5135 TRACE("Vertex got clipped\n");
5142 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5143 * outside of the main vertex buffer memory. That needs some more
5148 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5151 ( (float *) dest_ptr)[0] = x;
5152 ( (float *) dest_ptr)[1] = y;
5153 ( (float *) dest_ptr)[2] = z;
5154 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5156 dest_ptr += 3 * sizeof(float);
5158 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5159 dest_ptr += sizeof(float);
5164 ( (float *) dest_conv)[0] = x * w;
5165 ( (float *) dest_conv)[1] = y * w;
5166 ( (float *) dest_conv)[2] = z * w;
5167 ( (float *) dest_conv)[3] = w;
5169 dest_conv += 3 * sizeof(float);
5171 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5172 dest_conv += sizeof(float);
5176 if (DestFVF & D3DFVF_PSIZE) {
5177 dest_ptr += sizeof(DWORD);
5178 if(dest_conv) dest_conv += sizeof(DWORD);
5180 if (DestFVF & D3DFVF_NORMAL) {
5182 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5183 /* AFAIK this should go into the lighting information */
5184 FIXME("Didn't expect the destination to have a normal\n");
5185 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5187 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5191 if (DestFVF & D3DFVF_DIFFUSE) {
5193 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5195 static BOOL warned = FALSE;
5197 if(warned == FALSE) {
5198 ERR("No diffuse color in source, but destination has one\n");
5202 *( (DWORD *) dest_ptr) = 0xffffffff;
5203 dest_ptr += sizeof(DWORD);
5206 *( (DWORD *) dest_conv) = 0xffffffff;
5207 dest_conv += sizeof(DWORD);
5211 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5213 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5214 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5215 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5216 dest_conv += sizeof(DWORD);
5221 if (DestFVF & D3DFVF_SPECULAR) {
5222 /* What's the color value in the feedback buffer? */
5224 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5226 static BOOL warned = FALSE;
5228 if(warned == FALSE) {
5229 ERR("No specular color in source, but destination has one\n");
5233 *( (DWORD *) dest_ptr) = 0xFF000000;
5234 dest_ptr += sizeof(DWORD);
5237 *( (DWORD *) dest_conv) = 0xFF000000;
5238 dest_conv += sizeof(DWORD);
5242 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5244 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5245 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5246 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5247 dest_conv += sizeof(DWORD);
5252 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5254 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5255 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5257 ERR("No source texture, but destination requests one\n");
5258 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5259 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5262 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5264 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5271 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5272 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5279 #undef copy_and_next
5281 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5283 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5284 WineDirect3DVertexStridedData strided;
5285 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5287 /* We don't need the source vbo because this buffer is only used as
5288 * a source for ProcessVertices. Avoid wasting resources by converting the
5289 * buffer and loading the VBO
5292 TRACE("Releaseing the source vbo, it won't be needed\n");
5294 if(!SrcImpl->resource.allocatedMemory) {
5295 /* Rescue the data from the buffer */
5297 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5298 if(!SrcImpl->resource.allocatedMemory) {
5299 ERR("Out of memory\n");
5300 return E_OUTOFMEMORY;
5304 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5305 checkGLcall("glBindBufferARB");
5307 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5309 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5312 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5313 checkGLcall("glUnmapBufferARB");
5318 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5319 checkGLcall("glBindBufferARB");
5320 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5321 checkGLcall("glDeleteBuffersARB");
5327 memset(&strided, 0, sizeof(strided));
5328 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5330 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5334 * Apply / Get / Set Texture Stage States
5335 * TODO: Verify against dx9 definitions
5338 /* 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 */
5339 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5341 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5342 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5344 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5346 /* Check that the stage is within limits */
5347 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5348 TRACE("Attempt to access invalid texture rejected\n");
5355 case WINED3DTSS_ALPHAOP :
5356 case WINED3DTSS_COLOROP :
5357 /* nothing to do as moved to drawprim for now */
5359 case WINED3DTSS_ADDRESSW :
5360 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5361 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5362 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5365 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5366 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5367 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5368 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5371 case WINED3DTSS_TEXCOORDINDEX :
5373 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5375 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5376 one flag, you can still specify an index value, which the system uses to
5377 determine the texture wrapping mode.
5378 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5379 means use the vertex position (camera-space) as the input texture coordinates
5380 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5381 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5382 to the TEXCOORDINDEX value */
5385 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5387 switch (Value & 0xFFFF0000) {
5388 case D3DTSS_TCI_PASSTHRU:
5389 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5390 glDisable(GL_TEXTURE_GEN_S);
5391 glDisable(GL_TEXTURE_GEN_T);
5392 glDisable(GL_TEXTURE_GEN_R);
5393 glDisable(GL_TEXTURE_GEN_Q);
5394 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5397 case D3DTSS_TCI_CAMERASPACEPOSITION:
5398 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5399 as the input texture coordinates for this stage's texture transformation. This
5400 equates roughly to EYE_LINEAR */
5402 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5403 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5404 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5405 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5406 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5408 glMatrixMode(GL_MODELVIEW);
5411 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5412 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5413 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5414 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5417 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5418 glEnable(GL_TEXTURE_GEN_S);
5419 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5420 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5421 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5422 glEnable(GL_TEXTURE_GEN_T);
5423 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5424 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5425 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5426 glEnable(GL_TEXTURE_GEN_R);
5427 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5428 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5429 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5433 case D3DTSS_TCI_CAMERASPACENORMAL:
5435 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5436 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5437 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5438 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5439 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5440 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5442 glMatrixMode(GL_MODELVIEW);
5445 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5446 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5447 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5448 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5451 glEnable(GL_TEXTURE_GEN_S);
5452 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5453 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5454 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5455 glEnable(GL_TEXTURE_GEN_T);
5456 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5457 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5458 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5459 glEnable(GL_TEXTURE_GEN_R);
5460 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5461 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5462 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5467 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5469 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5470 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5471 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5472 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5473 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5474 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5476 glMatrixMode(GL_MODELVIEW);
5479 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5480 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5481 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5482 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5485 glEnable(GL_TEXTURE_GEN_S);
5486 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5487 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5488 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5489 glEnable(GL_TEXTURE_GEN_T);
5490 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5491 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5492 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5493 glEnable(GL_TEXTURE_GEN_R);
5494 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5495 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5496 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5501 /* Unhandled types: */
5504 /* ? disable GL_TEXTURE_GEN_n ? */
5505 glDisable(GL_TEXTURE_GEN_S);
5506 glDisable(GL_TEXTURE_GEN_T);
5507 glDisable(GL_TEXTURE_GEN_R);
5508 glDisable(GL_TEXTURE_GEN_Q);
5509 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5516 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5517 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);
5520 case WINED3DTSS_BUMPENVMAT00 :
5521 case WINED3DTSS_BUMPENVMAT01 :
5522 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5524 case WINED3DTSS_BUMPENVMAT10 :
5525 case WINED3DTSS_BUMPENVMAT11 :
5526 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5529 case WINED3DTSS_BUMPENVLSCALE :
5530 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5533 case WINED3DTSS_BUMPENVLOFFSET :
5534 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5537 case WINED3DTSS_RESULTARG :
5538 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5542 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5543 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5552 * Get / Set Texture Stage States
5553 * TODO: Verify against dx9 definitions
5555 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5558 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5560 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5562 /* Reject invalid texture units */
5563 if (Stage >= GL_LIMITS(texture_stages)) {
5564 TRACE("Attempt to access invalid texture rejected\n");
5565 return WINED3DERR_INVALIDCALL;
5568 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5569 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5570 This->updateStateBlock->textureState[Stage][Type] = Value;
5575 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5578 *pValue = This->updateStateBlock->textureState[Stage][Type];
5585 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5588 IWineD3DBaseTexture *oldTexture;
5590 oldTexture = This->updateStateBlock->textures[Stage];
5591 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5593 #if 0 /* TODO: check so vertex textures */
5594 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5595 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5600 /* Reject invalid texture units */
5601 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5602 WARN("Attempt to access invalid texture rejected\n");
5603 return WINED3DERR_INVALIDCALL;
5606 if(pTexture != NULL) {
5607 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5609 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5610 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5611 return WINED3DERR_INVALIDCALL;
5615 oldTexture = This->updateStateBlock->textures[Stage];
5616 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5617 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5619 This->updateStateBlock->set.textures[Stage] = TRUE;
5620 This->updateStateBlock->changed.textures[Stage] = TRUE;
5621 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5622 This->updateStateBlock->textures[Stage] = pTexture;
5624 /* Handle recording of state blocks */
5625 if (This->isRecordingState) {
5626 TRACE("Recording... not performing anything\n");
5630 /** NOTE: MSDN says that setTexture increases the reference count,
5631 * and the the application nust set the texture back to null (or have a leaky application),
5632 * This means we should pass the refcount up to the parent
5633 *******************************/
5634 if (NULL != This->updateStateBlock->textures[Stage]) {
5635 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5638 if (NULL != oldTexture) {
5639 IWineD3DBaseTexture_Release(oldTexture);
5642 /* Reset color keying */
5643 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5644 BOOL enable_ckey = FALSE;
5647 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5648 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5652 glAlphaFunc(GL_NOTEQUAL, 0.0);
5653 checkGLcall("glAlphaFunc");
5660 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5664 /* Reject invalid texture units */
5665 if (Stage >= GL_LIMITS(sampler_stages)) {
5666 TRACE("Attempt to access invalid texture rejected\n");
5667 return WINED3DERR_INVALIDCALL;
5669 *ppTexture=This->updateStateBlock->textures[Stage];
5671 IWineD3DBaseTexture_AddRef(*ppTexture);
5673 return WINED3DERR_INVALIDCALL;
5680 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5681 IWineD3DSurface **ppBackBuffer) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 IWineD3DSwapChain *swapChain;
5686 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5688 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5689 if (hr == WINED3D_OK) {
5690 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5691 IWineD3DSwapChain_Release(swapChain);
5693 *ppBackBuffer = NULL;
5698 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5700 WARN("(%p) : stub, calling idirect3d for now\n", This);
5701 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 IWineD3DSwapChain *swapChain;
5709 if(iSwapChain > 0) {
5710 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5711 if (hr == WINED3D_OK) {
5712 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5713 IWineD3DSwapChain_Release(swapChain);
5715 FIXME("(%p) Error getting display mode\n", This);
5718 /* Don't read the real display mode,
5719 but return the stored mode instead. X11 can't change the color
5720 depth, and some apps are pretty angry if they SetDisplayMode from
5721 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5723 Also don't relay to the swapchain because with ddraw it's possible
5724 that there isn't a swapchain at all */
5725 pMode->Width = This->ddraw_width;
5726 pMode->Height = This->ddraw_height;
5727 pMode->Format = This->ddraw_format;
5728 pMode->RefreshRate = 0;
5735 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 TRACE("(%p)->(%p)\n", This, hWnd);
5739 This->ddraw_window = hWnd;
5743 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 TRACE("(%p)->(%p)\n", This, hWnd);
5747 *hWnd = This->ddraw_window;
5752 * Stateblock related functions
5755 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 IWineD3DStateBlockImpl *object;
5758 HRESULT temp_result;
5760 TRACE("(%p)", This);
5762 if (This->isRecordingState) {
5763 return WINED3DERR_INVALIDCALL;
5766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5767 if (NULL == object ) {
5768 FIXME("(%p)Error allocating memory for stateblock\n", This);
5769 return E_OUTOFMEMORY;
5771 TRACE("(%p) created object %p\n", This, object);
5772 object->wineD3DDevice= This;
5773 /** FIXME: object->parent = parent; **/
5774 object->parent = NULL;
5775 object->blockType = WINED3DSBT_ALL;
5777 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5779 temp_result = allocate_shader_constants(object);
5780 if (WINED3D_OK != temp_result)
5783 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5784 This->updateStateBlock = object;
5785 This->isRecordingState = TRUE;
5787 TRACE("(%p) recording stateblock %p\n",This , object);
5791 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 if (!This->isRecordingState) {
5795 FIXME("(%p) not recording! returning error\n", This);
5796 *ppStateBlock = NULL;
5797 return WINED3DERR_INVALIDCALL;
5800 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5801 This->isRecordingState = FALSE;
5802 This->updateStateBlock = This->stateBlock;
5803 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5804 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5805 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5810 * Scene related functions
5812 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5813 /* At the moment we have no need for any functionality at the beginning
5815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5816 TRACE("(%p) : stub\n", This);
5820 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 TRACE("(%p)\n", This);
5824 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5826 checkGLcall("glFlush");
5828 TRACE("End Scene\n");
5829 if(This->renderTarget != NULL) {
5831 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5832 IUnknown *targetContainer = NULL;
5833 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5834 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5835 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5836 /** always dirtify for now. we must find a better way to see that surface have been modified
5837 (Modifications should will only occur via draw-primitive, but we do need better locking
5838 switching to render-to-texture should remove the overhead though.
5840 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5841 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5842 IWineD3DSurface_PreLoad(This->renderTarget);
5843 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5844 IUnknown_Release(targetContainer);
5847 This->sceneEnded = TRUE;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5853 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5854 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5856 IWineD3DSwapChain *swapChain = NULL;
5858 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5860 TRACE("(%p) Presenting the frame\n", This);
5862 for(i = 0 ; i < swapchains ; i ++) {
5864 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5865 TRACE("presentinng chain %d, %p\n", i, swapChain);
5866 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5867 IWineD3DSwapChain_Release(swapChain);
5873 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5874 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5877 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5878 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5879 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5880 GLbitfield glMask = 0;
5881 GLboolean old_ztest;
5882 GLfloat old_z_clear_value;
5883 GLint old_stencil_clear_value;
5884 GLfloat old_color_clear_value[4];
5886 CONST D3DRECT* curRect;
5888 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5889 Count, pRects, Flags, Z, Stencil);
5893 glEnable(GL_SCISSOR_TEST);
5894 checkGLcall("glEnable GL_SCISSOR_TEST");
5896 if (Count > 0 && pRects) {
5902 /* Only set the values up once, as they are not changing */
5903 if (Flags & D3DCLEAR_STENCIL) {
5904 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5905 glClearStencil(Stencil);
5906 checkGLcall("glClearStencil");
5907 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5908 glStencilMask(0xFFFFFFFF);
5911 if (Flags & D3DCLEAR_ZBUFFER) {
5912 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5913 glDepthMask(GL_TRUE);
5914 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5916 checkGLcall("glClearDepth");
5917 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5920 if (Flags & D3DCLEAR_TARGET) {
5921 TRACE("Clearing screen with glClear to color %lx\n", Color);
5922 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5923 glClearColor(D3DCOLOR_R(Color),
5927 checkGLcall("glClearColor");
5929 /* Clear ALL colors! */
5930 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5931 glMask = glMask | GL_COLOR_BUFFER_BIT;
5934 /* Now process each rect in turn */
5935 for (i = 0; i < Count || i == 0; i++) {
5938 /* Note gl uses lower left, width/height */
5939 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5940 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5941 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5942 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5943 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5944 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5945 checkGLcall("glScissor");
5947 glScissor(This->stateBlock->viewport.X,
5948 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5949 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5950 This->stateBlock->viewport.Width,
5951 This->stateBlock->viewport.Height);
5952 checkGLcall("glScissor");
5955 /* Clear the selected rectangle (or full screen) */
5957 checkGLcall("glClear");
5959 /* Step to the next rectangle */
5960 if (curRect) curRect = curRect + sizeof(D3DRECT);
5963 /* Restore the old values (why..?) */
5964 if (Flags & D3DCLEAR_STENCIL) {
5965 glClearStencil(old_stencil_clear_value);
5966 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5968 if (Flags & D3DCLEAR_ZBUFFER) {
5969 glDepthMask(old_ztest);
5970 glClearDepth(old_z_clear_value);
5972 if (Flags & D3DCLEAR_TARGET) {
5973 glClearColor(old_color_clear_value[0],
5974 old_color_clear_value[1],
5975 old_color_clear_value[2],
5976 old_color_clear_value[3]);
5977 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5978 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5979 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5980 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5983 glDisable(GL_SCISSOR_TEST);
5984 checkGLcall("glDisable");
5993 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5994 UINT PrimitiveCount) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 This->stateBlock->streamIsUP = FALSE;
5999 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6000 debug_d3dprimitivetype(PrimitiveType),
6001 StartVertex, PrimitiveCount);
6002 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6003 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6009 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6010 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6011 D3DPRIMITIVETYPE PrimitiveType,
6012 INT baseVIndex, UINT minIndex,
6013 UINT NumVertices, UINT startIndex, UINT primCount) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6017 IWineD3DIndexBuffer *pIB;
6018 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6020 pIB = This->stateBlock->pIndexData;
6021 This->stateBlock->streamIsUP = FALSE;
6023 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6024 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6025 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6027 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6028 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6034 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6035 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6040 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6041 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6042 UINT VertexStreamZeroStride) {
6043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6045 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6046 debug_d3dprimitivetype(PrimitiveType),
6047 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6049 /* release the stream source */
6050 if (This->stateBlock->streamSource[0] != NULL) {
6051 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6054 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6055 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6056 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6057 This->stateBlock->streamIsUP = TRUE;
6059 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6060 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6062 /* MSDN specifies stream zero settings must be set to NULL */
6063 This->stateBlock->streamStride[0] = 0;
6064 This->stateBlock->streamSource[0] = NULL;
6066 /*stream zero settings set to null at end, as per the msdn */
6070 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6071 UINT MinVertexIndex, UINT NumVertices,
6072 UINT PrimitiveCount, CONST void* pIndexData,
6073 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6074 UINT VertexStreamZeroStride) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6078 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6079 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6080 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6081 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6083 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6089 /* release the stream and index data */
6090 if (This->stateBlock->streamSource[0] != NULL) {
6091 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6093 if (This->stateBlock->pIndexData) {
6094 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6097 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6098 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6099 This->stateBlock->streamIsUP = TRUE;
6100 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6102 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6104 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6105 This->stateBlock->streamSource[0] = NULL;
6106 This->stateBlock->streamStride[0] = 0;
6107 This->stateBlock->pIndexData = NULL;
6112 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6114 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6117 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6118 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 HRESULT hr = WINED3D_OK;
6121 WINED3DRESOURCETYPE sourceType;
6122 WINED3DRESOURCETYPE destinationType;
6125 /* TODO: think about moving the code into IWineD3DBaseTexture */
6127 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6129 /* verify that the source and destination textures aren't NULL */
6130 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6131 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6132 This, pSourceTexture, pDestinationTexture);
6133 hr = WINED3DERR_INVALIDCALL;
6136 if (pSourceTexture == pDestinationTexture) {
6137 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6138 This, pSourceTexture, pDestinationTexture);
6139 hr = WINED3DERR_INVALIDCALL;
6141 /* Verify that the source and destination textures are the same type */
6142 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6143 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6145 if (sourceType != destinationType) {
6146 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6148 hr = WINED3DERR_INVALIDCALL;
6151 /* check that both textures have the identical numbers of levels */
6152 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6153 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6154 hr = WINED3DERR_INVALIDCALL;
6157 if (WINED3D_OK == hr) {
6159 /* Make sure that the destination texture is loaded */
6160 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6162 /* Update every surface level of the texture */
6163 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6165 switch (sourceType) {
6166 case WINED3DRTYPE_TEXTURE:
6168 IWineD3DSurface *srcSurface;
6169 IWineD3DSurface *destSurface;
6171 for (i = 0 ; i < levels ; ++i) {
6172 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6173 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6174 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6175 IWineD3DSurface_Release(srcSurface);
6176 IWineD3DSurface_Release(destSurface);
6177 if (WINED3D_OK != hr) {
6178 WARN("(%p) : Call to update surface failed\n", This);
6184 case WINED3DRTYPE_CUBETEXTURE:
6186 IWineD3DSurface *srcSurface;
6187 IWineD3DSurface *destSurface;
6188 WINED3DCUBEMAP_FACES faceType;
6190 for (i = 0 ; i < levels ; ++i) {
6191 /* Update each cube face */
6192 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6193 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6194 if (WINED3D_OK != hr) {
6195 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6197 TRACE("Got srcSurface %p\n", srcSurface);
6199 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6200 if (WINED3D_OK != hr) {
6201 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6203 TRACE("Got desrSurface %p\n", destSurface);
6205 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6206 IWineD3DSurface_Release(srcSurface);
6207 IWineD3DSurface_Release(destSurface);
6208 if (WINED3D_OK != hr) {
6209 WARN("(%p) : Call to update surface failed\n", This);
6216 #if 0 /* TODO: Add support for volume textures */
6217 case WINED3DRTYPE_VOLUMETEXTURE:
6219 IWineD3DVolume srcVolume = NULL;
6220 IWineD3DSurface destVolume = NULL;
6222 for (i = 0 ; i < levels ; ++i) {
6223 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6224 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6225 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6226 IWineD3DVolume_Release(srcSurface);
6227 IWineD3DVolume_Release(destSurface);
6228 if (WINED3D_OK != hr) {
6229 WARN("(%p) : Call to update volume failed\n", This);
6237 FIXME("(%p) : Unsupported source and destination type\n", This);
6238 hr = WINED3DERR_INVALIDCALL;
6245 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6246 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6247 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6250 TRACE("(%p) : stub\n", This);
6253 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6255 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6256 * NOTE It may be best to move the code into surface to occomplish this
6257 ****************************************/
6259 WINED3DSURFACE_DESC surfaceDesc;
6260 unsigned int surfaceWidth, surfaceHeight;
6261 glDescriptor *targetGlDescription = NULL;
6262 glDescriptor *surfaceGlDescription = NULL;
6263 IWineD3DSwapChainImpl *container = NULL;
6265 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6266 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6267 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6269 surfaceDesc.Width = &surfaceWidth;
6270 surfaceDesc.Height = &surfaceHeight;
6271 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6272 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6274 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6275 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6277 /* TODO: opengl Context switching for swapchains etc... */
6278 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6279 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6280 glReadBuffer(GL_BACK);
6281 vcheckGLcall("glReadBuffer(GL_BACK)");
6282 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6283 glReadBuffer(GL_FRONT);
6284 vcheckGLcall("glReadBuffer(GL_FRONT)");
6285 } else if (pRenderTarget == This->depthStencilBuffer) {
6286 FIXME("Reading of depthstencil not yet supported\n");
6289 glReadPixels(surfaceGlDescription->target,
6290 surfaceGlDescription->level,
6293 surfaceGlDescription->glFormat,
6294 surfaceGlDescription->glType,
6295 (void *)IWineD3DSurface_GetData(pSurface));
6296 vcheckGLcall("glReadPixels(...)");
6297 if(NULL != container ){
6298 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6301 IWineD3DBaseTexture *container;
6302 GLenum textureDimensions = GL_TEXTURE_2D;
6304 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6305 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6306 IWineD3DBaseTexture_Release(container);
6308 /* TODO: 2D -> Cube surface coppies etc.. */
6309 if (surfaceGlDescription->target != textureDimensions) {
6310 FIXME("(%p) : Texture dimension mismatch\n", This);
6312 glEnable(textureDimensions);
6313 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6314 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6315 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6316 vcheckGLcall("glBindTexture");
6317 glGetTexImage(surfaceGlDescription->target,
6318 surfaceGlDescription->level,
6319 surfaceGlDescription->glFormat,
6320 surfaceGlDescription->glType,
6321 (void *)IWineD3DSurface_GetData(pSurface));
6322 glDisable(textureDimensions);
6323 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6330 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6331 IWineD3DSwapChain *swapChain;
6333 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6334 if(hr == WINED3D_OK) {
6335 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6336 IWineD3DSwapChain_Release(swapChain);
6341 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6343 /* return a sensible default */
6345 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6346 FIXME("(%p) : stub\n", This);
6350 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6353 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6354 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6355 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6356 return WINED3DERR_INVALIDCALL;
6358 for (j = 0; j < 256; ++j) {
6359 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6360 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6361 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6362 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6364 TRACE("(%p) : returning\n", This);
6368 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6371 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6372 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6373 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6374 return WINED3DERR_INVALIDCALL;
6376 for (j = 0; j < 256; ++j) {
6377 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6378 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6379 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6380 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6382 TRACE("(%p) : returning\n", This);
6386 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6388 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6389 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6390 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6391 return WINED3DERR_INVALIDCALL;
6393 /*TODO: stateblocks */
6394 This->currentPalette = PaletteNumber;
6395 TRACE("(%p) : returning\n", This);
6399 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 if (PaletteNumber == NULL) {
6402 WARN("(%p) : returning Invalid Call\n", This);
6403 return WINED3DERR_INVALIDCALL;
6405 /*TODO: stateblocks */
6406 *PaletteNumber = This->currentPalette;
6407 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6411 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6413 static BOOL showFixmes = TRUE;
6415 FIXME("(%p) : stub\n", This);
6419 This->softwareVertexProcessing = bSoftware;
6424 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6426 static BOOL showFixmes = TRUE;
6428 FIXME("(%p) : stub\n", This);
6431 return This->softwareVertexProcessing;
6435 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 IWineD3DSwapChain *swapChain;
6440 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6442 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6443 if(hr == WINED3D_OK){
6444 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6445 IWineD3DSwapChain_Release(swapChain);
6447 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6453 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6455 static BOOL showfixmes = TRUE;
6456 if(nSegments != 0.0f) {
6458 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6465 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6467 static BOOL showfixmes = TRUE;
6469 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6475 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6477 /** TODO: remove casts to IWineD3DSurfaceImpl
6478 * NOTE: move code to surface to accomplish this
6479 ****************************************/
6480 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6481 int srcWidth, srcHeight;
6482 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6483 WINED3DFORMAT destFormat, srcFormat;
6485 int destLeft, destTop;
6486 WINED3DPOOL srcPool, destPool;
6488 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6489 glDescriptor *glDescription = NULL;
6490 GLenum textureDimensions = GL_TEXTURE_2D;
6491 IWineD3DBaseTexture *baseTexture;
6493 WINED3DSURFACE_DESC winedesc;
6495 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6496 memset(&winedesc, 0, sizeof(winedesc));
6497 winedesc.Width = &srcSurfaceWidth;
6498 winedesc.Height = &srcSurfaceHeight;
6499 winedesc.Pool = &srcPool;
6500 winedesc.Format = &srcFormat;
6502 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6504 winedesc.Width = &destSurfaceWidth;
6505 winedesc.Height = &destSurfaceHeight;
6506 winedesc.Pool = &destPool;
6507 winedesc.Format = &destFormat;
6508 winedesc.Size = &destSize;
6510 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6512 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6513 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6514 return WINED3DERR_INVALIDCALL;
6517 if (destFormat == WINED3DFMT_UNKNOWN) {
6518 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6519 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6521 /* Get the update surface description */
6522 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6525 /* Make sure the surface is loaded and up to date */
6526 IWineD3DSurface_PreLoad(pDestinationSurface);
6528 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6532 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6533 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6534 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6535 destLeft = pDestPoint ? pDestPoint->x : 0;
6536 destTop = pDestPoint ? pDestPoint->y : 0;
6539 /* This function doesn't support compressed textures
6540 the pitch is just bytesPerPixel * width */
6541 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6542 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6543 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6544 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6546 /* TODO DXT formats */
6548 if(pSourceRect != NULL && pSourceRect->top != 0){
6549 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6551 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6553 ,glDescription->level
6558 ,glDescription->glFormat
6559 ,glDescription->glType
6560 ,IWineD3DSurface_GetData(pSourceSurface)
6564 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6566 /* need to lock the surface to get the data */
6567 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6570 /* TODO: Cube and volume support */
6572 /* not a whole row so we have to do it a line at a time */
6575 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6576 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6578 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6580 glTexSubImage2D(glDescription->target
6581 ,glDescription->level
6586 ,glDescription->glFormat
6587 ,glDescription->glType
6588 ,data /* could be quicker using */
6593 } else { /* Full width, so just write out the whole texture */
6595 if (WINED3DFMT_DXT1 == destFormat ||
6596 WINED3DFMT_DXT2 == destFormat ||
6597 WINED3DFMT_DXT3 == destFormat ||
6598 WINED3DFMT_DXT4 == destFormat ||
6599 WINED3DFMT_DXT5 == destFormat) {
6600 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6601 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6602 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6603 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6604 } if (destFormat != srcFormat) {
6605 FIXME("Updating mixed format compressed texture is not curretly support\n");
6607 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6608 glDescription->level,
6609 glDescription->glFormatInternal,
6614 IWineD3DSurface_GetData(pSourceSurface));
6617 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6622 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6624 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6625 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6626 data returned by GetData non-power2 width/height with hardware non-power2
6627 pow2Width/height are set to surface width height, repacking isn't needed so it
6628 doesn't matter which function gets called. */
6629 glTexSubImage2D(glDescription->target
6630 ,glDescription->level
6635 ,glDescription->glFormat
6636 ,glDescription->glType
6637 ,IWineD3DSurface_GetData(pSourceSurface)
6641 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6642 glTexSubImage2D(glDescription->target
6643 ,glDescription->level
6646 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6647 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6648 ,glDescription->glFormat
6649 ,glDescription->glType
6650 ,IWineD3DSurface_GetData(pSourceSurface)
6656 checkGLcall("glTexSubImage2D");
6658 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6659 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6660 * surface bigger than it needs to be hmm.. */
6661 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6662 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6663 IWineD3DBaseTexture_Release(baseTexture);
6666 glDisable(textureDimensions); /* This needs to be managed better.... */
6672 /* Used by DirectX 8 */
6673 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6674 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6675 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6678 HRESULT hr = WINED3D_OK;
6679 WINED3DFORMAT srcFormat, destFormat;
6680 UINT srcWidth, destWidth;
6681 UINT srcHeight, destHeight;
6683 WINED3DSURFACE_DESC winedesc;
6685 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6686 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6689 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6690 memset(&winedesc, 0, sizeof(winedesc));
6692 winedesc.Format = &srcFormat;
6693 winedesc.Width = &srcWidth;
6694 winedesc.Height = &srcHeight;
6695 winedesc.Size = &srcSize;
6696 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6698 winedesc.Format = &destFormat;
6699 winedesc.Width = &destWidth;
6700 winedesc.Height = &destHeight;
6701 winedesc.Size = NULL;
6702 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6704 /* Check that the source and destination formats match */
6705 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6706 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6707 return WINED3DERR_INVALIDCALL;
6708 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6709 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6710 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6711 destFormat = srcFormat;
6714 /* Quick if complete copy ... */
6715 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6717 if (srcWidth == destWidth && srcHeight == destHeight) {
6718 WINED3DLOCKED_RECT lrSrc;
6719 WINED3DLOCKED_RECT lrDst;
6720 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6721 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6722 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6724 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6726 IWineD3DSurface_UnlockRect(pSourceSurface);
6727 IWineD3DSurface_UnlockRect(pDestinationSurface);
6728 TRACE("Unlocked src and dst\n");
6732 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6733 hr = WINED3DERR_INVALIDCALL;
6738 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6740 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6743 /* Copy rect by rect */
6744 for (i = 0; i < cRects; ++i) {
6745 CONST RECT* r = &pSourceRectsArray[i];
6746 CONST POINT* p = &pDestPointsArray[i];
6749 WINED3DLOCKED_RECT lrSrc;
6750 WINED3DLOCKED_RECT lrDst;
6753 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6754 if (srcFormat == WINED3DFMT_DXT1) {
6755 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6757 copyperline = ((r->right - r->left) * bytesPerPixel);
6760 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6761 dest_rect.left = p->x;
6762 dest_rect.top = p->y;
6763 dest_rect.right = p->x + (r->right - r->left);
6764 dest_rect.bottom= p->y + (r->bottom - r->top);
6765 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6766 TRACE("Locked src and dst\n");
6768 /* Find where to start */
6769 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6770 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6772 IWineD3DSurface_UnlockRect(pSourceSurface);
6773 IWineD3DSurface_UnlockRect(pDestinationSurface);
6774 TRACE("Unlocked src and dst\n");
6777 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6778 hr = WINED3DERR_INVALIDCALL;
6785 /* Implementation details at http://developer.nvidia.com/attach/6494
6787 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6788 hmm.. no longer supported use
6789 OpenGL evaluators or tessellate surfaces within your application.
6792 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6793 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6795 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6796 FIXME("(%p) : Stub\n", This);
6801 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6802 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6804 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6805 FIXME("(%p) : Stub\n", This);
6809 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6811 TRACE("(%p) Handle(%d)\n", This, Handle);
6812 FIXME("(%p) : Stub\n", This);
6816 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6817 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6818 fill a surface with a block of color! */
6819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6820 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6821 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6822 IWineD3DSwapChainImpl *container = NULL;
6823 BOOL isRenderTarget = FALSE;
6824 unsigned int width, height;
6825 unsigned int top, left;
6828 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6830 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6831 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6832 return WINED3DERR_INVALIDCALL;
6835 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6836 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6837 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6838 /* TODO: make sure we set everything back to the way it was, and context management!
6839 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6840 vcheckGLcall("glIntegerv");
6841 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6842 vcheckGLcall("glIntegerv");
6844 TRACE("Color fill to render targets may cause some graphics issues\n");
6845 if (pSurface == container->frontBuffer) {
6846 glDrawBuffer(GL_FRONT);
6848 glDrawBuffer(GL_BACK);
6851 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6852 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6854 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6856 if (container != NULL) {
6857 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6859 /* we can use GL_STENCIL_INDEX etc...*/
6862 if (container != NULL) {
6863 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6865 isRenderTarget = TRUE;
6867 /* TODO: drawing to GL_FRONT and GL_BACK */
6868 /* TODO: see if things can be speeded up by using the correct
6869 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6870 if (pRect == NULL) {
6873 width = surface->currentDesc.Width;
6874 height = surface->currentDesc.Height;
6878 width = pRect->x2 - left;
6879 height = pRect->y2 - top;
6882 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6883 /* Create a 'line' of color color, in the correct format for the surface */
6884 for (u = 0 ; u < width ; u ++) {
6889 if (isRenderTarget == FALSE) {
6890 glDescriptor *glDesc;
6891 IWineD3DSurface_PreLoad(pSurface);
6893 /* draw a block of the coloured line on the sufrace */
6894 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6895 for (v = 0 ; v< height;v++) {
6896 glTexSubImage2D(glDesc->target
6897 ,glDesc->level /* level */
6907 checkGLcall("glTexSubImage2D");
6909 glDisable(glDesc->target);
6911 /** FIXME: Using GLClear may be faster **/
6912 glRasterPos2i(left, top);
6913 glPixelZoom((float)width ,(float)height);
6914 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6915 checkGLcall("glDrawPixels");
6917 HeapFree(GetProcessHeap(), 0, data);
6923 /* rendertarget and deptth stencil functions */
6924 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6927 /* FIXME: Implelent RenderTargetIndex >0 */
6928 if(RenderTargetIndex > 0)
6929 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6931 *ppRenderTarget = This->renderTarget;
6932 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6933 /* Note inc ref on returned surface */
6934 if(*ppRenderTarget != NULL)
6935 IWineD3DSurface_AddRef(*ppRenderTarget);
6939 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6941 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6942 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6943 IWineD3DSwapChainImpl *Swapchain;
6946 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6948 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6949 if(hr != WINED3D_OK) {
6950 ERR("Can't get the swapchain\n");
6954 /* Make sure to release the swapchain */
6955 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6957 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6958 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6959 return WINED3DERR_INVALIDCALL;
6961 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6962 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6963 return WINED3DERR_INVALIDCALL;
6966 if(Swapchain->frontBuffer != Front) {
6967 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6969 if(Swapchain->frontBuffer)
6970 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6971 Swapchain->frontBuffer = Front;
6973 if(Swapchain->frontBuffer) {
6974 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6978 if(Back && !Swapchain->backBuffer) {
6979 /* We need memory for the back buffer array - only one back buffer this way */
6980 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6981 if(!Swapchain->backBuffer) {
6982 ERR("Out of memory\n");
6983 return E_OUTOFMEMORY;
6987 if(Swapchain->backBuffer[0] != Back) {
6988 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6990 if(!Swapchain->backBuffer[0]) {
6991 /* GL was told to draw to the front buffer at creation,
6994 glDrawBuffer(GL_BACK);
6995 checkGLcall("glDrawBuffer(GL_BACK)");
6996 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6997 Swapchain->presentParms.BackBufferCount = 1;
6999 /* That makes problems - disable for now */
7000 /* glDrawBuffer(GL_FRONT); */
7001 checkGLcall("glDrawBuffer(GL_FRONT)");
7002 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7003 Swapchain->presentParms.BackBufferCount = 0;
7007 if(Swapchain->backBuffer[0])
7008 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7009 Swapchain->backBuffer[0] = Back;
7011 if(Swapchain->backBuffer[0]) {
7012 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7014 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7022 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7024 *ppZStencilSurface = This->depthStencilBuffer;
7025 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7027 if(*ppZStencilSurface != NULL) {
7028 /* Note inc ref on returned surface */
7029 IWineD3DSurface_AddRef(*ppZStencilSurface);
7034 /* internal static helper functions */
7035 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7036 IWineD3DSurface *RenderSurface);
7038 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7040 HRESULT hr = WINED3D_OK;
7041 WINED3DVIEWPORT viewport;
7043 TRACE("(%p) Swapping rendertarget\n",This);
7044 if (RenderTargetIndex > 0) {
7045 FIXME("(%p) Render targets other than the first are not supported\n",This);
7046 RenderTargetIndex = 0;
7049 /* MSDN says that null disables the render target
7050 but a device must always be associated with a render target
7051 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7053 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7056 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7057 FIXME("Trying to set render target 0 to NULL\n");
7058 return WINED3DERR_INVALIDCALL;
7060 /* TODO: replace Impl* usage with interface usage */
7061 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7062 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);
7063 return WINED3DERR_INVALIDCALL;
7065 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7066 * builds, but I think wine counts as a 'debug' build for now.
7067 ******************************/
7068 /* If we are trying to set what we already have, don't bother */
7069 if (pRenderTarget == This->renderTarget) {
7070 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7072 /* Otherwise, set the render target up */
7074 if (FALSE == This->sceneEnded) {
7075 IWineD3DDevice_EndScene(iface);
7077 TRACE("clearing renderer\n");
7078 /* IWineD3DDeviceImpl_CleanRender(iface); */
7079 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7080 depending on the renter target implementation being used.
7081 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7082 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7083 stencil buffer and incure an extra memory overhead */
7084 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7087 if (SUCCEEDED(hr)) {
7088 /* Finally, reset the viewport as the MSDN states. */
7089 /* TODO: Replace impl usage */
7090 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7091 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7094 viewport.MaxZ = 1.0f;
7095 viewport.MinZ = 0.0f;
7096 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7098 FIXME("Unknown error setting the render target\n");
7100 This->sceneEnded = FALSE;
7104 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7106 HRESULT hr = WINED3D_OK;
7107 IWineD3DSurface *tmp;
7109 TRACE("(%p) Swapping z-buffer\n",This);
7111 if (pNewZStencil == This->stencilBufferTarget) {
7112 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7114 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7115 * depending on the renter target implementation being used.
7116 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7117 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7118 * stencil buffer and incure an extra memory overhead
7119 ******************************************************/
7122 tmp = This->stencilBufferTarget;
7123 This->stencilBufferTarget = pNewZStencil;
7124 /* should we be calling the parent or the wined3d surface? */
7125 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7126 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7128 /** TODO: glEnable/glDisable on depth/stencil depending on
7129 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7130 **********************************************************/
7137 #ifdef GL_VERSION_1_3
7138 /* Internal functions not in DirectX */
7139 /** TODO: move this off to the opengl context manager
7140 *(the swapchain doesn't need to know anything about offscreen rendering!)
7141 ****************************************************/
7143 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7147 TRACE("(%p), %p\n", This, swapchain);
7149 if (swapchain->win != swapchain->drawable) {
7150 /* Set everything back the way it ws */
7151 swapchain->render_ctx = swapchain->glCtx;
7152 swapchain->drawable = swapchain->win;
7157 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7158 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7162 unsigned int height;
7163 WINED3DFORMAT format;
7164 WINED3DSURFACE_DESC surfaceDesc;
7165 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7166 surfaceDesc.Width = &width;
7167 surfaceDesc.Height = &height;
7168 surfaceDesc.Format = &format;
7169 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7171 /* I need a get width/height function (and should do something with the format) */
7172 for (i = 0; i < CONTEXT_CACHE; ++i) {
7173 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7174 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7175 the pSurface can be set to 0 allowing it to be reused from cache **/
7176 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7177 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7178 *context = &This->contextCache[i];
7181 if (This->contextCache[i].Width == 0) {
7182 This->contextCache[i].pSurface = pSurface;
7183 This->contextCache[i].Width = width;
7184 This->contextCache[i].Height = height;
7185 *context = &This->contextCache[i];
7189 if (i == CONTEXT_CACHE) {
7190 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7191 glContext *dropContext = 0;
7192 for (i = 0; i < CONTEXT_CACHE; i++) {
7193 if (This->contextCache[i].usedcount < minUsage) {
7194 dropContext = &This->contextCache[i];
7195 minUsage = This->contextCache[i].usedcount;
7198 /* clean up the context (this doesn't work for ATI at the moment */
7200 glXDestroyContext(swapchain->display, dropContext->context);
7201 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7204 dropContext->Width = 0;
7205 dropContext->pSurface = pSurface;
7206 *context = dropContext;
7208 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7209 for (i = 0; i < CONTEXT_CACHE; i++) {
7210 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7214 if (*context != NULL)
7217 return E_OUTOFMEMORY;
7221 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7222 * the functionality needs splitting up so that we don't do more than we should do.
7223 * this only seems to impact performance a little.
7224 ******************************/
7225 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7226 IWineD3DSurface *RenderSurface) {
7227 HRESULT ret = WINED3DERR_INVALIDCALL;
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 #if 1 /* 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 */
7452 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7453 oldUpdateStateBlock = This->updateStateBlock;
7454 oldRecording= This->isRecordingState;
7455 This->isRecordingState = FALSE;
7456 This->updateStateBlock = This->stateBlock;
7457 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7459 This->isRecordingState = oldRecording;
7460 This->updateStateBlock = oldUpdateStateBlock;
7465 /* clean up the current rendertargets swapchain (if it belonged to one) */
7466 if (currentSwapchain != NULL) {
7467 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7470 /* Were done with the opengl context management, setup the rendertargets */
7472 tmp = This->renderTarget;
7473 This->renderTarget = RenderSurface;
7474 IWineD3DSurface_AddRef(This->renderTarget);
7475 IWineD3DSurface_Release(tmp);
7481 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7482 /* Check that the container is not a swapchain member */
7484 IWineD3DSwapChain *tmpSwapChain;
7485 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7486 This->renderUpsideDown = TRUE;
7488 This->renderUpsideDown = FALSE;
7489 IWineD3DSwapChain_Release(tmpSwapChain);
7491 /* Force updating the cull mode */
7492 TRACE("setting render state\n");
7493 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7494 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7496 /* Force updating projection matrix */
7497 This->last_was_rhw = FALSE;
7498 This->proj_valid = FALSE;
7506 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7507 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7512 if ( NULL != impSwapChain) {
7513 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7521 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7522 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7524 /* TODO: the use of Impl is deprecated. */
7525 /* some basic validation checks */
7526 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7528 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7530 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7531 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7532 return WINED3DERR_INVALIDCALL;
7534 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7535 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7536 return WINED3DERR_INVALIDCALL;
7538 /* TODO: make the cursor 'real' */
7540 This->xHotSpot = XHotSpot;
7541 This->yHotSpot = YHotSpot;
7546 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7548 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7550 This->xScreenSpace = XScreenSpace;
7551 This->yScreenSpace = YScreenSpace;
7557 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7559 TRACE("(%p) : visible(%d)\n", This, bShow);
7561 This->bCursorVisible = bShow;
7566 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7568 TRACE("(%p) : state (%lu)\n", This, This->state);
7569 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7570 switch (This->state) {
7573 case WINED3DERR_DEVICELOST:
7575 ResourceList *resourceList = This->resources;
7576 while (NULL != resourceList) {
7577 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7578 return WINED3DERR_DEVICENOTRESET;
7579 resourceList = resourceList->next;
7581 return WINED3DERR_DEVICELOST;
7583 case WINED3DERR_DRIVERINTERNALERROR:
7584 return WINED3DERR_DRIVERINTERNALERROR;
7588 return WINED3DERR_DRIVERINTERNALERROR;
7592 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7594 /** FIXME: Resource tracking needs to be done,
7595 * The closes we can do to this is set the priorities of all managed textures low
7596 * and then reset them.
7597 ***********************************************************/
7598 FIXME("(%p) : stub\n", This);
7602 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7604 /** FIXME: Resource trascking needs to be done.
7605 * in effect this pulls all non only default
7606 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7607 * and should clear down the context and set it up according to pPresentationParameters
7608 ***********************************************************/
7609 FIXME("(%p) : stub\n", This);
7613 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7615 /** FIXME: always true at the moment **/
7616 if(bEnableDialogs == FALSE) {
7617 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7623 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7625 TRACE("(%p) : pParameters %p\n", This, pParameters);
7627 *pParameters = This->createParms;
7631 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7632 IWineD3DSwapChain *swapchain;
7633 HRESULT hrc = WINED3D_OK;
7635 TRACE("Relaying to swapchain\n");
7637 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7638 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7639 IWineD3DSwapChain_Release(swapchain);
7644 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7645 IWineD3DSwapChain *swapchain;
7646 HRESULT hrc = WINED3D_OK;
7648 TRACE("Relaying to swapchain\n");
7650 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7651 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7652 IWineD3DSwapChain_Release(swapchain);
7658 /** ********************************************************
7659 * Notification functions
7660 ** ********************************************************/
7661 /** This function must be called in the release of a resource when ref == 0,
7662 * the contents of resource must still be correct,
7663 * any handels to other resource held by the caller must be closed
7664 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7665 *****************************************************/
7666 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7668 ResourceList* resourceList;
7670 TRACE("(%p) : resource %p\n", This, resource);
7672 EnterCriticalSection(&resourceStoreCriticalSection);
7674 /* add a new texture to the frot of the linked list */
7675 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7676 resourceList->resource = resource;
7678 /* Get the old head */
7679 resourceList->next = This->resources;
7681 This->resources = resourceList;
7682 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7685 LeaveCriticalSection(&resourceStoreCriticalSection);
7690 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7692 ResourceList* resourceList = NULL;
7693 ResourceList* previousResourceList = NULL;
7695 TRACE("(%p) : resource %p\n", This, resource);
7698 EnterCriticalSection(&resourceStoreCriticalSection);
7700 resourceList = This->resources;
7702 while (resourceList != NULL) {
7703 if(resourceList->resource == resource) break;
7704 previousResourceList = resourceList;
7705 resourceList = resourceList->next;
7708 if (resourceList == NULL) {
7709 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7711 LeaveCriticalSection(&resourceStoreCriticalSection);
7715 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7717 /* make sure we don't leave a hole in the list */
7718 if (previousResourceList != NULL) {
7719 previousResourceList->next = resourceList->next;
7721 This->resources = resourceList->next;
7725 LeaveCriticalSection(&resourceStoreCriticalSection);
7731 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7735 TRACE("(%p) : resource %p\n", This, resource);
7736 switch(IWineD3DResource_GetType(resource)){
7737 case WINED3DRTYPE_SURFACE:
7738 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7740 case WINED3DRTYPE_TEXTURE:
7741 case WINED3DRTYPE_CUBETEXTURE:
7742 case WINED3DRTYPE_VOLUMETEXTURE:
7743 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7744 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7745 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7746 This->stateBlock->textures[counter] = NULL;
7748 if (This->updateStateBlock != This->stateBlock ){
7749 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7750 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7751 This->updateStateBlock->textures[counter] = NULL;
7756 case WINED3DRTYPE_VOLUME:
7757 /* TODO: nothing really? */
7759 case WINED3DRTYPE_VERTEXBUFFER:
7760 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7763 TRACE("Cleaning up stream pointers\n");
7765 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7766 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7767 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7769 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7770 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7771 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7772 This->updateStateBlock->streamSource[streamNumber] = 0;
7773 /* Set changed flag? */
7776 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) */
7777 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7778 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7779 This->stateBlock->streamSource[streamNumber] = 0;
7782 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7783 else { /* This shouldn't happen */
7784 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7791 case WINED3DRTYPE_INDEXBUFFER:
7792 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7793 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7794 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7795 This->updateStateBlock->pIndexData = NULL;
7798 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7799 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7800 This->stateBlock->pIndexData = NULL;
7806 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7811 /* Remove the resoruce from the resourceStore */
7812 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7814 TRACE("Resource released\n");
7818 /**********************************************************
7819 * IWineD3DDevice VTbl follows
7820 **********************************************************/
7822 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7824 /*** IUnknown methods ***/
7825 IWineD3DDeviceImpl_QueryInterface,
7826 IWineD3DDeviceImpl_AddRef,
7827 IWineD3DDeviceImpl_Release,
7828 /*** IWineD3DDevice methods ***/
7829 IWineD3DDeviceImpl_GetParent,
7830 /*** Creation methods**/
7831 IWineD3DDeviceImpl_CreateVertexBuffer,
7832 IWineD3DDeviceImpl_CreateIndexBuffer,
7833 IWineD3DDeviceImpl_CreateStateBlock,
7834 IWineD3DDeviceImpl_CreateSurface,
7835 IWineD3DDeviceImpl_CreateTexture,
7836 IWineD3DDeviceImpl_CreateVolumeTexture,
7837 IWineD3DDeviceImpl_CreateVolume,
7838 IWineD3DDeviceImpl_CreateCubeTexture,
7839 IWineD3DDeviceImpl_CreateQuery,
7840 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7841 IWineD3DDeviceImpl_CreateVertexDeclaration,
7842 IWineD3DDeviceImpl_CreateVertexShader,
7843 IWineD3DDeviceImpl_CreatePixelShader,
7844 IWineD3DDeviceImpl_CreatePalette,
7845 /*** Odd functions **/
7846 IWineD3DDeviceImpl_Init3D,
7847 IWineD3DDeviceImpl_Uninit3D,
7848 IWineD3DDeviceImpl_EnumDisplayModes,
7849 IWineD3DDeviceImpl_EvictManagedResources,
7850 IWineD3DDeviceImpl_GetAvailableTextureMem,
7851 IWineD3DDeviceImpl_GetBackBuffer,
7852 IWineD3DDeviceImpl_GetCreationParameters,
7853 IWineD3DDeviceImpl_GetDeviceCaps,
7854 IWineD3DDeviceImpl_GetDirect3D,
7855 IWineD3DDeviceImpl_GetDisplayMode,
7856 IWineD3DDeviceImpl_SetDisplayMode,
7857 IWineD3DDeviceImpl_GetHWND,
7858 IWineD3DDeviceImpl_SetHWND,
7859 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7860 IWineD3DDeviceImpl_GetRasterStatus,
7861 IWineD3DDeviceImpl_GetSwapChain,
7862 IWineD3DDeviceImpl_Reset,
7863 IWineD3DDeviceImpl_SetDialogBoxMode,
7864 IWineD3DDeviceImpl_SetCursorProperties,
7865 IWineD3DDeviceImpl_SetCursorPosition,
7866 IWineD3DDeviceImpl_ShowCursor,
7867 IWineD3DDeviceImpl_TestCooperativeLevel,
7868 /*** Getters and setters **/
7869 IWineD3DDeviceImpl_SetClipPlane,
7870 IWineD3DDeviceImpl_GetClipPlane,
7871 IWineD3DDeviceImpl_SetClipStatus,
7872 IWineD3DDeviceImpl_GetClipStatus,
7873 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7874 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7875 IWineD3DDeviceImpl_SetDepthStencilSurface,
7876 IWineD3DDeviceImpl_GetDepthStencilSurface,
7877 IWineD3DDeviceImpl_SetFVF,
7878 IWineD3DDeviceImpl_GetFVF,
7879 IWineD3DDeviceImpl_SetGammaRamp,
7880 IWineD3DDeviceImpl_GetGammaRamp,
7881 IWineD3DDeviceImpl_SetIndices,
7882 IWineD3DDeviceImpl_GetIndices,
7883 IWineD3DDeviceImpl_SetLight,
7884 IWineD3DDeviceImpl_GetLight,
7885 IWineD3DDeviceImpl_SetLightEnable,
7886 IWineD3DDeviceImpl_GetLightEnable,
7887 IWineD3DDeviceImpl_SetMaterial,
7888 IWineD3DDeviceImpl_GetMaterial,
7889 IWineD3DDeviceImpl_SetNPatchMode,
7890 IWineD3DDeviceImpl_GetNPatchMode,
7891 IWineD3DDeviceImpl_SetPaletteEntries,
7892 IWineD3DDeviceImpl_GetPaletteEntries,
7893 IWineD3DDeviceImpl_SetPixelShader,
7894 IWineD3DDeviceImpl_GetPixelShader,
7895 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7896 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7897 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7898 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7899 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7900 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7901 IWineD3DDeviceImpl_SetRenderState,
7902 IWineD3DDeviceImpl_GetRenderState,
7903 IWineD3DDeviceImpl_SetRenderTarget,
7904 IWineD3DDeviceImpl_GetRenderTarget,
7905 IWineD3DDeviceImpl_SetFrontBackBuffers,
7906 IWineD3DDeviceImpl_SetSamplerState,
7907 IWineD3DDeviceImpl_GetSamplerState,
7908 IWineD3DDeviceImpl_SetScissorRect,
7909 IWineD3DDeviceImpl_GetScissorRect,
7910 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7911 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7912 IWineD3DDeviceImpl_SetStreamSource,
7913 IWineD3DDeviceImpl_GetStreamSource,
7914 IWineD3DDeviceImpl_SetStreamSourceFreq,
7915 IWineD3DDeviceImpl_GetStreamSourceFreq,
7916 IWineD3DDeviceImpl_SetTexture,
7917 IWineD3DDeviceImpl_GetTexture,
7918 IWineD3DDeviceImpl_SetTextureStageState,
7919 IWineD3DDeviceImpl_GetTextureStageState,
7920 IWineD3DDeviceImpl_SetTransform,
7921 IWineD3DDeviceImpl_GetTransform,
7922 IWineD3DDeviceImpl_SetVertexDeclaration,
7923 IWineD3DDeviceImpl_GetVertexDeclaration,
7924 IWineD3DDeviceImpl_SetVertexShader,
7925 IWineD3DDeviceImpl_GetVertexShader,
7926 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7927 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7928 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7929 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7930 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7931 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7932 IWineD3DDeviceImpl_SetViewport,
7933 IWineD3DDeviceImpl_GetViewport,
7934 IWineD3DDeviceImpl_MultiplyTransform,
7935 IWineD3DDeviceImpl_ValidateDevice,
7936 IWineD3DDeviceImpl_ProcessVertices,
7937 /*** State block ***/
7938 IWineD3DDeviceImpl_BeginStateBlock,
7939 IWineD3DDeviceImpl_EndStateBlock,
7940 /*** Scene management ***/
7941 IWineD3DDeviceImpl_BeginScene,
7942 IWineD3DDeviceImpl_EndScene,
7943 IWineD3DDeviceImpl_Present,
7944 IWineD3DDeviceImpl_Clear,
7946 IWineD3DDeviceImpl_DrawPrimitive,
7947 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7948 IWineD3DDeviceImpl_DrawPrimitiveUP,
7949 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7950 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7951 IWineD3DDeviceImpl_DrawRectPatch,
7952 IWineD3DDeviceImpl_DrawTriPatch,
7953 IWineD3DDeviceImpl_DeletePatch,
7954 IWineD3DDeviceImpl_ColorFill,
7955 IWineD3DDeviceImpl_UpdateTexture,
7956 IWineD3DDeviceImpl_UpdateSurface,
7957 IWineD3DDeviceImpl_CopyRects,
7958 IWineD3DDeviceImpl_StretchRect,
7959 IWineD3DDeviceImpl_GetRenderTargetData,
7960 IWineD3DDeviceImpl_GetFrontBufferData,
7961 /*** Internal use IWineD3DDevice methods ***/
7962 IWineD3DDeviceImpl_SetupTextureStates,
7963 /*** object tracking ***/
7964 IWineD3DDeviceImpl_ResourceReleased
7968 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7969 WINED3DRS_ALPHABLENDENABLE ,
7970 WINED3DRS_ALPHAFUNC ,
7971 WINED3DRS_ALPHAREF ,
7972 WINED3DRS_ALPHATESTENABLE ,
7974 WINED3DRS_COLORWRITEENABLE ,
7975 WINED3DRS_DESTBLEND ,
7976 WINED3DRS_DITHERENABLE ,
7977 WINED3DRS_FILLMODE ,
7978 WINED3DRS_FOGDENSITY ,
7980 WINED3DRS_FOGSTART ,
7981 WINED3DRS_LASTPIXEL ,
7982 WINED3DRS_SHADEMODE ,
7983 WINED3DRS_SRCBLEND ,
7984 WINED3DRS_STENCILENABLE ,
7985 WINED3DRS_STENCILFAIL ,
7986 WINED3DRS_STENCILFUNC ,
7987 WINED3DRS_STENCILMASK ,
7988 WINED3DRS_STENCILPASS ,
7989 WINED3DRS_STENCILREF ,
7990 WINED3DRS_STENCILWRITEMASK ,
7991 WINED3DRS_STENCILZFAIL ,
7992 WINED3DRS_TEXTUREFACTOR ,
8003 WINED3DRS_ZWRITEENABLE
8006 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8007 WINED3DTSS_ADDRESSW ,
8008 WINED3DTSS_ALPHAARG0 ,
8009 WINED3DTSS_ALPHAARG1 ,
8010 WINED3DTSS_ALPHAARG2 ,
8011 WINED3DTSS_ALPHAOP ,
8012 WINED3DTSS_BUMPENVLOFFSET ,
8013 WINED3DTSS_BUMPENVLSCALE ,
8014 WINED3DTSS_BUMPENVMAT00 ,
8015 WINED3DTSS_BUMPENVMAT01 ,
8016 WINED3DTSS_BUMPENVMAT10 ,
8017 WINED3DTSS_BUMPENVMAT11 ,
8018 WINED3DTSS_COLORARG0 ,
8019 WINED3DTSS_COLORARG1 ,
8020 WINED3DTSS_COLORARG2 ,
8021 WINED3DTSS_COLOROP ,
8022 WINED3DTSS_RESULTARG ,
8023 WINED3DTSS_TEXCOORDINDEX ,
8024 WINED3DTSS_TEXTURETRANSFORMFLAGS
8027 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8028 WINED3DSAMP_ADDRESSU ,
8029 WINED3DSAMP_ADDRESSV ,
8030 WINED3DSAMP_ADDRESSW ,
8031 WINED3DSAMP_BORDERCOLOR ,
8032 WINED3DSAMP_MAGFILTER ,
8033 WINED3DSAMP_MINFILTER ,
8034 WINED3DSAMP_MIPFILTER ,
8035 WINED3DSAMP_MIPMAPLODBIAS ,
8036 WINED3DSAMP_MAXMIPLEVEL ,
8037 WINED3DSAMP_MAXANISOTROPY ,
8038 WINED3DSAMP_SRGBTEXTURE ,
8039 WINED3DSAMP_ELEMENTINDEX
8042 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8044 WINED3DRS_AMBIENTMATERIALSOURCE ,
8045 WINED3DRS_CLIPPING ,
8046 WINED3DRS_CLIPPLANEENABLE ,
8047 WINED3DRS_COLORVERTEX ,
8048 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8049 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8050 WINED3DRS_FOGDENSITY ,
8052 WINED3DRS_FOGSTART ,
8053 WINED3DRS_FOGTABLEMODE ,
8054 WINED3DRS_FOGVERTEXMODE ,
8055 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8056 WINED3DRS_LIGHTING ,
8057 WINED3DRS_LOCALVIEWER ,
8058 WINED3DRS_MULTISAMPLEANTIALIAS ,
8059 WINED3DRS_MULTISAMPLEMASK ,
8060 WINED3DRS_NORMALIZENORMALS ,
8061 WINED3DRS_PATCHEDGESTYLE ,
8062 WINED3DRS_POINTSCALE_A ,
8063 WINED3DRS_POINTSCALE_B ,
8064 WINED3DRS_POINTSCALE_C ,
8065 WINED3DRS_POINTSCALEENABLE ,
8066 WINED3DRS_POINTSIZE ,
8067 WINED3DRS_POINTSIZE_MAX ,
8068 WINED3DRS_POINTSIZE_MIN ,
8069 WINED3DRS_POINTSPRITEENABLE ,
8070 WINED3DRS_RANGEFOGENABLE ,
8071 WINED3DRS_SPECULARMATERIALSOURCE ,
8072 WINED3DRS_TWEENFACTOR ,
8073 WINED3DRS_VERTEXBLEND
8076 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8077 WINED3DTSS_TEXCOORDINDEX ,
8078 WINED3DTSS_TEXTURETRANSFORMFLAGS
8081 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8082 WINED3DSAMP_DMAPOFFSET