d3d: Remove AddRef from IWineD3DDevice_GetDepthStencilSurface.
[wine.git] / dlls / wined3d / device.c
blob9812c6f40dc4945bf3214d21532b23925f6b7da6
1 /*
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
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
82 /* helper macros */
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
91 object->ref = 1; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
100 object->ref = 1; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
122 *pp##type = NULL; \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
131 *pp##type = NULL; \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * Utility functions follow
153 **********************************************************/
154 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
155 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
157 float quad_att;
158 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
162 glMatrixMode(GL_MODELVIEW);
163 glPushMatrix();
164 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
166 /* Diffuse: */
167 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
168 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
169 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
170 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
171 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
172 checkGLcall("glLightfv");
174 /* Specular */
175 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
176 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
177 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
178 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
179 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
180 checkGLcall("glLightfv");
182 /* Ambient */
183 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
184 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
185 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
186 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
187 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
188 checkGLcall("glLightfv");
190 /* Attenuation - Are these right? guessing... */
191 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
192 checkGLcall("glLightf");
193 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
194 checkGLcall("glLightf");
196 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
197 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
198 } else {
199 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
202 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
203 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
204 checkGLcall("glLightf");
206 switch (lightInfo->OriginalParms.Type) {
207 case WINED3DLIGHT_POINT:
208 /* Position */
209 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
210 checkGLcall("glLightfv");
211 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
212 checkGLcall("glLightf");
213 /* FIXME: Range */
214 break;
216 case WINED3DLIGHT_SPOT:
217 /* Position */
218 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
219 checkGLcall("glLightfv");
220 /* Direction */
221 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
222 checkGLcall("glLightfv");
223 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
224 checkGLcall("glLightf");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
226 checkGLcall("glLightf");
227 /* FIXME: Range */
228 break;
230 case WINED3DLIGHT_DIRECTIONAL:
231 /* Direction */
232 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
233 checkGLcall("glLightfv");
234 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
235 checkGLcall("glLightf");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
237 checkGLcall("glLightf");
238 break;
240 default:
241 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
244 /* Restore the modelview matrix */
245 glPopMatrix();
248 /**********************************************************
249 * GLSL helper functions follow
250 **********************************************************/
252 /** Attach a GLSL pixel or vertex shader object to the shader program */
253 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
256 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
257 if (This->stateBlock->glsl_program && shaderObj != 0) {
258 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
259 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
260 checkGLcall("glAttachObjectARB");
264 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
265 * It sets the programId on the current StateBlock (because it should be called
266 * inside of the DrawPrimitive() part of the render loop).
268 * If a program for the given combination does not exist, create one, and store
269 * the program in the list. If it creates a program, it will link the given
270 * objects, too.
272 * We keep the shader programs around on a list because linking
273 * shader objects together is an expensive operation. It's much
274 * faster to loop through a list of pre-compiled & linked programs
275 * each time that the application sets a new pixel or vertex shader
276 * than it is to re-link them together at that time.
278 * The list will be deleted in IWineD3DDevice::Release().
280 void set_glsl_shader_program(IWineD3DDevice *iface) {
282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
283 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
284 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
285 struct glsl_shader_prog_link *curLink = NULL;
286 struct glsl_shader_prog_link *newLink = NULL;
287 struct list *ptr = NULL;
288 GLhandleARB programId = 0;
289 int i;
290 char glsl_name[8];
292 ptr = list_head( &This->glsl_shader_progs );
293 while (ptr) {
294 /* At least one program exists - see if it matches our ps/vs combination */
295 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
296 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
297 /* Existing Program found, use it */
298 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
299 curLink->programId);
300 This->stateBlock->glsl_program = curLink;
301 return;
303 /* This isn't the entry we need - try the next one */
304 ptr = list_next( &This->glsl_shader_progs, ptr );
307 /* If we get to this point, then no matching program exists, so we create one */
308 programId = GL_EXTCALL(glCreateProgramObjectARB());
309 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
311 /* Allocate a new link for the list of programs */
312 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
313 newLink->programId = programId;
314 This->stateBlock->glsl_program = newLink;
316 /* Attach GLSL vshader */
317 if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
318 int i;
319 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
320 char tmp_name[10];
322 TRACE("Attaching vertex shader to GLSL program\n");
323 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
325 /* Bind vertex attributes to a corresponding index number to match
326 * the same index numbers as ARB_vertex_programs (makes loading
327 * vertex attributes simpler). With this method, we can use the
328 * exact same code to load the attributes later for both ARB and
329 * GLSL shaders.
331 * We have to do this here because we need to know the Program ID
332 * in order to make the bindings work, and it has to be done prior
333 * to linking the GLSL program. */
334 for (i = 0; i < max_attribs; ++i) {
335 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
336 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
338 checkGLcall("glBindAttribLocationARB");
339 newLink->vertexShader = vshader;
342 /* Attach GLSL pshader */
343 if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
344 TRACE("Attaching pixel shader to GLSL program\n");
345 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
346 newLink->pixelShader = pshader;
349 /* Link the program */
350 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
351 GL_EXTCALL(glLinkProgramARB(programId));
352 print_glsl_info_log(&GLINFO_LOCATION, programId);
353 list_add_head( &This->glsl_shader_progs, &newLink->entry);
355 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
356 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
357 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
358 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
360 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
361 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
362 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
363 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
366 return;
369 /** Detach the GLSL pixel or vertex shader object from the shader program */
370 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
374 if (shaderObj != 0 && programId != 0) {
375 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
376 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
377 checkGLcall("glDetachObjectARB");
381 /** Delete a GLSL shader program */
382 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
386 if (obj != 0) {
387 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
388 GL_EXTCALL(glDeleteObjectARB(obj));
389 checkGLcall("glDeleteObjectARB");
393 /** Delete the list of linked programs this shader is associated with.
394 * Also at this point, check to see if there are any objects left attached
395 * to each GLSL program. If not, delete the GLSL program object.
396 * This will be run when a device is released. */
397 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
399 struct list *ptr = NULL;
400 struct glsl_shader_prog_link *curLink = NULL;
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 int numAttached = 0;
404 int i;
405 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
406 (one pixel shader and one vertex shader at most) */
408 ptr = list_head( &This->glsl_shader_progs );
409 while (ptr) {
410 /* First, get the current item,
411 * save the link to the next pointer,
412 * detach and delete shader objects,
413 * then de-allocate the list item's memory */
414 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
415 ptr = list_next( &This->glsl_shader_progs, ptr );
417 /* See if this object is still attached to the program - it may have been detached already */
418 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
419 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
420 for (i = 0; i < numAttached; i++) {
421 detach_glsl_shader(iface, objList[i], curLink->programId);
424 delete_glsl_shader_program(iface, curLink->programId);
426 /* Free the uniform locations */
427 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
428 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
430 /* Free the memory for this list item */
431 HeapFree(GetProcessHeap(), 0, curLink);
436 /* Apply the current values to the specified texture stage */
437 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 float col[4];
441 union {
442 float f;
443 DWORD d;
444 } tmpvalue;
446 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
447 clamping, MIPLOD, etc. This will work for up to 16 samplers.
450 if (Sampler >= GL_LIMITS(sampler_stages)) {
451 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
452 return;
454 VTRACE(("Activating appropriate texture state %d\n", Sampler));
455 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
456 ENTER_GL();
457 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
458 checkGLcall("glActiveTextureARB");
459 LEAVE_GL();
460 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
461 } else if (Sampler > 0) {
462 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
463 return;
466 /* TODO: change this to a lookup table
467 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
468 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
469 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
470 especially when there are a number of groups of states. */
472 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
474 /* 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 */
475 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
476 /* these are the only two supported states that need to be applied */
477 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
478 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
479 #if 0 /* not supported at the moment */
480 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
481 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
482 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
483 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
484 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
485 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
486 APPLY_STATE(WINED3DTSS_RESULTARG);
487 APPLY_STATE(WINED3DTSS_CONSTANT);
488 #endif
489 /* a quick sanity check in case someone forgot to update this function */
490 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
491 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
493 #undef APPLY_STATE
495 /* apply any sampler states that always need applying */
496 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
497 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
498 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
499 GL_TEXTURE_LOD_BIAS_EXT,
500 tmpvalue.f);
501 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
504 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
505 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
506 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
508 /* TODO: NV_POINT_SPRITE */
509 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
510 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
511 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
512 glDisable(GL_POINT_SMOOTH);
514 /* Centre the texture on the vertex */
515 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
516 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
518 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
519 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
520 checkGLcall("glTexEnvf(...)");
521 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
522 glEnable( GL_POINT_SPRITE_ARB );
523 checkGLcall("glEnable(...)");
524 } else {
525 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
526 glDisable( GL_POINT_SPRITE_ARB );
527 checkGLcall("glEnable(...)");
531 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
534 /**********************************************************
535 * IUnknown parts follows
536 **********************************************************/
538 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
542 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
543 if (IsEqualGUID(riid, &IID_IUnknown)
544 || IsEqualGUID(riid, &IID_IWineD3DBase)
545 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
546 IUnknown_AddRef(iface);
547 *ppobj = This;
548 return S_OK;
550 *ppobj = NULL;
551 return E_NOINTERFACE;
554 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
556 ULONG refCount = InterlockedIncrement(&This->ref);
558 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
559 return refCount;
562 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
564 ULONG refCount = InterlockedDecrement(&This->ref);
566 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
568 if (!refCount) {
569 /* TODO: Clean up all the surfaces and textures! */
570 /* NOTE: You must release the parent if the object was created via a callback
571 ** ***************************/
573 /* Delete any GLSL shader programs that may exist */
574 if (This->vs_selected_mode == SHADER_GLSL ||
575 This->ps_selected_mode == SHADER_GLSL)
576 delete_glsl_shader_list(iface);
578 /* Release the update stateblock */
579 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
580 if(This->updateStateBlock != This->stateBlock)
581 FIXME("(%p) Something's still holding the Update stateblock\n",This);
583 This->updateStateBlock = NULL;
584 { /* because were not doing proper internal refcounts releasing the primary state block
585 causes recursion with the extra checks in ResourceReleased, to avoid this we have
586 to set this->stateBlock = NULL; first */
587 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
588 This->stateBlock = NULL;
590 /* Release the stateblock */
591 if(IWineD3DStateBlock_Release(stateBlock) > 0){
592 FIXME("(%p) Something's still holding the Update stateblock\n",This);
596 if (This->resources != NULL ) {
597 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
598 dumpResources(This->resources);
602 IWineD3D_Release(This->wineD3D);
603 This->wineD3D = NULL;
604 HeapFree(GetProcessHeap(), 0, This);
605 TRACE("Freed device %p\n", This);
606 This = NULL;
608 return refCount;
611 /**********************************************************
612 * IWineD3DDevice implementation follows
613 **********************************************************/
614 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
616 *pParent = This->parent;
617 IUnknown_AddRef(This->parent);
618 return WINED3D_OK;
621 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
622 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
623 GLenum error, glUsage;
624 DWORD vboUsage = object->resource.usage;
625 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
626 WARN("Creating a vbo failed once, not trying again\n");
627 return;
630 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
632 ENTER_GL();
633 /* Make sure that the gl error is cleared. Do not use checkGLcall
634 * here because checkGLcall just prints a fixme and continues. However,
635 * if an error during VBO creation occurs we can fall back to non-vbo operation
636 * with full functionality(but performance loss)
638 while(glGetError() != GL_NO_ERROR);
640 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
641 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
642 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
643 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
644 * to check if the rhw and color values are in the correct format.
647 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
648 error = glGetError();
649 if(object->vbo == 0 || error != GL_NO_ERROR) {
650 WARN("Failed to create a VBO with error %d\n", error);
651 goto error;
654 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
655 error = glGetError();
656 if(error != GL_NO_ERROR) {
657 WARN("Failed to bind the VBO, error %d\n", error);
658 goto error;
661 /* Transformed vertices are horribly inflexible. If the app specifies an
662 * vertex buffer with transformed vertices in default pool without DYNAMIC
663 * usage assume DYNAMIC usage and print a warning. The app will have to update
664 * the vertices regularily for them to be useful
666 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
667 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
668 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
669 vboUsage |= WINED3DUSAGE_DYNAMIC;
672 /* Don't use static, because dx apps tend to update the buffer
673 * quite often even if they specify 0 usage
675 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
676 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
677 TRACE("Gl usage = GL_STREAM_DRAW\n");
678 glUsage = GL_STREAM_DRAW_ARB;
679 break;
680 case D3DUSAGE_WRITEONLY:
681 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
682 glUsage = GL_DYNAMIC_DRAW_ARB;
683 break;
684 case D3DUSAGE_DYNAMIC:
685 TRACE("Gl usage = GL_STREAM_COPY\n");
686 glUsage = GL_STREAM_COPY_ARB;
687 break;
688 default:
689 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
690 glUsage = GL_DYNAMIC_COPY_ARB;
691 break;
694 /* Reserve memory for the buffer. The amount of data won't change
695 * so we are safe with calling glBufferData once with a NULL ptr and
696 * calling glBufferSubData on updates
698 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
699 error = glGetError();
700 if(error != GL_NO_ERROR) {
701 WARN("glBufferDataARB failed with error %d\n", error);
702 goto error;
705 LEAVE_GL();
707 return;
708 error:
709 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
710 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
711 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
712 object->vbo = 0;
713 object->Flags |= VBFLAG_VBOCREATEFAIL;
714 LEAVE_GL();
715 return;
718 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
719 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
720 IUnknown *parent) {
721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
722 IWineD3DVertexBufferImpl *object;
723 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
724 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
725 BOOL conv;
726 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
728 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
729 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
731 if(Size == 0) return WINED3DERR_INVALIDCALL;
733 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
734 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
736 object->fvf = FVF;
738 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
739 * drawStridedFast (half-life 2).
741 * Basically converting the vertices in the buffer is quite expensive, and observations
742 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
743 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
745 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
746 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
747 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
748 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
749 * dx7 apps.
750 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
751 * more. In this call we can convert dx7 buffers too.
753 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
754 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
755 (dxVersion > 7 || !conv) ) {
756 CreateVBO(object);
758 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
759 if(dxVersion == 7 && object->vbo) {
760 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
761 object->resource.allocatedMemory = NULL;
765 return WINED3D_OK;
768 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
769 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
770 HANDLE *sharedHandle, IUnknown *parent) {
771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
772 IWineD3DIndexBufferImpl *object;
773 TRACE("(%p) Creating index buffer\n", This);
775 /* Allocate the storage for the device */
776 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
778 /*TODO: use VBO's */
779 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
780 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
783 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
784 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
785 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
787 return WINED3D_OK;
790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 IWineD3DStateBlockImpl *object;
794 int i, j;
795 HRESULT temp_result;
797 D3DCREATEOBJECTINSTANCE(object, StateBlock)
798 object->blockType = Type;
800 /* Special case - Used during initialization to produce a placeholder stateblock
801 so other functions called can update a state block */
802 if (Type == WINED3DSBT_INIT) {
803 /* Don't bother increasing the reference count otherwise a device will never
804 be freed due to circular dependencies */
805 return WINED3D_OK;
808 temp_result = allocate_shader_constants(object);
809 if (WINED3D_OK != temp_result)
810 return temp_result;
812 /* Otherwise, might as well set the whole state block to the appropriate values */
813 if (This->stateBlock != NULL)
814 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
815 else
816 memset(object->streamFreq, 1, sizeof(object->streamFreq));
818 /* Reset the ref and type after kludging it */
819 object->wineD3DDevice = This;
820 object->ref = 1;
821 object->blockType = Type;
823 TRACE("Updating changed flags appropriate for type %d\n", Type);
825 if (Type == WINED3DSBT_ALL) {
827 TRACE("ALL => Pretend everything has changed\n");
828 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
830 } else if (Type == WINED3DSBT_PIXELSTATE) {
832 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
833 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
835 object->changed.pixelShader = TRUE;
837 /* Pixel Shader Constants */
838 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
839 object->changed.pixelShaderConstantsF[i] = TRUE;
840 for (i = 0; i < MAX_CONST_B; ++i)
841 object->changed.pixelShaderConstantsB[i] = TRUE;
842 for (i = 0; i < MAX_CONST_I; ++i)
843 object->changed.pixelShaderConstantsI[i] = TRUE;
845 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
846 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
848 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
849 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
850 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
853 for (j = 0 ; j < 16; j++) {
854 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
856 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
860 } else if (Type == WINED3DSBT_VERTEXSTATE) {
862 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
863 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
865 object->changed.vertexShader = TRUE;
867 /* Vertex Shader Constants */
868 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
869 object->changed.vertexShaderConstantsF[i] = TRUE;
870 for (i = 0; i < MAX_CONST_B; ++i)
871 object->changed.vertexShaderConstantsB[i] = TRUE;
872 for (i = 0; i < MAX_CONST_I; ++i)
873 object->changed.vertexShaderConstantsI[i] = TRUE;
875 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
876 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
878 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
879 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
880 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
883 for (j = 0 ; j < 16; j++){
884 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
885 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
889 /* Duplicate light chain */
891 PLIGHTINFOEL *src = NULL;
892 PLIGHTINFOEL *dst = NULL;
893 PLIGHTINFOEL *newEl = NULL;
894 src = This->stateBlock->lights;
895 object->lights = NULL;
898 while (src) {
899 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
900 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
901 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
902 newEl->prev = dst;
903 newEl->changed = TRUE;
904 newEl->enabledChanged = TRUE;
905 if (dst == NULL) {
906 object->lights = newEl;
907 } else {
908 dst->next = newEl;
910 dst = newEl;
911 src = src->next;
916 } else {
917 FIXME("Unrecognized state block type %d\n", Type);
920 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
921 return WINED3D_OK;
925 /* ************************************
926 MSDN:
927 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
929 Discard
930 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
932 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.
934 ******************************** */
936 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) {
937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
938 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
939 unsigned int pow2Width, pow2Height;
940 unsigned int Size = 1;
941 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
942 TRACE("(%p) Create surface\n",This);
944 /** FIXME: Check ranges on the inputs are valid
945 * MSDN
946 * MultisampleQuality
947 * [in] Quality level. The valid range is between zero and one less than the level
948 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
949 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
950 * values of paired render targets, depth stencil surfaces, and the MultiSample type
951 * must all match.
952 *******************************/
956 * TODO: Discard MSDN
957 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
959 * If this flag is set, the contents of the depth stencil buffer will be
960 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
961 * with a different depth surface.
963 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
964 ***************************/
966 if(MultisampleQuality < 0) {
967 FIXME("Invalid multisample level %d\n", MultisampleQuality);
968 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
971 if(MultisampleQuality > 0) {
972 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
973 MultisampleQuality=0;
976 /** FIXME: Check that the format is supported
977 * by the device.
978 *******************************/
980 /* Non-power2 support */
981 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
982 pow2Width = Width;
983 pow2Height = Height;
984 } else {
985 /* Find the nearest pow2 match */
986 pow2Width = pow2Height = 1;
987 while (pow2Width < Width) pow2Width <<= 1;
988 while (pow2Height < Height) pow2Height <<= 1;
991 if (pow2Width > Width || pow2Height > Height) {
992 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
993 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
994 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
995 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
996 This, Width, Height);
997 return WINED3DERR_NOTAVAILABLE;
1001 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1002 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1003 * space!
1004 *********************************/
1005 if (WINED3DFMT_UNKNOWN == Format) {
1006 Size = 0;
1007 } else if (Format == WINED3DFMT_DXT1) {
1008 /* DXT1 is half byte per pixel */
1009 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1011 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1012 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1013 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1014 } else {
1015 /* The pitch is a multiple of 4 bytes */
1016 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1017 Size *= pow2Height;
1020 /** Create and initialise the surface resource **/
1021 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1022 /* "Standalone" surface */
1023 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1025 object->currentDesc.Width = Width;
1026 object->currentDesc.Height = Height;
1027 object->currentDesc.MultiSampleType = MultiSample;
1028 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1030 /* Setup some glformat defaults */
1031 object->glDescription.glFormat = tableEntry->glFormat;
1032 object->glDescription.glFormatInternal = tableEntry->glInternal;
1033 object->glDescription.glType = tableEntry->glType;
1035 object->glDescription.textureName = 0;
1036 object->glDescription.level = Level;
1037 object->glDescription.target = GL_TEXTURE_2D;
1039 /* Internal data */
1040 object->pow2Width = pow2Width;
1041 object->pow2Height = pow2Height;
1043 /* Flags */
1044 object->Flags = 0; /* We start without flags set */
1045 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1046 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1047 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1048 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1051 if (WINED3DFMT_UNKNOWN != Format) {
1052 object->bytesPerPixel = tableEntry->bpp;
1053 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1054 object->pow2Size *= pow2Height;
1055 } else {
1056 object->bytesPerPixel = 0;
1057 object->pow2Size = 0;
1060 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1062 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1064 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1065 * this function is too deep to need to care about things like this.
1066 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1067 * ****************************************/
1068 switch(Pool) {
1069 case WINED3DPOOL_SCRATCH:
1070 if(!Lockable)
1071 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1072 which are mutually exclusive, setting lockable to true\n");
1073 Lockable = TRUE;
1074 break;
1075 case WINED3DPOOL_SYSTEMMEM:
1076 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1077 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1078 case WINED3DPOOL_MANAGED:
1079 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1080 Usage of DYNAMIC which are mutually exclusive, not doing \
1081 anything just telling you.\n");
1082 break;
1083 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1084 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1085 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1086 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1087 break;
1088 default:
1089 FIXME("(%p) Unknown pool %d\n", This, Pool);
1090 break;
1093 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1094 FIXME("Trying to create a render target that isn't in the default pool\n");
1097 /* mark the texture as dirty so that it gets loaded first time around*/
1098 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1099 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1100 This, Width, Height, Format, debug_d3dformat(Format),
1101 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1103 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1104 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1105 This->ddraw_primary = (IWineD3DSurface *) object;
1107 /* Look at the implementation and set the correct Vtable */
1108 switch(Impl) {
1109 case SURFACE_OPENGL:
1110 /* Nothing to do, it's set already */
1111 break;
1113 case SURFACE_GDI:
1114 object->lpVtbl = &IWineGDISurface_Vtbl;
1115 break;
1117 default:
1118 /* To be sure to catch this */
1119 ERR("Unknown requested surface implementation %d!\n", Impl);
1120 IWineD3DSurface_Release((IWineD3DSurface *) object);
1121 return WINED3DERR_INVALIDCALL;
1124 /* Call the private setup routine */
1125 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1129 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1130 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1131 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1132 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1135 IWineD3DTextureImpl *object;
1136 unsigned int i;
1137 UINT tmpW;
1138 UINT tmpH;
1139 HRESULT hr;
1140 unsigned int pow2Width;
1141 unsigned int pow2Height;
1144 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1145 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1146 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1148 /* TODO: It should only be possible to create textures for formats
1149 that are reported as supported */
1150 if (WINED3DFMT_UNKNOWN >= Format) {
1151 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1152 return WINED3DERR_INVALIDCALL;
1155 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1156 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1157 object->width = Width;
1158 object->height = Height;
1160 /** Non-power2 support **/
1161 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1162 pow2Width = Width;
1163 pow2Height = Height;
1164 } else {
1165 /* Find the nearest pow2 match */
1166 pow2Width = pow2Height = 1;
1167 while (pow2Width < Width) pow2Width <<= 1;
1168 while (pow2Height < Height) pow2Height <<= 1;
1171 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1172 /* Precalculated scaling for 'faked' non power of two texture coords */
1173 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1174 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1175 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1177 /* Calculate levels for mip mapping */
1178 if (Levels == 0) {
1179 TRACE("calculating levels %d\n", object->baseTexture.levels);
1180 object->baseTexture.levels++;
1181 tmpW = Width;
1182 tmpH = Height;
1183 while (tmpW > 1 || tmpH > 1) {
1184 tmpW = max(1, tmpW >> 1);
1185 tmpH = max(1, tmpH >> 1);
1186 object->baseTexture.levels++;
1188 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1191 /* Generate all the surfaces */
1192 tmpW = Width;
1193 tmpH = Height;
1194 for (i = 0; i < object->baseTexture.levels; i++)
1196 /* use the callback to create the texture surface */
1197 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1198 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1199 FIXME("Failed to create surface %p\n", object);
1200 /* clean up */
1201 object->surfaces[i] = NULL;
1202 IWineD3DTexture_Release((IWineD3DTexture *)object);
1204 *ppTexture = NULL;
1205 return hr;
1208 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1209 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1210 /* calculate the next mipmap level */
1211 tmpW = max(1, tmpW >> 1);
1212 tmpH = max(1, tmpH >> 1);
1215 TRACE("(%p) : Created texture %p\n", This, object);
1216 return WINED3D_OK;
1219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1220 UINT Width, UINT Height, UINT Depth,
1221 UINT Levels, DWORD Usage,
1222 WINED3DFORMAT Format, WINED3DPOOL Pool,
1223 IWineD3DVolumeTexture **ppVolumeTexture,
1224 HANDLE *pSharedHandle, IUnknown *parent,
1225 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1228 IWineD3DVolumeTextureImpl *object;
1229 unsigned int i;
1230 UINT tmpW;
1231 UINT tmpH;
1232 UINT tmpD;
1234 /* TODO: It should only be possible to create textures for formats
1235 that are reported as supported */
1236 if (WINED3DFMT_UNKNOWN >= Format) {
1237 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1238 return WINED3DERR_INVALIDCALL;
1241 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1242 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1244 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1245 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1247 object->width = Width;
1248 object->height = Height;
1249 object->depth = Depth;
1251 /* Calculate levels for mip mapping */
1252 if (Levels == 0) {
1253 object->baseTexture.levels++;
1254 tmpW = Width;
1255 tmpH = Height;
1256 tmpD = Depth;
1257 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1258 tmpW = max(1, tmpW >> 1);
1259 tmpH = max(1, tmpH >> 1);
1260 tmpD = max(1, tmpD >> 1);
1261 object->baseTexture.levels++;
1263 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1266 /* Generate all the surfaces */
1267 tmpW = Width;
1268 tmpH = Height;
1269 tmpD = Depth;
1271 for (i = 0; i < object->baseTexture.levels; i++)
1273 /* Create the volume */
1274 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1275 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1277 /* Set its container to this object */
1278 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1280 /* calcualte the next mipmap level */
1281 tmpW = max(1, tmpW >> 1);
1282 tmpH = max(1, tmpH >> 1);
1283 tmpD = max(1, tmpD >> 1);
1286 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1287 TRACE("(%p) : Created volume texture %p\n", This, object);
1288 return WINED3D_OK;
1291 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1292 UINT Width, UINT Height, UINT Depth,
1293 DWORD Usage,
1294 WINED3DFORMAT Format, WINED3DPOOL Pool,
1295 IWineD3DVolume** ppVolume,
1296 HANDLE* pSharedHandle, IUnknown *parent) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1300 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1302 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1304 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1305 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1307 object->currentDesc.Width = Width;
1308 object->currentDesc.Height = Height;
1309 object->currentDesc.Depth = Depth;
1310 object->bytesPerPixel = formatDesc->bpp;
1312 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1313 object->lockable = TRUE;
1314 object->locked = FALSE;
1315 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1316 object->dirty = TRUE;
1318 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1322 UINT Levels, DWORD Usage,
1323 WINED3DFORMAT Format, WINED3DPOOL Pool,
1324 IWineD3DCubeTexture **ppCubeTexture,
1325 HANDLE *pSharedHandle, IUnknown *parent,
1326 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1330 unsigned int i, j;
1331 UINT tmpW;
1332 HRESULT hr;
1333 unsigned int pow2EdgeLength = EdgeLength;
1335 /* TODO: It should only be possible to create textures for formats
1336 that are reported as supported */
1337 if (WINED3DFMT_UNKNOWN >= Format) {
1338 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1339 return WINED3DERR_INVALIDCALL;
1342 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1343 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1345 TRACE("(%p) Create Cube Texture\n", This);
1347 /** Non-power2 support **/
1349 /* Find the nearest pow2 match */
1350 pow2EdgeLength = 1;
1351 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1353 object->edgeLength = EdgeLength;
1354 /* TODO: support for native non-power 2 */
1355 /* Precalculated scaling for 'faked' non power of two texture coords */
1356 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1358 /* Calculate levels for mip mapping */
1359 if (Levels == 0) {
1360 object->baseTexture.levels++;
1361 tmpW = EdgeLength;
1362 while (tmpW > 1) {
1363 tmpW = max(1, tmpW >> 1);
1364 object->baseTexture.levels++;
1366 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1369 /* Generate all the surfaces */
1370 tmpW = EdgeLength;
1371 for (i = 0; i < object->baseTexture.levels; i++) {
1373 /* Create the 6 faces */
1374 for (j = 0; j < 6; j++) {
1376 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1377 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1379 if(hr!= WINED3D_OK) {
1380 /* clean up */
1381 int k;
1382 int l;
1383 for (l = 0; l < j; l++) {
1384 IWineD3DSurface_Release(object->surfaces[j][i]);
1386 for (k = 0; k < i; k++) {
1387 for (l = 0; l < 6; l++) {
1388 IWineD3DSurface_Release(object->surfaces[l][j]);
1392 FIXME("(%p) Failed to create surface\n",object);
1393 HeapFree(GetProcessHeap(),0,object);
1394 *ppCubeTexture = NULL;
1395 return hr;
1397 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1398 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1400 tmpW = max(1, tmpW >> 1);
1403 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1404 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1405 return WINED3D_OK;
1408 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1410 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1412 if (NULL == ppQuery) {
1413 /* Just a check to see if we support this type of query */
1414 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1415 switch(Type) {
1416 case WINED3DQUERYTYPE_OCCLUSION:
1417 TRACE("(%p) occlusion query\n", This);
1418 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1419 hr = WINED3D_OK;
1420 else
1421 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1422 break;
1423 case WINED3DQUERYTYPE_VCACHE:
1424 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1425 case WINED3DQUERYTYPE_VERTEXSTATS:
1426 case WINED3DQUERYTYPE_EVENT:
1427 case WINED3DQUERYTYPE_TIMESTAMP:
1428 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1429 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1430 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1431 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1432 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1433 case WINED3DQUERYTYPE_PIXELTIMINGS:
1434 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1435 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1436 default:
1437 FIXME("(%p) Unhandled query type %d\n", This, Type);
1439 return hr;
1442 D3DCREATEOBJECTINSTANCE(object, Query)
1443 object->type = Type;
1444 /* allocated the 'extended' data based on the type of query requested */
1445 switch(Type){
1446 case WINED3DQUERYTYPE_OCCLUSION:
1447 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1448 TRACE("(%p) Allocating data for an occlusion query\n", This);
1449 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1450 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1451 break;
1453 case WINED3DQUERYTYPE_VCACHE:
1454 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1455 case WINED3DQUERYTYPE_VERTEXSTATS:
1456 case WINED3DQUERYTYPE_EVENT:
1457 case WINED3DQUERYTYPE_TIMESTAMP:
1458 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1459 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1460 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1461 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1462 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1463 case WINED3DQUERYTYPE_PIXELTIMINGS:
1464 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1465 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1466 default:
1467 object->extendedData = 0;
1468 FIXME("(%p) Unhandled query type %d\n",This , Type);
1470 TRACE("(%p) : Created Query %p\n", This, object);
1471 return WINED3D_OK;
1474 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1475 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1476 IUnknown* parent,
1477 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1478 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1481 HDC hDc;
1482 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1483 int num;
1484 XVisualInfo template;
1485 GLXContext oldContext;
1486 Drawable oldDrawable;
1487 HRESULT hr = WINED3D_OK;
1489 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1491 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1492 * does a device hold a reference to a swap chain giving them a lifetime of the device
1493 * or does the swap chain notify the device of its destruction.
1494 *******************************/
1496 /* Check the params */
1497 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1498 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1499 return WINED3DERR_INVALIDCALL;
1500 } else if (*pPresentationParameters->BackBufferCount > 1) {
1501 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");
1504 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1506 /*********************
1507 * Lookup the window Handle and the relating X window handle
1508 ********************/
1510 /* Setup hwnd we are using, plus which display this equates to */
1511 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1512 if (!object->win_handle) {
1513 object->win_handle = This->createParms.hFocusWindow;
1516 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1517 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1518 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1519 return WINED3DERR_NOTAVAILABLE;
1521 hDc = GetDC(object->win_handle);
1522 object->display = get_display(hDc);
1523 ReleaseDC(object->win_handle, hDc);
1524 TRACE("Using a display of %p %p\n", object->display, hDc);
1526 if (NULL == object->display || NULL == hDc) {
1527 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1528 return WINED3DERR_NOTAVAILABLE;
1531 if (object->win == 0) {
1532 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1533 return WINED3DERR_NOTAVAILABLE;
1536 * Create an opengl context for the display visual
1537 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1538 * use different properties after that point in time. FIXME: How to handle when requested format
1539 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1540 * it chooses is identical to the one already being used!
1541 **********************************/
1543 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1544 ENTER_GL();
1546 /* Create a new context for this swapchain */
1547 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1548 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1549 (or the best possible if none is requested) */
1550 TRACE("Found x visual ID : %ld\n", template.visualid);
1552 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1553 if (NULL == object->visInfo) {
1554 ERR("cannot really get XVisual\n");
1555 LEAVE_GL();
1556 return WINED3DERR_NOTAVAILABLE;
1557 } else {
1558 int n, value;
1559 /* Write out some debug info about the visual/s */
1560 TRACE("Using x visual ID : %ld\n", template.visualid);
1561 TRACE(" visual info: %p\n", object->visInfo);
1562 TRACE(" num items : %d\n", num);
1563 for (n = 0;n < num; n++) {
1564 TRACE("=====item=====: %d\n", n + 1);
1565 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1566 TRACE(" screen : %d\n", object->visInfo[n].screen);
1567 TRACE(" depth : %u\n", object->visInfo[n].depth);
1568 TRACE(" class : %d\n", object->visInfo[n].class);
1569 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1570 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1571 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1572 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1573 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1574 /* log some extra glx info */
1575 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1576 TRACE(" gl_aux_buffers : %d\n", value);
1577 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1578 TRACE(" gl_buffer_size : %d\n", value);
1579 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1580 TRACE(" gl_red_size : %d\n", value);
1581 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1582 TRACE(" gl_green_size : %d\n", value);
1583 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1584 TRACE(" gl_blue_size : %d\n", value);
1585 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1586 TRACE(" gl_alpha_size : %d\n", value);
1587 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1588 TRACE(" gl_depth_size : %d\n", value);
1589 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1590 TRACE(" gl_stencil_size : %d\n", value);
1592 /* Now choose a similar visual ID*/
1594 #ifdef USE_CONTEXT_MANAGER
1596 /** TODO: use a context mamager **/
1597 #endif
1600 IWineD3DSwapChain *implSwapChain;
1601 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1602 /* The first time around we create the context that is shared with all other swapchains and render targets */
1603 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1604 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1605 } else {
1607 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1608 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1609 /* and create a new context with the implicit swapchains context as the shared context */
1610 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1611 IWineD3DSwapChain_Release(implSwapChain);
1615 /* Cleanup */
1616 XFree(object->visInfo);
1617 object->visInfo = NULL;
1619 LEAVE_GL();
1621 if (!object->glCtx) {
1622 ERR("Failed to create GLX context\n");
1623 return WINED3DERR_NOTAVAILABLE;
1624 } else {
1625 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1626 object->win_handle, object->glCtx, object->win, object->visInfo);
1629 /*********************
1630 * Windowed / Fullscreen
1631 *******************/
1634 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1635 * so we should really check to see if there is a fullscreen swapchain already
1636 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1637 **************************************/
1639 if (!*(pPresentationParameters->Windowed)) {
1641 DEVMODEW devmode;
1642 HDC hdc;
1643 int bpp = 0;
1645 /* Get info on the current display setup */
1646 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1647 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1648 DeleteDC(hdc);
1650 /* Change the display settings */
1651 memset(&devmode, 0, sizeof(DEVMODEW));
1652 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1653 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1654 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1655 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1656 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1657 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1659 /* Make popup window */
1660 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1661 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1662 *(pPresentationParameters->BackBufferWidth),
1663 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1665 /* For GetDisplayMode */
1666 This->ddraw_width = devmode.dmPelsWidth;
1667 This->ddraw_height = devmode.dmPelsHeight;
1668 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1672 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1673 * then the corresponding dimension of the client area of the hDeviceWindow
1674 * (or the focus window, if hDeviceWindow is NULL) is taken.
1675 **********************/
1677 if (*(pPresentationParameters->Windowed) &&
1678 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1679 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1681 RECT Rect;
1682 GetClientRect(object->win_handle, &Rect);
1684 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1685 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1686 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1688 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1689 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1690 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1694 /*********************
1695 * finish off parameter initialization
1696 *******************/
1698 /* Put the correct figures in the presentation parameters */
1699 TRACE("Copying across presentation parameters\n");
1700 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1701 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1702 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1703 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1704 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1705 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1706 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1707 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1708 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1709 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1710 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1711 object->presentParms.Flags = *(pPresentationParameters->Flags);
1712 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1713 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1716 /*********************
1717 * Create the back, front and stencil buffers
1718 *******************/
1720 TRACE("calling rendertarget CB\n");
1721 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1722 object->presentParms.BackBufferWidth,
1723 object->presentParms.BackBufferHeight,
1724 object->presentParms.BackBufferFormat,
1725 object->presentParms.MultiSampleType,
1726 object->presentParms.MultiSampleQuality,
1727 TRUE /* Lockable */,
1728 &object->frontBuffer,
1729 NULL /* pShared (always null)*/);
1730 if (object->frontBuffer != NULL)
1731 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1733 if(object->presentParms.BackBufferCount > 0) {
1734 int i;
1736 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1737 if(!object->backBuffer) {
1738 ERR("Out of memory\n");
1740 if (object->frontBuffer) {
1741 IUnknown *bufferParent;
1742 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1743 IUnknown_Release(bufferParent); /* once for the get parent */
1744 if (IUnknown_Release(bufferParent) > 0) {
1745 FIXME("(%p) Something's still holding the front buffer\n",This);
1748 HeapFree(GetProcessHeap(), 0, object);
1749 return E_OUTOFMEMORY;
1752 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1753 TRACE("calling rendertarget CB\n");
1754 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1755 object->presentParms.BackBufferWidth,
1756 object->presentParms.BackBufferHeight,
1757 object->presentParms.BackBufferFormat,
1758 object->presentParms.MultiSampleType,
1759 object->presentParms.MultiSampleQuality,
1760 TRUE /* Lockable */,
1761 &object->backBuffer[i],
1762 NULL /* pShared (always null)*/);
1763 if(hr == WINED3D_OK && object->backBuffer[i]) {
1764 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1765 } else {
1766 break;
1769 } else {
1770 object->backBuffer = NULL;
1773 if (object->backBuffer != NULL) {
1774 ENTER_GL();
1775 glDrawBuffer(GL_BACK);
1776 checkGLcall("glDrawBuffer(GL_BACK)");
1777 LEAVE_GL();
1778 } else {
1779 /* Single buffering - draw to front buffer */
1780 ENTER_GL();
1781 glDrawBuffer(GL_FRONT);
1782 checkGLcall("glDrawBuffer(GL_FRONT)");
1783 LEAVE_GL();
1786 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1787 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1788 TRACE("Creating depth stencil buffer\n");
1789 if (This->depthStencilBuffer == NULL ) {
1790 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1791 object->presentParms.BackBufferWidth,
1792 object->presentParms.BackBufferHeight,
1793 object->presentParms.AutoDepthStencilFormat,
1794 object->presentParms.MultiSampleType,
1795 object->presentParms.MultiSampleQuality,
1796 FALSE /* FIXME: Discard */,
1797 &This->depthStencilBuffer,
1798 NULL /* pShared (always null)*/ );
1799 if (This->depthStencilBuffer != NULL)
1800 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1803 /** TODO: A check on width, height and multisample types
1804 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1805 ****************************/
1806 object->wantsDepthStencilBuffer = TRUE;
1807 } else {
1808 object->wantsDepthStencilBuffer = FALSE;
1811 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1814 /*********************
1815 * init the default renderTarget management
1816 *******************/
1817 object->drawable = object->win;
1818 object->render_ctx = object->glCtx;
1820 if (hr == WINED3D_OK) {
1821 /*********************
1822 * Setup some defaults and clear down the buffers
1823 *******************/
1824 ENTER_GL();
1825 /** save current context and drawable **/
1826 oldContext = glXGetCurrentContext();
1827 oldDrawable = glXGetCurrentDrawable();
1829 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1830 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1831 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1833 checkGLcall("glXMakeCurrent");
1835 TRACE("Setting up the screen\n");
1836 /* Clear the screen */
1837 glClearColor(1.0, 0.0, 0.0, 0.0);
1838 checkGLcall("glClearColor");
1839 glClearIndex(0);
1840 glClearDepth(1);
1841 glClearStencil(0xffff);
1843 checkGLcall("glClear");
1845 glColor3f(1.0, 1.0, 1.0);
1846 checkGLcall("glColor3f");
1848 glEnable(GL_LIGHTING);
1849 checkGLcall("glEnable");
1851 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1852 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1854 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1855 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1857 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1858 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1860 /* switch back to the original context (if there was one)*/
1861 if (This->swapchains) {
1862 /** TODO: restore the context and drawable **/
1863 glXMakeCurrent(object->display, oldDrawable, oldContext);
1866 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1867 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1868 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1869 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1870 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1872 LEAVE_GL();
1874 TRACE("Set swapchain to %p\n", object);
1875 } else { /* something went wrong so clean up */
1876 IUnknown* bufferParent;
1877 if (object->frontBuffer) {
1879 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1880 IUnknown_Release(bufferParent); /* once for the get parent */
1881 if (IUnknown_Release(bufferParent) > 0) {
1882 FIXME("(%p) Something's still holding the front buffer\n",This);
1885 if (object->backBuffer) {
1886 int i;
1887 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1888 if(object->backBuffer[i]) {
1889 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1890 IUnknown_Release(bufferParent); /* once for the get parent */
1891 if (IUnknown_Release(bufferParent) > 0) {
1892 FIXME("(%p) Something's still holding the back buffer\n",This);
1896 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1897 object->backBuffer = NULL;
1899 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1900 /* Clean up the context */
1901 /* check that we are the current context first (we shouldn't be though!) */
1902 if (object->glCtx != 0) {
1903 if(glXGetCurrentContext() == object->glCtx) {
1904 glXMakeCurrent(object->display, None, NULL);
1906 glXDestroyContext(object->display, object->glCtx);
1908 HeapFree(GetProcessHeap(), 0, object);
1912 return hr;
1915 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1916 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1918 TRACE("(%p)\n", This);
1920 return This->NumberOfSwapChains;
1923 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1925 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1927 if(iSwapChain < This->NumberOfSwapChains) {
1928 *pSwapChain = This->swapchains[iSwapChain];
1929 IWineD3DSwapChain_AddRef(*pSwapChain);
1930 TRACE("(%p) returning %p\n", This, *pSwapChain);
1931 return WINED3D_OK;
1932 } else {
1933 TRACE("Swapchain out of range\n");
1934 *pSwapChain = NULL;
1935 return WINED3DERR_INVALIDCALL;
1939 /*****
1940 * Vertex Declaration
1941 *****/
1942 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1944 IWineD3DVertexDeclarationImpl *object = NULL;
1945 HRESULT hr = WINED3D_OK;
1946 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1947 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1948 object->allFVF = 0;
1950 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1952 return hr;
1955 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1956 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1958 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1959 HRESULT hr = WINED3D_OK;
1960 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1961 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1963 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1965 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1966 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1967 if (pDeclaration != NULL) {
1968 IWineD3DVertexDeclaration *vertexDeclaration;
1969 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1970 if (WINED3D_OK == hr) {
1971 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1972 object->vertexDeclaration = vertexDeclaration;
1973 } else {
1974 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1975 IWineD3DVertexShader_Release(*ppVertexShader);
1976 return WINED3DERR_INVALIDCALL;
1980 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1982 if (WINED3D_OK != hr) {
1983 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1984 IWineD3DVertexShader_Release(*ppVertexShader);
1985 return WINED3DERR_INVALIDCALL;
1988 #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. */
1989 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1990 /* Foo */
1991 } else {
1992 /* Bar */
1995 #endif
1997 return WINED3D_OK;
2000 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2002 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2003 HRESULT hr = WINED3D_OK;
2005 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2006 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2007 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2008 if (WINED3D_OK == hr) {
2009 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2010 } else {
2011 WARN("(%p) : Failed to create pixel shader\n", This);
2014 return hr;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2019 IWineD3DPaletteImpl *object;
2020 HRESULT hr;
2021 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2023 /* Create the new object */
2024 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2025 if(!object) {
2026 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2027 return E_OUTOFMEMORY;
2030 object->lpVtbl = &IWineD3DPalette_Vtbl;
2031 object->ref = 1;
2032 object->Flags = Flags;
2033 object->parent = Parent;
2034 object->wineD3DDevice = This;
2035 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2037 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2039 if(!object->hpal) {
2040 HeapFree( GetProcessHeap(), 0, object);
2041 return E_OUTOFMEMORY;
2044 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2045 if(FAILED(hr)) {
2046 IWineD3DPalette_Release((IWineD3DPalette *) object);
2047 return hr;
2050 *Palette = (IWineD3DPalette *) object;
2052 return WINED3D_OK;
2055 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2057 IWineD3DSwapChainImpl *swapchain;
2059 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2060 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2062 /* TODO: Test if OpenGL is compiled in and loaded */
2064 /* Setup the implicit swapchain */
2065 TRACE("Creating implicit swapchain\n");
2066 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2067 WARN("Failed to create implicit swapchain\n");
2068 return WINED3DERR_INVALIDCALL;
2071 This->NumberOfSwapChains = 1;
2072 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2073 if(!This->swapchains) {
2074 ERR("Out of memory!\n");
2075 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2076 return E_OUTOFMEMORY;
2078 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2080 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2081 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2082 This->renderTarget = swapchain->backBuffer[0];
2084 else {
2085 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2086 This->renderTarget = swapchain->frontBuffer;
2088 IWineD3DSurface_AddRef(This->renderTarget);
2089 /* Depth Stencil support */
2090 This->stencilBufferTarget = This->depthStencilBuffer;
2091 if (NULL != This->stencilBufferTarget) {
2092 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2095 /* Set up some starting GL setup */
2096 ENTER_GL();
2098 * Initialize openGL extension related variables
2099 * with Default values
2102 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2103 /* Setup all the devices defaults */
2104 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2105 #if 0
2106 IWineD3DImpl_CheckGraphicsMemory();
2107 #endif
2108 LEAVE_GL();
2110 /* Initialize our list of GLSL programs */
2111 list_init(&This->glsl_shader_progs);
2113 { /* Set a default viewport */
2114 WINED3DVIEWPORT vp;
2115 vp.X = 0;
2116 vp.Y = 0;
2117 vp.Width = *(pPresentationParameters->BackBufferWidth);
2118 vp.Height = *(pPresentationParameters->BackBufferHeight);
2119 vp.MinZ = 0.0f;
2120 vp.MaxZ = 1.0f;
2121 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2124 /* Initialize the current view state */
2125 This->modelview_valid = 1;
2126 This->proj_valid = 0;
2127 This->view_ident = 1;
2128 This->last_was_rhw = 0;
2129 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2130 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2132 /* Clear the screen */
2133 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2135 This->d3d_initialized = TRUE;
2136 return WINED3D_OK;
2139 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2141 int sampler;
2142 IUnknown* stencilBufferParent;
2143 IUnknown* swapChainParent;
2144 uint i;
2145 TRACE("(%p)\n", This);
2147 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2149 /* Delete the mouse cursor texture */
2150 if(This->cursorTexture) {
2151 ENTER_GL();
2152 glDeleteTextures(1, &This->cursorTexture);
2153 LEAVE_GL();
2154 This->cursorTexture = 0;
2157 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2158 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2161 /* Release the buffers (with sanity checks)*/
2162 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2163 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2164 if(This->depthStencilBuffer != This->stencilBufferTarget)
2165 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2167 This->stencilBufferTarget = NULL;
2169 TRACE("Releasing the render target at %p\n", This->renderTarget);
2170 if(IWineD3DSurface_Release(This->renderTarget) >0){
2171 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2173 TRACE("Setting rendertarget to NULL\n");
2174 This->renderTarget = NULL;
2176 if (This->depthStencilBuffer) {
2177 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2178 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2179 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2180 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2182 This->depthStencilBuffer = NULL;
2185 for(i=0; i < This->NumberOfSwapChains; i++) {
2186 TRACE("Releasing the implicit swapchain %d\n", i);
2187 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2188 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2189 IUnknown_Release(swapChainParent); /* once for the get parent */
2190 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2191 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2195 HeapFree(GetProcessHeap(), 0, This->swapchains);
2196 This->swapchains = NULL;
2197 This->NumberOfSwapChains = 0;
2199 This->d3d_initialized = FALSE;
2200 return WINED3D_OK;
2203 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2205 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2207 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2208 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2209 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2210 * separately.
2212 This->ddraw_fullscreen = fullscreen;
2215 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 DEVMODEW DevModeW;
2219 int i;
2220 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2222 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2224 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2225 /* Ignore some modes if a description was passed */
2226 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2227 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2228 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2230 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2232 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2233 return D3D_OK;
2236 return D3D_OK;
2239 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2240 DEVMODEW devmode;
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2242 LONG ret;
2243 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2245 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2247 /* Resize the screen even without a window:
2248 * The app could have unset it with SetCooperativeLevel, but not called
2249 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2250 * but we don't have any hwnd
2253 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2254 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2255 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2256 devmode.dmPelsWidth = pMode->Width;
2257 devmode.dmPelsHeight = pMode->Height;
2259 devmode.dmDisplayFrequency = pMode->RefreshRate;
2260 if (pMode->RefreshRate != 0) {
2261 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2264 /* Only change the mode if necessary */
2265 if( (This->ddraw_width == pMode->Width) &&
2266 (This->ddraw_height == pMode->Height) &&
2267 (This->ddraw_format == pMode->Format) &&
2268 (pMode->RefreshRate == 0) ) {
2269 return D3D_OK;
2272 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2273 if (ret != DISP_CHANGE_SUCCESSFUL) {
2274 if(devmode.dmDisplayFrequency != 0) {
2275 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2276 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2277 devmode.dmDisplayFrequency = 0;
2278 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2280 if(ret != DISP_CHANGE_SUCCESSFUL) {
2281 return DDERR_INVALIDMODE;
2285 /* Store the new values */
2286 This->ddraw_width = pMode->Width;
2287 This->ddraw_height = pMode->Height;
2288 This->ddraw_format = pMode->Format;
2290 /* Only do this with a window of course */
2291 if(This->ddraw_window)
2292 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2294 return WINED3D_OK;
2297 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 *ppD3D= This->wineD3D;
2300 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2301 IWineD3D_AddRef(*ppD3D);
2302 return WINED3D_OK;
2305 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2306 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2307 * into the video ram as possible and seeing how many fit
2308 * you can also get the correct initial value from nvidia and ATI's driver via X
2309 * texture memory is video memory + AGP memory
2310 *******************/
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2312 static BOOL showfixmes = TRUE;
2313 if (showfixmes) {
2314 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2315 (wined3d_settings.emulated_textureram/(1024*1024)),
2316 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2317 showfixmes = FALSE;
2319 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2320 (wined3d_settings.emulated_textureram/(1024*1024)),
2321 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2322 /* return simulated texture memory left */
2323 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2328 /*****
2329 * Get / Set FVF
2330 *****/
2331 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 HRESULT hr = WINED3D_OK;
2335 /* Update the current state block */
2336 This->updateStateBlock->fvf = fvf;
2337 This->updateStateBlock->changed.fvf = TRUE;
2338 This->updateStateBlock->set.fvf = TRUE;
2340 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2341 return hr;
2345 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2347 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2348 *pfvf = This->stateBlock->fvf;
2349 return WINED3D_OK;
2352 /*****
2353 * Get / Set Stream Source
2354 *****/
2355 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2357 IWineD3DVertexBuffer *oldSrc;
2359 /**TODO: instance and index data, see
2360 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2362 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2363 **************/
2365 /* D3d9 only, but shouldn't hurt d3d8 */
2366 UINT streamFlags;
2368 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2369 if (streamFlags) {
2370 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2371 FIXME("stream index data not supported\n");
2373 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2374 FIXME("stream instance data not supported\n");
2378 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2380 if (StreamNumber >= MAX_STREAMS) {
2381 WARN("Stream out of range %d\n", StreamNumber);
2382 return WINED3DERR_INVALIDCALL;
2385 oldSrc = This->stateBlock->streamSource[StreamNumber];
2386 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2388 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2389 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2390 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2391 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2392 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2393 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2395 /* Handle recording of state blocks */
2396 if (This->isRecordingState) {
2397 TRACE("Recording... not performing anything\n");
2398 return WINED3D_OK;
2401 /* Same stream object: no action */
2402 if (oldSrc == pStreamData)
2403 return WINED3D_OK;
2405 /* Need to do a getParent and pass the reffs up */
2406 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2407 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2408 so for now, just count internally */
2409 if (pStreamData != NULL) {
2410 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2411 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2412 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2414 vbImpl->stream = StreamNumber;
2415 vbImpl->Flags |= VBFLAG_STREAM;
2416 IWineD3DVertexBuffer_AddRef(pStreamData);
2418 if (oldSrc != NULL) {
2419 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2420 IWineD3DVertexBuffer_Release(oldSrc);
2423 return WINED3D_OK;
2426 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2428 UINT streamFlags;
2430 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2431 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2434 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2435 if (streamFlags) {
2436 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2437 FIXME("stream index data not supported\n");
2439 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2440 FIXME("stream instance data not supported\n");
2444 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2446 if (StreamNumber >= MAX_STREAMS) {
2447 WARN("Stream out of range %d\n", StreamNumber);
2448 return WINED3DERR_INVALIDCALL;
2450 *pStream = This->stateBlock->streamSource[StreamNumber];
2451 *pStride = This->stateBlock->streamStride[StreamNumber];
2452 if (pOffset) {
2453 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2456 if (*pStream == NULL) {
2457 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2458 return WINED3DERR_INVALIDCALL;
2461 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2462 return WINED3D_OK;
2465 /*Should be quite easy, just an extension of vertexdata
2466 ref...
2467 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2469 The divider is a bit odd though
2471 VertexOffset = StartVertex / Divider * StreamStride +
2472 VertexIndex / Divider * StreamStride + StreamOffset
2475 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2478 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2479 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2481 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2482 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2483 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2485 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2486 FIXME("Stream indexing not fully supported\n");
2489 return WINED3D_OK;
2492 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2496 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2498 TRACE("(%p) : returning %d\n", This, *Divider);
2500 return WINED3D_OK;
2503 /*****
2504 * Get / Set & Multiply Transform
2505 *****/
2506 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2509 /* Most of this routine, comments included copied from ddraw tree initially: */
2510 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2512 /* Handle recording of state blocks */
2513 if (This->isRecordingState) {
2514 TRACE("Recording... not performing anything\n");
2515 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2516 This->updateStateBlock->set.transform[d3dts] = TRUE;
2517 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2518 return WINED3D_OK;
2522 * If the new matrix is the same as the current one,
2523 * we cut off any further processing. this seems to be a reasonable
2524 * optimization because as was noticed, some apps (warcraft3 for example)
2525 * tend towards setting the same matrix repeatedly for some reason.
2527 * From here on we assume that the new matrix is different, wherever it matters.
2529 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2530 TRACE("The app is setting the same matrix over again\n");
2531 return WINED3D_OK;
2532 } else {
2533 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2537 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2538 where ViewMat = Camera space, WorldMat = world space.
2540 In OpenGL, camera and world space is combined into GL_MODELVIEW
2541 matrix. The Projection matrix stay projection matrix.
2544 /* Capture the times we can just ignore the change for now */
2545 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2546 This->modelview_valid = FALSE;
2547 return WINED3D_OK;
2549 } else if (d3dts == WINED3DTS_PROJECTION) {
2550 This->proj_valid = FALSE;
2551 return WINED3D_OK;
2553 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2554 /* Indexed Vertex Blending Matrices 256 -> 511 */
2555 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2556 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2557 return WINED3D_OK;
2560 /* Now we really are going to have to change a matrix */
2561 ENTER_GL();
2563 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2564 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2565 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2566 unsigned int k;
2568 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2569 * NOTE: We have to reset the positions even if the light/plane is not currently
2570 * enabled, since the call to enable it will not reset the position.
2571 * NOTE2: Apparently texture transforms do NOT need reapplying
2574 PLIGHTINFOEL *lightChain = NULL;
2575 This->modelview_valid = FALSE;
2576 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2578 glMatrixMode(GL_MODELVIEW);
2579 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2580 glPushMatrix();
2581 glLoadMatrixf((float *)lpmatrix);
2582 checkGLcall("glLoadMatrixf(...)");
2584 /* Reset lights */
2585 lightChain = This->stateBlock->lights;
2586 while (lightChain && lightChain->glIndex != -1) {
2587 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2588 checkGLcall("glLightfv posn");
2589 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2590 checkGLcall("glLightfv dirn");
2591 lightChain = lightChain->next;
2594 /* Reset Clipping Planes if clipping is enabled */
2595 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2596 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2597 checkGLcall("glClipPlane");
2599 glPopMatrix();
2601 } else { /* What was requested!?? */
2602 WARN("invalid matrix specified: %i\n", d3dts);
2605 /* Release lock, all done */
2606 LEAVE_GL();
2607 return WINED3D_OK;
2610 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2613 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2614 return WINED3D_OK;
2617 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2618 WINED3DMATRIX *mat = NULL;
2619 WINED3DMATRIX temp;
2621 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2622 * below means it will be recorded in a state block change, but it
2623 * works regardless where it is recorded.
2624 * If this is found to be wrong, change to StateBlock.
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2627 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2629 if (State < HIGHEST_TRANSFORMSTATE)
2631 mat = &This->updateStateBlock->transforms[State];
2632 } else {
2633 FIXME("Unhandled transform state!!\n");
2636 multiply_matrix(&temp, mat, (WINED3DMATRIX *) pMatrix);
2638 /* Apply change via set transform - will reapply to eg. lights this way */
2639 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2642 /*****
2643 * Get / Set Light
2644 *****/
2645 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2646 you can reference any indexes you want as long as that number max are enabled at any
2647 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2648 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2649 but when recording, just build a chain pretty much of commands to be replayed. */
2651 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2652 float rho;
2653 PLIGHTINFOEL *object, *temp;
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2658 /* If recording state block, just add to end of lights chain */
2659 if (This->isRecordingState) {
2660 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2661 if (NULL == object) {
2662 return WINED3DERR_OUTOFVIDEOMEMORY;
2664 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2665 object->OriginalIndex = Index;
2666 object->glIndex = -1;
2667 object->changed = TRUE;
2669 /* Add to the END of the chain of lights changes to be replayed */
2670 if (This->updateStateBlock->lights == NULL) {
2671 This->updateStateBlock->lights = object;
2672 } else {
2673 temp = This->updateStateBlock->lights;
2674 while (temp->next != NULL) temp=temp->next;
2675 temp->next = object;
2677 TRACE("Recording... not performing anything more\n");
2678 return WINED3D_OK;
2681 /* Ok, not recording any longer so do real work */
2682 object = This->stateBlock->lights;
2683 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2685 /* If we didn't find it in the list of lights, time to add it */
2686 if (object == NULL) {
2687 PLIGHTINFOEL *insertAt,*prevPos;
2689 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2690 if (NULL == object) {
2691 return WINED3DERR_OUTOFVIDEOMEMORY;
2693 object->OriginalIndex = Index;
2694 object->glIndex = -1;
2696 /* Add it to the front of list with the idea that lights will be changed as needed
2697 BUT after any lights currently assigned GL indexes */
2698 insertAt = This->stateBlock->lights;
2699 prevPos = NULL;
2700 while (insertAt != NULL && insertAt->glIndex != -1) {
2701 prevPos = insertAt;
2702 insertAt = insertAt->next;
2705 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2706 This->stateBlock->lights = object;
2707 } else if (insertAt == NULL) { /* End of list */
2708 prevPos->next = object;
2709 object->prev = prevPos;
2710 } else { /* Middle of chain */
2711 if (prevPos == NULL) {
2712 This->stateBlock->lights = object;
2713 } else {
2714 prevPos->next = object;
2716 object->prev = prevPos;
2717 object->next = insertAt;
2718 insertAt->prev = object;
2722 /* Initialize the object */
2723 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2724 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2725 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2726 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2727 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2728 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2729 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2731 /* Save away the information */
2732 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2734 switch (pLight->Type) {
2735 case WINED3DLIGHT_POINT:
2736 /* Position */
2737 object->lightPosn[0] = pLight->Position.x;
2738 object->lightPosn[1] = pLight->Position.y;
2739 object->lightPosn[2] = pLight->Position.z;
2740 object->lightPosn[3] = 1.0f;
2741 object->cutoff = 180.0f;
2742 /* FIXME: Range */
2743 break;
2745 case WINED3DLIGHT_DIRECTIONAL:
2746 /* Direction */
2747 object->lightPosn[0] = -pLight->Direction.x;
2748 object->lightPosn[1] = -pLight->Direction.y;
2749 object->lightPosn[2] = -pLight->Direction.z;
2750 object->lightPosn[3] = 0.0;
2751 object->exponent = 0.0f;
2752 object->cutoff = 180.0f;
2753 break;
2755 case WINED3DLIGHT_SPOT:
2756 /* Position */
2757 object->lightPosn[0] = pLight->Position.x;
2758 object->lightPosn[1] = pLight->Position.y;
2759 object->lightPosn[2] = pLight->Position.z;
2760 object->lightPosn[3] = 1.0;
2762 /* Direction */
2763 object->lightDirn[0] = pLight->Direction.x;
2764 object->lightDirn[1] = pLight->Direction.y;
2765 object->lightDirn[2] = pLight->Direction.z;
2766 object->lightDirn[3] = 1.0;
2769 * opengl-ish and d3d-ish spot lights use too different models for the
2770 * light "intensity" as a function of the angle towards the main light direction,
2771 * so we only can approximate very roughly.
2772 * however spot lights are rather rarely used in games (if ever used at all).
2773 * furthermore if still used, probably nobody pays attention to such details.
2775 if (pLight->Falloff == 0) {
2776 rho = 6.28f;
2777 } else {
2778 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2780 if (rho < 0.0001) rho = 0.0001f;
2781 object->exponent = -0.3/log(cos(rho/2));
2782 if (object->exponent > 128.0) {
2783 object->exponent = 128.0;
2785 object->cutoff = pLight->Phi*90/M_PI;
2787 /* FIXME: Range */
2788 break;
2790 default:
2791 FIXME("Unrecognized light type %d\n", pLight->Type);
2794 /* Update the live definitions if the light is currently assigned a glIndex */
2795 if (object->glIndex != -1) {
2796 setup_light(iface, object->glIndex, object);
2798 return WINED3D_OK;
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2802 PLIGHTINFOEL *lightInfo = NULL;
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2806 /* Locate the light in the live lights */
2807 lightInfo = This->stateBlock->lights;
2808 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2810 if (lightInfo == NULL) {
2811 TRACE("Light information requested but light not defined\n");
2812 return WINED3DERR_INVALIDCALL;
2815 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2816 return WINED3D_OK;
2819 /*****
2820 * Get / Set Light Enable
2821 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2822 *****/
2823 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2824 PLIGHTINFOEL *lightInfo = NULL;
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2828 /* Tests show true = 128...not clear why */
2830 Enable = Enable? 128: 0;
2832 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2833 if (This->isRecordingState) {
2834 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2835 if (NULL == lightInfo) {
2836 return WINED3DERR_OUTOFVIDEOMEMORY;
2838 lightInfo->OriginalIndex = Index;
2839 lightInfo->glIndex = -1;
2840 lightInfo->enabledChanged = TRUE;
2841 lightInfo->lightEnabled = Enable;
2843 /* Add to the END of the chain of lights changes to be replayed */
2844 if (This->updateStateBlock->lights == NULL) {
2845 This->updateStateBlock->lights = lightInfo;
2846 } else {
2847 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2848 while (temp->next != NULL) temp=temp->next;
2849 temp->next = lightInfo;
2851 TRACE("Recording... not performing anything more\n");
2852 return WINED3D_OK;
2855 /* Not recording... So, locate the light in the live lights */
2856 lightInfo = This->stateBlock->lights;
2857 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2859 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2860 if (lightInfo == NULL) {
2862 TRACE("Light enabled requested but light not defined, so defining one!\n");
2863 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2865 /* Search for it again! Should be fairly quick as near head of list */
2866 lightInfo = This->stateBlock->lights;
2867 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2868 if (lightInfo == NULL) {
2869 FIXME("Adding default lights has failed dismally\n");
2870 return WINED3DERR_INVALIDCALL;
2874 /* OK, we now have a light... */
2875 if (!Enable) {
2877 /* If we are disabling it, check it was enabled, and
2878 still only do something if it has assigned a glIndex (which it should have!) */
2879 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2880 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2881 ENTER_GL();
2882 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2883 checkGLcall("glDisable GL_LIGHT0+Index");
2884 LEAVE_GL();
2885 } else {
2886 TRACE("Nothing to do as light was not enabled\n");
2888 lightInfo->lightEnabled = Enable;
2889 } else {
2891 /* We are enabling it. If it is enabled, it's really simple */
2892 if (lightInfo->lightEnabled) {
2893 /* nop */
2894 TRACE("Nothing to do as light was enabled\n");
2896 /* If it already has a glIndex, it's still simple */
2897 } else if (lightInfo->glIndex != -1) {
2898 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2899 lightInfo->lightEnabled = Enable;
2900 ENTER_GL();
2901 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2902 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2903 LEAVE_GL();
2905 /* Otherwise got to find space - lights are ordered gl indexes first */
2906 } else {
2907 PLIGHTINFOEL *bsf = NULL;
2908 PLIGHTINFOEL *pos = This->stateBlock->lights;
2909 PLIGHTINFOEL *prev = NULL;
2910 int Index= 0;
2911 int glIndex = -1;
2913 /* Try to minimize changes as much as possible */
2914 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2916 /* Try to remember which index can be replaced if necessary */
2917 if (bsf==NULL && !pos->lightEnabled) {
2918 /* Found a light we can replace, save as best replacement */
2919 bsf = pos;
2922 /* Step to next space */
2923 prev = pos;
2924 pos = pos->next;
2925 Index ++;
2928 /* If we have too many active lights, fail the call */
2929 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2930 FIXME("Program requests too many concurrent lights\n");
2931 return WINED3DERR_INVALIDCALL;
2933 /* If we have allocated all lights, but not all are enabled,
2934 reuse one which is not enabled */
2935 } else if (Index == This->maxConcurrentLights) {
2936 /* use bsf - Simply swap the new light and the BSF one */
2937 PLIGHTINFOEL *bsfNext = bsf->next;
2938 PLIGHTINFOEL *bsfPrev = bsf->prev;
2940 /* Sort out ends */
2941 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2942 if (bsf->prev != NULL) {
2943 bsf->prev->next = lightInfo;
2944 } else {
2945 This->stateBlock->lights = lightInfo;
2948 /* If not side by side, lots of chains to update */
2949 if (bsf->next != lightInfo) {
2950 lightInfo->prev->next = bsf;
2951 bsf->next->prev = lightInfo;
2952 bsf->next = lightInfo->next;
2953 bsf->prev = lightInfo->prev;
2954 lightInfo->next = bsfNext;
2955 lightInfo->prev = bsfPrev;
2957 } else {
2958 /* Simple swaps */
2959 bsf->prev = lightInfo;
2960 bsf->next = lightInfo->next;
2961 lightInfo->next = bsf;
2962 lightInfo->prev = bsfPrev;
2966 /* Update states */
2967 glIndex = bsf->glIndex;
2968 bsf->glIndex = -1;
2969 lightInfo->glIndex = glIndex;
2970 lightInfo->lightEnabled = Enable;
2972 /* Finally set up the light in gl itself */
2973 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2974 ENTER_GL();
2975 setup_light(iface, glIndex, lightInfo);
2976 glEnable(GL_LIGHT0 + glIndex);
2977 checkGLcall("glEnable GL_LIGHT0 new setup");
2978 LEAVE_GL();
2980 /* If we reached the end of the allocated lights, with space in the
2981 gl lights, setup a new light */
2982 } else if (pos->glIndex == -1) {
2984 /* We reached the end of the allocated gl lights, so already
2985 know the index of the next one! */
2986 glIndex = Index;
2987 lightInfo->glIndex = glIndex;
2988 lightInfo->lightEnabled = Enable;
2990 /* In an ideal world, it's already in the right place */
2991 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2992 /* No need to move it */
2993 } else {
2994 /* Remove this light from the list */
2995 lightInfo->prev->next = lightInfo->next;
2996 if (lightInfo->next != NULL) {
2997 lightInfo->next->prev = lightInfo->prev;
3000 /* Add in at appropriate place (inbetween prev and pos) */
3001 lightInfo->prev = prev;
3002 lightInfo->next = pos;
3003 if (prev == NULL) {
3004 This->stateBlock->lights = lightInfo;
3005 } else {
3006 prev->next = lightInfo;
3008 if (pos != NULL) {
3009 pos->prev = lightInfo;
3013 /* Finally set up the light in gl itself */
3014 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3015 ENTER_GL();
3016 setup_light(iface, glIndex, lightInfo);
3017 glEnable(GL_LIGHT0 + glIndex);
3018 checkGLcall("glEnable GL_LIGHT0 new setup");
3019 LEAVE_GL();
3024 return WINED3D_OK;
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3029 PLIGHTINFOEL *lightInfo = NULL;
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 TRACE("(%p) : for idx(%d)\n", This, Index);
3033 /* Locate the light in the live lights */
3034 lightInfo = This->stateBlock->lights;
3035 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3037 if (lightInfo == NULL) {
3038 TRACE("Light enabled state requested but light not defined\n");
3039 return WINED3DERR_INVALIDCALL;
3041 *pEnable = lightInfo->lightEnabled;
3042 return WINED3D_OK;
3045 /*****
3046 * Get / Set Clip Planes
3047 *****/
3048 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3052 /* Validate Index */
3053 if (Index >= GL_LIMITS(clipplanes)) {
3054 TRACE("Application has requested clipplane this device doesn't support\n");
3055 return WINED3DERR_INVALIDCALL;
3058 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3059 This->updateStateBlock->set.clipplane[Index] = TRUE;
3060 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3061 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3062 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3063 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3065 /* Handle recording of state blocks */
3066 if (This->isRecordingState) {
3067 TRACE("Recording... not performing anything\n");
3068 return WINED3D_OK;
3071 /* Apply it */
3073 ENTER_GL();
3075 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3076 glMatrixMode(GL_MODELVIEW);
3077 glPushMatrix();
3078 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3080 TRACE("Clipplane [%f,%f,%f,%f]\n",
3081 This->updateStateBlock->clipplane[Index][0],
3082 This->updateStateBlock->clipplane[Index][1],
3083 This->updateStateBlock->clipplane[Index][2],
3084 This->updateStateBlock->clipplane[Index][3]);
3085 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3086 checkGLcall("glClipPlane");
3088 glPopMatrix();
3089 LEAVE_GL();
3091 return WINED3D_OK;
3094 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : for idx %d\n", This, Index);
3098 /* Validate Index */
3099 if (Index >= GL_LIMITS(clipplanes)) {
3100 TRACE("Application has requested clipplane this device doesn't support\n");
3101 return WINED3DERR_INVALIDCALL;
3104 pPlane[0] = This->stateBlock->clipplane[Index][0];
3105 pPlane[1] = This->stateBlock->clipplane[Index][1];
3106 pPlane[2] = This->stateBlock->clipplane[Index][2];
3107 pPlane[3] = This->stateBlock->clipplane[Index][3];
3108 return WINED3D_OK;
3111 /*****
3112 * Get / Set Clip Plane Status
3113 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3114 *****/
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 FIXME("(%p) : stub\n", This);
3118 if (NULL == pClipStatus) {
3119 return WINED3DERR_INVALIDCALL;
3121 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3122 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 FIXME("(%p) : stub\n", This);
3129 if (NULL == pClipStatus) {
3130 return WINED3DERR_INVALIDCALL;
3132 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3133 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3134 return WINED3D_OK;
3137 /*****
3138 * Get / Set Material
3139 *****/
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 This->updateStateBlock->changed.material = TRUE;
3144 This->updateStateBlock->set.material = TRUE;
3145 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3147 /* Handle recording of state blocks */
3148 if (This->isRecordingState) {
3149 TRACE("Recording... not performing anything\n");
3150 return WINED3D_OK;
3153 ENTER_GL();
3154 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3155 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3156 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3157 pMaterial->Ambient.b, pMaterial->Ambient.a);
3158 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3159 pMaterial->Specular.b, pMaterial->Specular.a);
3160 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3161 pMaterial->Emissive.b, pMaterial->Emissive.a);
3162 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3164 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3165 checkGLcall("glMaterialfv(GL_AMBIENT)");
3166 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3167 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3169 /* Only change material color if specular is enabled, otherwise it is set to black */
3170 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3171 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3172 checkGLcall("glMaterialfv(GL_SPECULAR");
3173 } else {
3174 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3175 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3176 checkGLcall("glMaterialfv(GL_SPECULAR");
3178 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3179 checkGLcall("glMaterialfv(GL_EMISSION)");
3180 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3181 checkGLcall("glMaterialf(GL_SHININESS");
3183 LEAVE_GL();
3184 return WINED3D_OK;
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3190 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3191 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3192 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3193 pMaterial->Ambient.b, pMaterial->Ambient.a);
3194 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3195 pMaterial->Specular.b, pMaterial->Specular.a);
3196 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3197 pMaterial->Emissive.b, pMaterial->Emissive.a);
3198 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3200 return WINED3D_OK;
3203 /*****
3204 * Get / Set Indices
3205 *****/
3206 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3207 UINT BaseVertexIndex) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 IWineD3DIndexBuffer *oldIdxs;
3211 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3212 oldIdxs = This->updateStateBlock->pIndexData;
3214 This->updateStateBlock->changed.indices = TRUE;
3215 This->updateStateBlock->set.indices = TRUE;
3216 This->updateStateBlock->pIndexData = pIndexData;
3217 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3219 /* Handle recording of state blocks */
3220 if (This->isRecordingState) {
3221 TRACE("Recording... not performing anything\n");
3222 return WINED3D_OK;
3225 if (NULL != pIndexData) {
3226 IWineD3DIndexBuffer_AddRef(pIndexData);
3228 if (NULL != oldIdxs) {
3229 IWineD3DIndexBuffer_Release(oldIdxs);
3231 return WINED3D_OK;
3234 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 *ppIndexData = This->stateBlock->pIndexData;
3239 /* up ref count on ppindexdata */
3240 if (*ppIndexData) {
3241 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3242 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3243 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3244 }else{
3245 TRACE("(%p) No index data set\n", This);
3247 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3249 return WINED3D_OK;
3252 /*****
3253 * Get / Set Viewports
3254 *****/
3255 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 TRACE("(%p)\n", This);
3259 This->updateStateBlock->changed.viewport = TRUE;
3260 This->updateStateBlock->set.viewport = TRUE;
3261 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3266 return WINED3D_OK;
3268 This->viewport_changed = TRUE;
3270 ENTER_GL();
3272 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3273 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3275 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3276 checkGLcall("glDepthRange");
3277 /* Note: GL requires lower left, DirectX supplies upper left */
3278 /* TODO: replace usage of renderTarget with context management */
3279 glViewport(pViewport->X,
3280 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3281 pViewport->Width, pViewport->Height);
3283 checkGLcall("glViewport");
3285 LEAVE_GL();
3287 return WINED3D_OK;
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 TRACE("(%p)\n", This);
3294 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3295 return WINED3D_OK;
3298 static void renderstate_stencil_twosided(
3299 IWineD3DDeviceImpl *This,
3300 GLint face,
3301 GLint func,
3302 GLint ref,
3303 GLuint mask,
3304 GLint stencilFail,
3305 GLint depthFail,
3306 GLint stencilPass ) {
3307 #if 0 /* Don't use OpenGL 2.0 calls for now */
3308 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3309 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3310 checkGLcall("glStencilFuncSeparate(...)");
3311 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3312 checkGLcall("glStencilOpSeparate(...)");
3314 else
3315 #endif
3316 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3317 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3318 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3319 GL_EXTCALL(glActiveStencilFaceEXT(face));
3320 checkGLcall("glActiveStencilFaceEXT(...)");
3321 glStencilFunc(func, ref, mask);
3322 checkGLcall("glStencilFunc(...)");
3323 glStencilOp(stencilFail, depthFail, stencilPass);
3324 checkGLcall("glStencilOp(...)");
3325 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3326 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3327 checkGLcall("glStencilFuncSeparateATI(...)");
3328 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3329 checkGLcall("glStencilOpSeparateATI(...)");
3330 } else {
3331 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3335 static void renderstate_stencil(IWineD3DDeviceImpl *This, WINED3DRENDERSTATETYPE State, DWORD Value) {
3336 DWORD onesided_enable = FALSE;
3337 DWORD twosided_enable = FALSE;
3338 GLint func = GL_ALWAYS;
3339 GLint func_ccw = GL_ALWAYS;
3340 GLint ref = 0;
3341 GLuint mask = 0;
3342 GLint stencilFail = GL_KEEP;
3343 GLint depthFail = GL_KEEP;
3344 GLint stencilPass = GL_KEEP;
3345 GLint stencilFail_ccw = GL_KEEP;
3346 GLint depthFail_ccw = GL_KEEP;
3347 GLint stencilPass_ccw = GL_KEEP;
3349 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3350 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3351 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3352 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3353 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3354 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3355 func = GL_ALWAYS;
3356 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3357 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3358 func = GL_ALWAYS;
3359 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3360 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3361 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3362 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3363 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3364 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3365 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3366 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3367 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3368 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3369 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3370 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3371 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3372 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3373 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3374 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3376 TRACE("(onesided %d, twosided %d, ref %x, mask %x, \
3377 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3378 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3379 onesided_enable, twosided_enable, ref, mask,
3380 func, stencilFail, depthFail, stencilPass,
3381 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3383 if (twosided_enable) {
3384 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3385 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3386 } else {
3387 if (onesided_enable) {
3388 glEnable(GL_STENCIL_TEST);
3389 checkGLcall("glEnable GL_STENCIL_TEST");
3390 glStencilFunc(func, ref, mask);
3391 checkGLcall("glStencilFunc(...)");
3392 glStencilOp(stencilFail, depthFail, stencilPass);
3393 checkGLcall("glStencilOp(...)");
3394 } else {
3395 glDisable(GL_STENCIL_TEST);
3396 checkGLcall("glDisable GL_STENCIL_TEST");
3401 /*****
3402 * Get / Set Render States
3403 * TODO: Verify against dx9 definitions
3404 *****/
3405 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3408 DWORD OldValue = This->stateBlock->renderState[State];
3410 /* Simple way of referring to either a DWORD or a 4 byte float */
3411 union {
3412 DWORD d;
3413 float f;
3414 } tmpvalue;
3416 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3417 This->updateStateBlock->changed.renderState[State] = TRUE;
3418 This->updateStateBlock->set.renderState[State] = TRUE;
3419 This->updateStateBlock->renderState[State] = Value;
3421 /* Handle recording of state blocks */
3422 if (This->isRecordingState) {
3423 TRACE("Recording... not performing anything\n");
3424 return WINED3D_OK;
3427 ENTER_GL();
3429 switch (State) {
3430 case WINED3DRS_FILLMODE :
3431 switch ((WINED3DFILLMODE) Value) {
3432 case WINED3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3433 case WINED3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3434 case WINED3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3435 default:
3436 FIXME("Unrecognized WINED3DRS_FILLMODE value %d\n", Value);
3438 checkGLcall("glPolygonMode (fillmode)");
3439 break;
3441 case WINED3DRS_LIGHTING :
3442 if (Value) {
3443 glEnable(GL_LIGHTING);
3444 checkGLcall("glEnable GL_LIGHTING");
3445 } else {
3446 glDisable(GL_LIGHTING);
3447 checkGLcall("glDisable GL_LIGHTING");
3449 break;
3451 case WINED3DRS_ZENABLE :
3452 switch ((WINED3DZBUFFERTYPE) Value) {
3453 case WINED3DZB_FALSE:
3454 glDisable(GL_DEPTH_TEST);
3455 checkGLcall("glDisable GL_DEPTH_TEST");
3456 break;
3457 case WINED3DZB_TRUE:
3458 glEnable(GL_DEPTH_TEST);
3459 checkGLcall("glEnable GL_DEPTH_TEST");
3460 break;
3461 case WINED3DZB_USEW:
3462 glEnable(GL_DEPTH_TEST);
3463 checkGLcall("glEnable GL_DEPTH_TEST");
3464 FIXME("W buffer is not well handled\n");
3465 break;
3466 default:
3467 FIXME("Unrecognized WINED3DZBUFFERTYPE value %d\n", Value);
3469 break;
3471 case WINED3DRS_CULLMODE :
3473 /* If we are culling "back faces with clockwise vertices" then
3474 set front faces to be counter clockwise and enable culling
3475 of back faces */
3476 switch ((WINED3DCULL) Value) {
3477 case WINED3DCULL_NONE:
3478 glDisable(GL_CULL_FACE);
3479 checkGLcall("glDisable GL_CULL_FACE");
3480 break;
3481 case WINED3DCULL_CW:
3482 glEnable(GL_CULL_FACE);
3483 checkGLcall("glEnable GL_CULL_FACE");
3484 if (This->render_offscreen) {
3485 glFrontFace(GL_CW);
3486 checkGLcall("glFrontFace GL_CW");
3487 } else {
3488 glFrontFace(GL_CCW);
3489 checkGLcall("glFrontFace GL_CCW");
3491 glCullFace(GL_BACK);
3492 break;
3493 case WINED3DCULL_CCW:
3494 glEnable(GL_CULL_FACE);
3495 checkGLcall("glEnable GL_CULL_FACE");
3496 if (This->render_offscreen) {
3497 glFrontFace(GL_CCW);
3498 checkGLcall("glFrontFace GL_CCW");
3499 } else {
3500 glFrontFace(GL_CW);
3501 checkGLcall("glFrontFace GL_CW");
3503 glCullFace(GL_BACK);
3504 break;
3505 default:
3506 FIXME("Unrecognized/Unhandled WINED3DCULL value %d\n", Value);
3508 break;
3510 case WINED3DRS_SHADEMODE :
3511 switch ((WINED3DSHADEMODE) Value) {
3512 case WINED3DSHADE_FLAT:
3513 glShadeModel(GL_FLAT);
3514 checkGLcall("glShadeModel");
3515 break;
3516 case WINED3DSHADE_GOURAUD:
3517 glShadeModel(GL_SMOOTH);
3518 checkGLcall("glShadeModel");
3519 break;
3520 case WINED3DSHADE_PHONG:
3521 FIXME("WINED3DSHADE_PHONG isn't supported\n");
3522 break;
3523 default:
3524 FIXME("Unrecognized/Unhandled WINED3DSHADEMODE value %d\n", Value);
3526 break;
3528 case WINED3DRS_DITHERENABLE :
3529 if (Value) {
3530 glEnable(GL_DITHER);
3531 checkGLcall("glEnable GL_DITHER");
3532 } else {
3533 glDisable(GL_DITHER);
3534 checkGLcall("glDisable GL_DITHER");
3536 break;
3538 case WINED3DRS_ZWRITEENABLE :
3539 if (Value) {
3540 glDepthMask(1);
3541 checkGLcall("glDepthMask");
3542 } else {
3543 glDepthMask(0);
3544 checkGLcall("glDepthMask");
3546 break;
3548 case WINED3DRS_ZFUNC :
3550 int glParm = CompareFunc(Value);
3552 if(glParm) {
3553 glDepthFunc(glParm);
3554 checkGLcall("glDepthFunc");
3557 break;
3559 case WINED3DRS_AMBIENT :
3561 float col[4];
3562 D3DCOLORTOGLFLOAT4(Value, col);
3563 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3564 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3565 checkGLcall("glLightModel for MODEL_AMBIENT");
3568 break;
3570 case WINED3DRS_ALPHABLENDENABLE :
3571 if (Value) {
3572 glEnable(GL_BLEND);
3573 checkGLcall("glEnable GL_BLEND");
3574 } else {
3575 glDisable(GL_BLEND);
3576 checkGLcall("glDisable GL_BLEND");
3578 break;
3580 case WINED3DRS_SRCBLEND :
3581 case WINED3DRS_DESTBLEND :
3583 int newVal = GL_ZERO;
3584 switch (Value) {
3585 case WINED3DBLEND_ZERO : newVal = GL_ZERO; break;
3586 case WINED3DBLEND_ONE : newVal = GL_ONE; break;
3587 case WINED3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3588 case WINED3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3589 case WINED3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3590 case WINED3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3591 case WINED3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3592 case WINED3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3593 case WINED3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3594 case WINED3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3595 case WINED3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3597 case WINED3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3598 This->srcBlend = newVal;
3599 This->dstBlend = newVal;
3600 break;
3602 case WINED3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3603 This->srcBlend = newVal;
3604 This->dstBlend = newVal;
3605 break;
3606 case WINED3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3607 case WINED3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3608 default:
3609 FIXME("Unrecognized src/dest blend value %d (%d)\n", Value, State);
3612 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3613 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3614 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3615 glBlendFunc(This->srcBlend, This->dstBlend);
3617 checkGLcall("glBlendFunc");
3619 break;
3621 case WINED3DRS_ALPHATESTENABLE :
3622 case WINED3DRS_ALPHAFUNC :
3623 case WINED3DRS_ALPHAREF :
3624 case WINED3DRS_COLORKEYENABLE :
3626 int glParm = 0;
3627 float ref;
3628 BOOL enable_ckey = FALSE;
3630 IWineD3DSurfaceImpl *surf;
3632 /* Find out if the texture on the first stage has a ckey set */
3633 if(This->stateBlock->textures[0]) {
3634 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3635 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3638 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3639 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3640 glEnable(GL_ALPHA_TEST);
3641 checkGLcall("glEnable GL_ALPHA_TEST");
3642 } else {
3643 glDisable(GL_ALPHA_TEST);
3644 checkGLcall("glDisable GL_ALPHA_TEST");
3645 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3646 * enable call
3648 break;
3651 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3652 glParm = GL_NOTEQUAL;
3653 ref = 0.0;
3654 } else {
3655 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3656 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3658 if(glParm) {
3659 This->alphafunc = glParm;
3660 glAlphaFunc(glParm, ref);
3661 checkGLcall("glAlphaFunc");
3664 break;
3666 case WINED3DRS_CLIPPLANEENABLE :
3667 case WINED3DRS_CLIPPING :
3669 /* Ensure we only do the changed clip planes */
3670 DWORD enable = 0xFFFFFFFF;
3671 DWORD disable = 0x00000000;
3673 /* If enabling / disabling all */
3674 if (State == WINED3DRS_CLIPPING) {
3675 if (Value) {
3676 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3677 disable = 0x00;
3678 } else {
3679 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3680 enable = 0x00;
3682 } else {
3683 enable = Value & ~OldValue;
3684 disable = ~Value & OldValue;
3687 if (enable & WINED3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3688 if (enable & WINED3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3689 if (enable & WINED3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3690 if (enable & WINED3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3691 if (enable & WINED3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3692 if (enable & WINED3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3694 if (disable & WINED3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3695 if (disable & WINED3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3696 if (disable & WINED3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3697 if (disable & WINED3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3698 if (disable & WINED3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3699 if (disable & WINED3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3701 /** update clipping status */
3702 if (enable) {
3703 This->stateBlock->clip_status.ClipUnion = 0;
3704 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3705 } else {
3706 This->stateBlock->clip_status.ClipUnion = 0;
3707 This->stateBlock->clip_status.ClipIntersection = 0;
3710 break;
3712 case WINED3DRS_BLENDOP :
3714 int glParm = GL_FUNC_ADD;
3716 switch ((WINED3DBLENDOP) Value) {
3717 case WINED3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3718 case WINED3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3719 case WINED3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3720 case WINED3DBLENDOP_MIN : glParm = GL_MIN; break;
3721 case WINED3DBLENDOP_MAX : glParm = GL_MAX; break;
3722 default:
3723 FIXME("Unrecognized/Unhandled WINED3DBLENDOP value %d\n", Value);
3726 if(GL_SUPPORT(EXT_BLEND_MINMAX)) {
3727 TRACE("glBlendEquation(%x)\n", glParm);
3728 GL_EXTCALL(glBlendEquation(glParm));
3729 checkGLcall("glBlendEquation");
3730 } else {
3731 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3734 break;
3736 case WINED3DRS_TEXTUREFACTOR :
3738 unsigned int i;
3740 /* Note the texture color applies to all textures whereas
3741 GL_TEXTURE_ENV_COLOR applies to active only */
3742 float col[4];
3743 D3DCOLORTOGLFLOAT4(Value, col);
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 WINED3DRS 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");
3753 } else if (i>0) {
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);");
3762 break;
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
3771 some extent.
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
3774 running 1.4 yet!
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.
3796 if (Value) {
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);
3801 } else {
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()");
3810 } else {
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);
3820 } else {
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()");
3831 break;
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);
3846 break;
3847 case WINED3DRS_STENCILWRITEMASK :
3849 glStencilMask(Value);
3850 TRACE("glStencilMask(%u)\n", Value);
3851 checkGLcall("glStencilMask");
3853 break;
3855 case WINED3DRS_FOGENABLE :
3857 if (Value) {
3858 glEnable(GL_FOG);
3859 checkGLcall("glEnable GL_FOG");
3860 } else {
3861 glDisable(GL_FOG);
3862 checkGLcall("glDisable GL_FOG");
3865 break;
3867 case WINED3DRS_RANGEFOGENABLE :
3869 if (Value) {
3870 TRACE("Enabled RANGEFOG\n");
3871 } else {
3872 TRACE("Disabled RANGEFOG\n");
3875 break;
3877 case WINED3DRS_FOGCOLOR :
3879 float col[4];
3880 D3DCOLORTOGLFLOAT4(Value, col);
3881 /* Set the default alpha blend color */
3882 glFogfv(GL_FOG_COLOR, &col[0]);
3883 checkGLcall("glFog GL_FOG_COLOR");
3885 break;
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] == WINED3DFOG_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
3898 case WINED3DFOG_EXP: {
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]);
3908 break;
3911 case WINED3DFOG_EXP2: {
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]);
3921 break;
3924 case WINED3DFOG_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]);
3934 break;
3937 case WINED3DFOG_NONE: {
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");
3951 } else {
3952 /* Disable GL fog, handle this in software in drawStridedSlow */
3953 glDisable(GL_FOG);
3954 checkGLcall("glDisable(GL_FOG)");
3956 break;
3958 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3960 } else {
3961 glHint(GL_FOG_HINT, GL_NICEST);
3962 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3963 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3964 case WINED3DFOG_EXP:
3965 glFogi(GL_FOG_MODE, GL_EXP);
3966 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3967 if(GL_SUPPORT(EXT_FOG_COORD)) {
3968 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3969 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3970 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3971 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3973 break;
3974 case WINED3DFOG_EXP2:
3975 glFogi(GL_FOG_MODE, GL_EXP2);
3976 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3977 if(GL_SUPPORT(EXT_FOG_COORD)) {
3978 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3979 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3980 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3981 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3983 break;
3984 case WINED3DFOG_LINEAR:
3985 glFogi(GL_FOG_MODE, GL_LINEAR);
3986 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3987 if(GL_SUPPORT(EXT_FOG_COORD)) {
3988 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3989 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3990 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3991 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3993 break;
3994 case WINED3DFOG_NONE:
3995 default: /* Won't happen */
3996 FIXME("Unexpected WINED3DRS_FOGTABLEMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3999 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4000 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4003 break;
4005 case WINED3DRS_FOGSTART :
4007 tmpvalue.d = Value;
4008 glFogfv(GL_FOG_START, &tmpvalue.f);
4009 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4010 TRACE("Fog Start == %f\n", tmpvalue.f);
4012 break;
4014 case WINED3DRS_FOGEND :
4016 tmpvalue.d = Value;
4017 glFogfv(GL_FOG_END, &tmpvalue.f);
4018 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4019 TRACE("Fog End == %f\n", tmpvalue.f);
4021 break;
4023 case WINED3DRS_FOGDENSITY :
4025 tmpvalue.d = Value;
4026 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4027 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4029 break;
4031 case WINED3DRS_VERTEXBLEND :
4033 This->updateStateBlock->vertex_blend = (WINED3DVERTEXBLENDFLAGS) Value;
4034 TRACE("Vertex Blending state to %d\n", Value);
4036 break;
4038 case WINED3DRS_TWEENFACTOR :
4040 tmpvalue.d = Value;
4041 This->updateStateBlock->tween_factor = tmpvalue.f;
4042 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4044 break;
4046 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4048 TRACE("Indexed Vertex Blend Enable to %u\n", (BOOL) Value);
4050 break;
4052 case WINED3DRS_COLORVERTEX :
4053 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4054 case WINED3DRS_SPECULARMATERIALSOURCE :
4055 case WINED3DRS_AMBIENTMATERIALSOURCE :
4056 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4058 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4060 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4061 TRACE("diff %d, amb %d, emis %d, spec %d\n",
4062 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4063 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4064 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4065 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4067 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4068 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4069 Parm = GL_AMBIENT_AND_DIFFUSE;
4070 } else {
4071 Parm = GL_DIFFUSE;
4073 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4074 Parm = GL_AMBIENT;
4075 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4076 Parm = GL_EMISSION;
4077 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4078 Parm = GL_SPECULAR;
4079 } else {
4080 Parm = -1;
4083 if (Parm == -1) {
4084 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4085 } else {
4086 This->tracking_color = NEEDS_TRACKING;
4087 This->tracking_parm = Parm;
4090 } else {
4091 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4094 break;
4096 case WINED3DRS_LINEPATTERN :
4098 union {
4099 DWORD d;
4100 WINED3DLINEPATTERN lp;
4101 } tmppattern;
4102 tmppattern.d = Value;
4104 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4106 if (tmppattern.lp.wRepeatFactor) {
4107 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4108 checkGLcall("glLineStipple(repeat, linepattern)");
4109 glEnable(GL_LINE_STIPPLE);
4110 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4111 } else {
4112 glDisable(GL_LINE_STIPPLE);
4113 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4116 break;
4118 case WINED3DRS_ZBIAS : /* D3D8 only */
4120 if (Value) {
4121 tmpvalue.d = Value;
4122 TRACE("ZBias value %f\n", tmpvalue.f);
4123 glPolygonOffset(0, -tmpvalue.f);
4124 checkGLcall("glPolygonOffset(0, -Value)");
4125 glEnable(GL_POLYGON_OFFSET_FILL);
4126 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4127 glEnable(GL_POLYGON_OFFSET_LINE);
4128 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4129 glEnable(GL_POLYGON_OFFSET_POINT);
4130 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4131 } else {
4132 glDisable(GL_POLYGON_OFFSET_FILL);
4133 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4134 glDisable(GL_POLYGON_OFFSET_LINE);
4135 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4136 glDisable(GL_POLYGON_OFFSET_POINT);
4137 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4140 break;
4142 case WINED3DRS_NORMALIZENORMALS :
4143 if (Value) {
4144 glEnable(GL_NORMALIZE);
4145 checkGLcall("glEnable(GL_NORMALIZE);");
4146 } else {
4147 glDisable(GL_NORMALIZE);
4148 checkGLcall("glDisable(GL_NORMALIZE);");
4150 break;
4152 case WINED3DRS_POINTSIZE :
4153 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4154 tmpvalue.d = Value;
4155 TRACE("Set point size to %f\n", tmpvalue.f);
4156 glPointSize(tmpvalue.f);
4157 checkGLcall("glPointSize(...);");
4158 break;
4160 case WINED3DRS_POINTSIZE_MIN :
4161 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4162 tmpvalue.d = Value;
4163 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4164 checkGLcall("glPointParameterfEXT(...);");
4165 } else {
4166 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4168 break;
4170 case WINED3DRS_POINTSIZE_MAX :
4171 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4172 tmpvalue.d = Value;
4173 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4174 checkGLcall("glPointParameterfEXT(...);");
4175 } else {
4176 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4178 break;
4180 case WINED3DRS_POINTSCALE_A :
4181 case WINED3DRS_POINTSCALE_B :
4182 case WINED3DRS_POINTSCALE_C :
4183 case WINED3DRS_POINTSCALEENABLE :
4186 * POINTSCALEENABLE controls how point size value is treated. If set to
4187 * true, the point size is scaled with respect to height of viewport.
4188 * When set to false point size is in pixels.
4190 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4193 /* Default values */
4194 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4197 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4198 * This means that OpenGL will clamp really small point sizes to 1.0f.
4199 * To correct for this we need to multiply by the scale factor when sizes
4200 * are less than 1.0f. scale_factor = 1.0f / point_size.
4202 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4203 if(pointSize > 0.0f) {
4204 GLfloat scaleFactor;
4206 if(pointSize < 1.0f) {
4207 scaleFactor = pointSize * pointSize;
4208 } else {
4209 scaleFactor = 1.0f;
4212 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4213 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4214 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4215 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4216 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4217 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4218 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4222 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4223 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4224 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4226 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4227 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4228 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4229 } else {
4230 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4232 break;
4234 case WINED3DRS_COLORWRITEENABLE :
4236 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4237 Value & WINED3DCOLORWRITEENABLE_RED ? 1 : 0,
4238 Value & WINED3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4239 Value & WINED3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4240 Value & WINED3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4241 glColorMask(Value & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4242 Value & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4243 Value & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4244 Value & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4245 checkGLcall("glColorMask(...)");
4247 break;
4249 case WINED3DRS_LOCALVIEWER :
4251 GLint state = (Value) ? 1 : 0;
4252 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4253 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4255 break;
4257 case WINED3DRS_LASTPIXEL :
4259 if (Value) {
4260 TRACE("Last Pixel Drawing Enabled\n");
4261 } else {
4262 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4265 break;
4267 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4269 if (Value) {
4270 TRACE("Software Processing Enabled\n");
4271 } else {
4272 TRACE("Software Processing Disabled\n");
4275 break;
4277 /** not supported */
4278 case WINED3DRS_ZVISIBLE :
4280 LEAVE_GL();
4281 return WINED3DERR_INVALIDCALL;
4283 case WINED3DRS_POINTSPRITEENABLE :
4285 /* TODO: NV_POINT_SPRITE */
4286 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4287 TRACE("Point sprites not supported\n");
4288 break;
4292 * Point sprites are always enabled. Value controls texture coordinate
4293 * replacement mode. Must be set true for point sprites to use
4294 * textures.
4296 glEnable(GL_POINT_SPRITE_ARB);
4297 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4299 if (Value) {
4300 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4301 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4302 } else {
4303 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4304 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4306 break;
4308 case WINED3DRS_EDGEANTIALIAS :
4310 if(Value) {
4311 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4312 glEnable(GL_BLEND);
4313 checkGLcall("glEnable(GL_BLEND)");
4314 glEnable(GL_LINE_SMOOTH);
4315 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4316 } else {
4317 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4318 glDisable(GL_BLEND);
4319 checkGLcall("glDisable(GL_BLEND)");
4321 glDisable(GL_LINE_SMOOTH);
4322 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4324 break;
4326 case WINED3DRS_WRAP0 :
4327 case WINED3DRS_WRAP1 :
4328 case WINED3DRS_WRAP2 :
4329 case WINED3DRS_WRAP3 :
4330 case WINED3DRS_WRAP4 :
4331 case WINED3DRS_WRAP5 :
4332 case WINED3DRS_WRAP6 :
4333 case WINED3DRS_WRAP7 :
4334 case WINED3DRS_WRAP8 :
4335 case WINED3DRS_WRAP9 :
4336 case WINED3DRS_WRAP10 :
4337 case WINED3DRS_WRAP11 :
4338 case WINED3DRS_WRAP12 :
4339 case WINED3DRS_WRAP13 :
4340 case WINED3DRS_WRAP14 :
4341 case WINED3DRS_WRAP15 :
4343 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4344 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4345 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4346 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4347 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4349 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4352 if(Value) {
4353 ERR("(%p)->(%s,%d) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4355 break;
4358 case WINED3DRS_MULTISAMPLEANTIALIAS :
4360 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4361 if(Value) {
4362 glEnable(GL_MULTISAMPLE_ARB);
4363 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4364 } else {
4365 glDisable(GL_MULTISAMPLE_ARB);
4366 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4368 } else {
4369 if(Value) {
4370 ERR("Multisample antialiasing not supported by gl\n");
4373 break;
4376 case WINED3DRS_SCISSORTESTENABLE :
4378 if(Value) {
4379 glEnable(GL_SCISSOR_TEST);
4380 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4381 } else {
4382 glDisable(GL_SCISSOR_TEST);
4383 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4385 break;
4387 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4389 if(Value) {
4390 tmpvalue.d = Value;
4391 glEnable(GL_POLYGON_OFFSET_FILL);
4392 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4393 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4394 checkGLcall("glPolygonOffset(...)");
4395 } else {
4396 glDisable(GL_POLYGON_OFFSET_FILL);
4397 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4399 break;
4401 case WINED3DRS_ANTIALIASEDLINEENABLE :
4403 if(Value) {
4404 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4405 glEnable(GL_BLEND);
4406 checkGLcall("glEnable(GL_BLEND)");
4407 glEnable(GL_LINE_SMOOTH);
4408 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4409 } else {
4410 glDisable(GL_BLEND);
4411 checkGLcall("glDisable(GL_BLEND)");
4412 glDisable(GL_LINE_SMOOTH);
4413 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4415 break;
4417 case WINED3DRS_DEPTHBIAS :
4419 if(Value) {
4420 tmpvalue.d = Value;
4421 glEnable(GL_POLYGON_OFFSET_FILL);
4422 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4423 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4424 checkGLcall("glPolygonOffset(...)");
4425 } else {
4426 glDisable(GL_POLYGON_OFFSET_FILL);
4427 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4429 break;
4432 case WINED3DRS_TEXTUREPERSPECTIVE :
4434 if (Value)
4435 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4436 else
4437 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4438 break;
4441 case WINED3DRS_STIPPLEDALPHA :
4443 if (Value)
4444 ERR(" Stippled Alpha not supported yet.\n");
4445 break;
4447 case WINED3DRS_ANTIALIAS :
4449 if (Value)
4450 ERR(" Antialias not supported yet.\n");
4451 break;
4454 case WINED3DRS_MULTISAMPLEMASK :
4456 if(0xFFFFFFFF != Value)
4457 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4458 break;
4461 case WINED3DRS_PATCHEDGESTYLE :
4463 if(WINED3DPATCHEDGE_DISCRETE != Value)
4464 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4465 break;
4468 case WINED3DRS_PATCHSEGMENTS :
4470 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4471 tmpvalue.f = 1.0f;
4472 if(tmpvalue.d != Value)
4473 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4474 break;
4477 case WINED3DRS_DEBUGMONITORTOKEN :
4479 /* Only useful for "debug builds". */
4480 if(0xbaadcafe != Value) {
4481 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4482 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4483 * but our tests disagree.
4484 * We do not claim to implement a debugging lib, so do not write an ERR
4486 WARN("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4488 break;
4491 case WINED3DRS_POSITIONDEGREE :
4493 if(WINED3DDEGREE_CUBIC != Value)
4494 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4495 break;
4498 case WINED3DRS_NORMALDEGREE :
4500 if(WINED3DDEGREE_LINEAR != Value)
4501 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4502 break;
4505 case WINED3DRS_MINTESSELLATIONLEVEL :
4506 case WINED3DRS_MAXTESSELLATIONLEVEL :
4507 case WINED3DRS_ADAPTIVETESS_X :
4508 case WINED3DRS_ADAPTIVETESS_Y :
4509 case WINED3DRS_ADAPTIVETESS_Z :
4510 case WINED3DRS_ADAPTIVETESS_W :
4512 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4513 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4514 else
4515 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4516 break;
4519 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4521 if(Value)
4522 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4523 break;
4526 case WINED3DRS_COLORWRITEENABLE1 :
4527 case WINED3DRS_COLORWRITEENABLE2 :
4528 case WINED3DRS_COLORWRITEENABLE3 :
4530 /* depends on WINED3DRS_COLORWRITEENABLE. */
4531 if(0x0000000F != Value)
4532 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4533 break;
4536 case WINED3DRS_BLENDFACTOR :
4538 float col[4];
4540 TRACE("Setting BlendFactor to %d\n", Value);
4542 D3DCOLORTOGLFLOAT4(Value, col);
4543 if (0xFFFFFFFF != Value) {
4544 glEnable(GL_BLEND);
4545 checkGLcall("glEnable(GL_BLEND)");
4547 else {
4548 glDisable(GL_BLEND);
4549 checkGLcall("glDisable(GL_BLEND)");
4551 glBlendColor (col[0],col[1],col[2],col[3]);
4552 break;
4555 case WINED3DRS_SRGBWRITEENABLE :
4557 if(Value)
4558 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4559 break;
4562 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4564 if(Value)
4565 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4566 break;
4569 case WINED3DRS_SRCBLENDALPHA :
4570 case WINED3DRS_DESTBLENDALPHA :
4571 case WINED3DRS_BLENDOPALPHA :
4573 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4574 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4575 else
4576 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4577 break;
4580 default:
4581 FIXME("(%p)->(%s,%d) unknown state\n", This, debug_d3drenderstate(State), Value);
4584 LEAVE_GL();
4586 return WINED3D_OK;
4589 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
4590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4591 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
4592 *pValue = This->stateBlock->renderState[State];
4593 return WINED3D_OK;
4596 /*****
4597 * Get / Set Sampler States
4598 * TODO: Verify against dx9 definitions
4599 *****/
4601 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4604 * SetSampler is designed to allow for more than the standard up to 8 textures
4605 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4606 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4608 * http://developer.nvidia.com/object/General_FAQ.html#t6
4610 * There are two new settings for GForce
4611 * the sampler one:
4612 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4613 * and the texture one:
4614 * GL_MAX_TEXTURE_COORDS_ARB.
4615 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4616 ******************/
4617 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4618 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4619 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4620 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4621 return WINED3DERR_INVALIDCALL;
4624 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
4625 debug_d3dsamplerstate(Type), Type, Value);
4626 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4627 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4628 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4630 /* Handle recording of state blocks */
4631 if (This->isRecordingState) {
4632 TRACE("Recording... not performing anything\n");
4633 return WINED3D_OK;
4636 return WINED3D_OK;
4639 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 /** TODO: check that sampler is in range **/
4642 *Value = This->stateBlock->samplerState[Sampler][Type];
4643 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
4645 return WINED3D_OK;
4648 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 RECT windowRect;
4651 UINT winHeight;
4653 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
4654 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
4655 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
4657 winHeight = windowRect.bottom - windowRect.top;
4658 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
4659 pRect->right - pRect->left, pRect->bottom - pRect->top);
4660 ENTER_GL();
4661 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
4662 checkGLcall("glScissor");
4663 LEAVE_GL();
4665 return WINED3D_OK;
4668 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 GLint scissorBox[4];
4672 ENTER_GL();
4673 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4674 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4675 pRect->left = scissorBox[0];
4676 pRect->top = scissorBox[1];
4677 pRect->right = scissorBox[0] + scissorBox[2];
4678 pRect->bottom = scissorBox[1] + scissorBox[3];
4679 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4680 LEAVE_GL();
4681 return WINED3D_OK;
4684 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4686 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4688 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4690 This->updateStateBlock->vertexDecl = pDecl;
4691 This->updateStateBlock->changed.vertexDecl = TRUE;
4692 This->updateStateBlock->set.vertexDecl = TRUE;
4694 if (This->isRecordingState) {
4695 TRACE("Recording... not performing anything\n");
4698 if (NULL != pDecl) {
4699 IWineD3DVertexDeclaration_AddRef(pDecl);
4701 if (NULL != oldDecl) {
4702 IWineD3DVertexDeclaration_Release(oldDecl);
4704 return WINED3D_OK;
4707 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4710 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4712 *ppDecl = This->stateBlock->vertexDecl;
4713 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4714 return WINED3D_OK;
4717 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4721 This->updateStateBlock->vertexShader = pShader;
4722 This->updateStateBlock->changed.vertexShader = TRUE;
4723 This->updateStateBlock->set.vertexShader = TRUE;
4725 if (This->isRecordingState) {
4726 TRACE("Recording... not performing anything\n");
4729 if (NULL != pShader) {
4730 IWineD3DVertexShader_AddRef(pShader);
4732 if (NULL != oldShader) {
4733 IWineD3DVertexShader_Release(oldShader);
4736 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4738 * TODO: merge HAL shaders context switching from prototype
4740 return WINED3D_OK;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4746 if (NULL == ppShader) {
4747 return WINED3DERR_INVALIDCALL;
4749 *ppShader = This->stateBlock->vertexShader;
4750 if( NULL != *ppShader)
4751 IWineD3DVertexShader_AddRef(*ppShader);
4753 TRACE("(%p) : returning %p\n", This, *ppShader);
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4758 IWineD3DDevice *iface,
4759 UINT start,
4760 CONST BOOL *srcData,
4761 UINT count) {
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 int i, cnt = min(count, MAX_CONST_B - start);
4766 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4767 iface, srcData, start, count);
4769 if (srcData == NULL || cnt < 0)
4770 return WINED3DERR_INVALIDCALL;
4772 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4773 for (i = 0; i < cnt; i++)
4774 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4776 for (i = start; i < cnt + start; ++i) {
4777 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4778 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4781 return WINED3D_OK;
4784 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4785 IWineD3DDevice *iface,
4786 UINT start,
4787 BOOL *dstData,
4788 UINT count) {
4790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4791 int cnt = min(count, MAX_CONST_B - start);
4793 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4794 iface, dstData, start, count);
4796 if (dstData == NULL || cnt < 0)
4797 return WINED3DERR_INVALIDCALL;
4799 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4800 return WINED3D_OK;
4803 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4804 IWineD3DDevice *iface,
4805 UINT start,
4806 CONST int *srcData,
4807 UINT count) {
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4810 int i, cnt = min(count, MAX_CONST_I - start);
4812 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4813 iface, srcData, start, count);
4815 if (srcData == NULL || cnt < 0)
4816 return WINED3DERR_INVALIDCALL;
4818 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4819 for (i = 0; i < cnt; i++)
4820 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4821 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4823 for (i = start; i < cnt + start; ++i) {
4824 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4825 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4828 return WINED3D_OK;
4831 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4832 IWineD3DDevice *iface,
4833 UINT start,
4834 int *dstData,
4835 UINT count) {
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838 int cnt = min(count, MAX_CONST_I - start);
4840 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4841 iface, dstData, start, count);
4843 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4844 return WINED3DERR_INVALIDCALL;
4846 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4847 return WINED3D_OK;
4850 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4851 IWineD3DDevice *iface,
4852 UINT start,
4853 CONST float *srcData,
4854 UINT count) {
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4857 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4859 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4860 iface, srcData, start, count);
4862 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4863 return WINED3DERR_INVALIDCALL;
4865 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4866 for (i = 0; i < cnt; i++)
4867 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4868 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4870 for (i = start; i < cnt + start; ++i) {
4871 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4872 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4873 ptr->idx = i;
4874 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4875 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4877 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4880 return WINED3D_OK;
4883 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4884 IWineD3DDevice *iface,
4885 UINT start,
4886 float *dstData,
4887 UINT count) {
4889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4890 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4892 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4893 iface, dstData, start, count);
4895 if (dstData == NULL || cnt < 0)
4896 return WINED3DERR_INVALIDCALL;
4898 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4899 return WINED3D_OK;
4902 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4904 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4905 This->updateStateBlock->pixelShader = pShader;
4906 This->updateStateBlock->changed.pixelShader = TRUE;
4907 This->updateStateBlock->set.pixelShader = TRUE;
4909 /* Handle recording of state blocks */
4910 if (This->isRecordingState) {
4911 TRACE("Recording... not performing anything\n");
4914 if (NULL != pShader) {
4915 IWineD3DPixelShader_AddRef(pShader);
4917 if (NULL != oldShader) {
4918 IWineD3DPixelShader_Release(oldShader);
4921 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4923 * TODO: merge HAL shaders context switching from prototype
4925 return WINED3D_OK;
4928 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 if (NULL == ppShader) {
4932 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4933 return WINED3DERR_INVALIDCALL;
4936 *ppShader = This->stateBlock->pixelShader;
4937 if (NULL != *ppShader) {
4938 IWineD3DPixelShader_AddRef(*ppShader);
4940 TRACE("(%p) : returning %p\n", This, *ppShader);
4941 return WINED3D_OK;
4944 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4945 IWineD3DDevice *iface,
4946 UINT start,
4947 CONST BOOL *srcData,
4948 UINT count) {
4950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4951 int i, cnt = min(count, MAX_CONST_B - start);
4953 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4954 iface, srcData, start, count);
4956 if (srcData == NULL || cnt < 0)
4957 return WINED3DERR_INVALIDCALL;
4959 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4960 for (i = 0; i < cnt; i++)
4961 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4963 for (i = start; i < cnt + start; ++i) {
4964 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4965 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4968 return WINED3D_OK;
4971 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4972 IWineD3DDevice *iface,
4973 UINT start,
4974 BOOL *dstData,
4975 UINT count) {
4977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4978 int cnt = min(count, MAX_CONST_B - start);
4980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4981 iface, dstData, start, count);
4983 if (dstData == NULL || cnt < 0)
4984 return WINED3DERR_INVALIDCALL;
4986 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4987 return WINED3D_OK;
4990 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4991 IWineD3DDevice *iface,
4992 UINT start,
4993 CONST int *srcData,
4994 UINT count) {
4996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4997 int i, cnt = min(count, MAX_CONST_I - start);
4999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5000 iface, srcData, start, count);
5002 if (srcData == NULL || cnt < 0)
5003 return WINED3DERR_INVALIDCALL;
5005 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
5006 for (i = 0; i < cnt; i++)
5007 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
5008 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5010 for (i = start; i < cnt + start; ++i) {
5011 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
5012 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
5015 return WINED3D_OK;
5018 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
5019 IWineD3DDevice *iface,
5020 UINT start,
5021 int *dstData,
5022 UINT count) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5025 int cnt = min(count, MAX_CONST_I - start);
5027 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5028 iface, dstData, start, count);
5030 if (dstData == NULL || cnt < 0)
5031 return WINED3DERR_INVALIDCALL;
5033 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5034 return WINED3D_OK;
5037 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5038 IWineD3DDevice *iface,
5039 UINT start,
5040 CONST float *srcData,
5041 UINT count) {
5043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5044 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5046 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5047 iface, srcData, start, count);
5049 if (srcData == NULL || cnt < 0)
5050 return WINED3DERR_INVALIDCALL;
5052 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5053 for (i = 0; i < cnt; i++)
5054 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5055 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5057 for (i = start; i < cnt + start; ++i) {
5058 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5059 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5060 ptr->idx = i;
5061 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5062 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5064 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5067 return WINED3D_OK;
5070 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5071 IWineD3DDevice *iface,
5072 UINT start,
5073 float *dstData,
5074 UINT count) {
5076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5077 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5079 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5080 iface, dstData, start, count);
5082 if (dstData == NULL || cnt < 0)
5083 return WINED3DERR_INVALIDCALL;
5085 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5086 return WINED3D_OK;
5089 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5090 static HRESULT
5091 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5092 char *dest_ptr, *dest_conv = NULL;
5093 unsigned int i;
5094 DWORD DestFVF = dest->fvf;
5095 WINED3DVIEWPORT vp;
5096 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
5097 BOOL doClip;
5098 int numTextures;
5100 if (SrcFVF & WINED3DFVF_NORMAL) {
5101 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5104 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
5105 ERR("Source has no position mask\n");
5106 return WINED3DERR_INVALIDCALL;
5109 /* We might access VBOs from this code, so hold the lock */
5110 ENTER_GL();
5112 if (dest->resource.allocatedMemory == NULL) {
5113 /* This may happen if we do direct locking into a vbo. Unlikely,
5114 * but theoretically possible(ddraw processvertices test)
5116 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5117 if(!dest->resource.allocatedMemory) {
5118 LEAVE_GL();
5119 ERR("Out of memory\n");
5120 return E_OUTOFMEMORY;
5122 if(dest->vbo) {
5123 void *src;
5124 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5125 checkGLcall("glBindBufferARB");
5126 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5127 if(src) {
5128 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5130 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5131 checkGLcall("glUnmapBufferARB");
5135 /* Get a pointer into the destination vbo(create one if none exists) and
5136 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5138 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5139 CreateVBO(dest);
5142 if(dest->vbo) {
5143 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5144 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5145 if(!dest_conv) {
5146 ERR("glMapBuffer failed\n");
5147 /* Continue without storing converted vertices */
5151 /* Should I clip?
5152 * a) WINED3DRS_CLIPPING is enabled
5153 * b) WINED3DVOP_CLIP is passed
5155 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5156 static BOOL warned = FALSE;
5158 * The clipping code is not quite correct. Some things need
5159 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5160 * so disable clipping for now.
5161 * (The graphics in Half-Life are broken, and my processvertices
5162 * test crashes with IDirect3DDevice3)
5163 doClip = TRUE;
5165 doClip = FALSE;
5166 if(!warned) {
5167 warned = TRUE;
5168 FIXME("Clipping is broken and disabled for now\n");
5170 } else doClip = FALSE;
5171 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5172 if(dest_conv) {
5173 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5176 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5177 WINED3DTS_VIEW,
5178 &view_mat);
5179 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5180 WINED3DTS_PROJECTION,
5181 &proj_mat);
5182 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5183 WINED3DTS_WORLDMATRIX(0),
5184 &world_mat);
5186 TRACE("View mat:\n");
5187 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); \
5188 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); \
5189 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); \
5190 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); \
5192 TRACE("Proj mat:\n");
5193 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); \
5194 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); \
5195 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); \
5196 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); \
5198 TRACE("World mat:\n");
5199 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); \
5200 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); \
5201 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); \
5202 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); \
5204 /* Get the viewport */
5205 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5206 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
5207 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5209 multiply_matrix(&mat,&view_mat,&world_mat);
5210 multiply_matrix(&mat,&proj_mat,&mat);
5212 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
5214 for (i = 0; i < dwCount; i+= 1) {
5215 unsigned int tex_index;
5217 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
5218 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
5219 /* The position first */
5220 float *p =
5221 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5222 float x, y, z, rhw;
5223 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5225 /* Multiplication with world, view and projection matrix */
5226 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);
5227 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);
5228 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);
5229 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);
5231 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5233 /* WARNING: The following things are taken from d3d7 and were not yet checked
5234 * against d3d8 or d3d9!
5237 /* Clipping conditions: From
5238 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5240 * A vertex is clipped if it does not match the following requirements
5241 * -rhw < x <= rhw
5242 * -rhw < y <= rhw
5243 * 0 < z <= rhw
5244 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5246 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5247 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5251 if( !doClip ||
5252 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5253 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5254 ( rhw > eps ) ) ) {
5256 /* "Normal" viewport transformation (not clipped)
5257 * 1) The values are divided by rhw
5258 * 2) The y axis is negative, so multiply it with -1
5259 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5260 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5261 * 4) Multiply x with Width/2 and add Width/2
5262 * 5) The same for the height
5263 * 6) Add the viewpoint X and Y to the 2D coordinates and
5264 * The minimum Z value to z
5265 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5267 * Well, basically it's simply a linear transformation into viewport
5268 * coordinates
5271 x /= rhw;
5272 y /= rhw;
5273 z /= rhw;
5275 y *= -1;
5277 x *= vp.Width / 2;
5278 y *= vp.Height / 2;
5279 z *= vp.MaxZ - vp.MinZ;
5281 x += vp.Width / 2 + vp.X;
5282 y += vp.Height / 2 + vp.Y;
5283 z += vp.MinZ;
5285 rhw = 1 / rhw;
5286 } else {
5287 /* That vertex got clipped
5288 * Contrary to OpenGL it is not dropped completely, it just
5289 * undergoes a different calculation.
5291 TRACE("Vertex got clipped\n");
5292 x += rhw;
5293 y += rhw;
5295 x /= 2;
5296 y /= 2;
5298 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5299 * outside of the main vertex buffer memory. That needs some more
5300 * investigation...
5304 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5307 ( (float *) dest_ptr)[0] = x;
5308 ( (float *) dest_ptr)[1] = y;
5309 ( (float *) dest_ptr)[2] = z;
5310 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5312 dest_ptr += 3 * sizeof(float);
5314 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5315 dest_ptr += sizeof(float);
5318 if(dest_conv) {
5319 float w = 1 / rhw;
5320 ( (float *) dest_conv)[0] = x * w;
5321 ( (float *) dest_conv)[1] = y * w;
5322 ( (float *) dest_conv)[2] = z * w;
5323 ( (float *) dest_conv)[3] = w;
5325 dest_conv += 3 * sizeof(float);
5327 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5328 dest_conv += sizeof(float);
5332 if (DestFVF & WINED3DFVF_PSIZE) {
5333 dest_ptr += sizeof(DWORD);
5334 if(dest_conv) dest_conv += sizeof(DWORD);
5336 if (DestFVF & WINED3DFVF_NORMAL) {
5337 float *normal =
5338 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5339 /* AFAIK this should go into the lighting information */
5340 FIXME("Didn't expect the destination to have a normal\n");
5341 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5342 if(dest_conv) {
5343 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5347 if (DestFVF & WINED3DFVF_DIFFUSE) {
5348 DWORD *color_d =
5349 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5350 if(!color_d) {
5351 static BOOL warned = FALSE;
5353 if(!warned) {
5354 ERR("No diffuse color in source, but destination has one\n");
5355 warned = TRUE;
5358 *( (DWORD *) dest_ptr) = 0xffffffff;
5359 dest_ptr += sizeof(DWORD);
5361 if(dest_conv) {
5362 *( (DWORD *) dest_conv) = 0xffffffff;
5363 dest_conv += sizeof(DWORD);
5366 else {
5367 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5368 if(dest_conv) {
5369 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5370 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5371 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5372 dest_conv += sizeof(DWORD);
5377 if (DestFVF & WINED3DFVF_SPECULAR) {
5378 /* What's the color value in the feedback buffer? */
5379 DWORD *color_s =
5380 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5381 if(!color_s) {
5382 static BOOL warned = FALSE;
5384 if(!warned) {
5385 ERR("No specular color in source, but destination has one\n");
5386 warned = TRUE;
5389 *( (DWORD *) dest_ptr) = 0xFF000000;
5390 dest_ptr += sizeof(DWORD);
5392 if(dest_conv) {
5393 *( (DWORD *) dest_conv) = 0xFF000000;
5394 dest_conv += sizeof(DWORD);
5397 else {
5398 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5399 if(dest_conv) {
5400 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5401 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5402 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5403 dest_conv += sizeof(DWORD);
5408 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5409 float *tex_coord =
5410 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5411 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5412 if(!tex_coord) {
5413 ERR("No source texture, but destination requests one\n");
5414 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5415 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5417 else {
5418 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5419 if(dest_conv) {
5420 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5426 if(dest_conv) {
5427 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5428 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5431 LEAVE_GL();
5433 return WINED3D_OK;
5435 #undef copy_and_next
5437 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5439 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5440 WineDirect3DVertexStridedData strided;
5441 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5443 if (!SrcImpl) {
5444 WARN("NULL source vertex buffer\n");
5445 return WINED3DERR_INVALIDCALL;
5447 /* We don't need the source vbo because this buffer is only used as
5448 * a source for ProcessVertices. Avoid wasting resources by converting the
5449 * buffer and loading the VBO
5451 if(SrcImpl->vbo) {
5452 TRACE("Releasing the source vbo, it won't be needed\n");
5454 if(!SrcImpl->resource.allocatedMemory) {
5455 /* Rescue the data from the buffer */
5456 void *src;
5457 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5458 if(!SrcImpl->resource.allocatedMemory) {
5459 ERR("Out of memory\n");
5460 return E_OUTOFMEMORY;
5463 ENTER_GL();
5464 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5465 checkGLcall("glBindBufferARB");
5467 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5468 if(src) {
5469 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5472 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5473 checkGLcall("glUnmapBufferARB");
5474 } else {
5475 ENTER_GL();
5478 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5479 checkGLcall("glBindBufferARB");
5480 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5481 checkGLcall("glDeleteBuffersARB");
5482 LEAVE_GL();
5484 SrcImpl->vbo = 0;
5487 memset(&strided, 0, sizeof(strided));
5488 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5490 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5493 /*****
5494 * Apply / Get / Set Texture Stage States
5495 * TODO: Verify against dx9 definitions
5496 *****/
5498 /* 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 */
5499 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5501 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5502 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5504 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5506 /* Check that the stage is within limits */
5507 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5508 TRACE("Attempt to access invalid texture rejected\n");
5509 return;
5512 ENTER_GL();
5514 switch (Type) {
5515 case WINED3DTSS_ALPHAOP :
5516 case WINED3DTSS_COLOROP :
5517 /* nothing to do as moved to drawprim for now */
5518 break;
5519 case WINED3DTSS_ADDRESSW :
5520 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5521 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5522 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
5524 } else {
5525 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5526 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5527 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5528 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5530 #endif
5531 case WINED3DTSS_TEXCOORDINDEX :
5533 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5535 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5536 one flag, you can still specify an index value, which the system uses to
5537 determine the texture wrapping mode.
5538 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5539 means use the vertex position (camera-space) as the input texture coordinates
5540 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5541 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
5542 to the TEXCOORDINDEX value */
5545 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5547 switch (Value & 0xFFFF0000) {
5548 case WINED3DTSS_TCI_PASSTHRU:
5549 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5550 glDisable(GL_TEXTURE_GEN_S);
5551 glDisable(GL_TEXTURE_GEN_T);
5552 glDisable(GL_TEXTURE_GEN_R);
5553 glDisable(GL_TEXTURE_GEN_Q);
5554 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5555 break;
5557 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
5558 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5559 as the input texture coordinates for this stage's texture transformation. This
5560 equates roughly to EYE_LINEAR */
5562 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5563 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5564 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5565 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5566 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5568 glMatrixMode(GL_MODELVIEW);
5569 glPushMatrix();
5570 glLoadIdentity();
5571 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5572 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5573 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5574 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5575 glPopMatrix();
5577 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5578 glEnable(GL_TEXTURE_GEN_S);
5579 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5580 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5581 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5582 glEnable(GL_TEXTURE_GEN_T);
5583 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5584 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5585 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5586 glEnable(GL_TEXTURE_GEN_R);
5587 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5588 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5589 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5591 break;
5593 case WINED3DTSS_TCI_CAMERASPACENORMAL:
5595 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5596 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5597 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5598 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5599 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5600 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5602 glMatrixMode(GL_MODELVIEW);
5603 glPushMatrix();
5604 glLoadIdentity();
5605 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5606 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5607 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5608 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5609 glPopMatrix();
5611 glEnable(GL_TEXTURE_GEN_S);
5612 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5613 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5614 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5615 glEnable(GL_TEXTURE_GEN_T);
5616 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5617 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5618 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5619 glEnable(GL_TEXTURE_GEN_R);
5620 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5621 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5622 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5625 break;
5627 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5629 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5630 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5631 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5632 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5633 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5634 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5636 glMatrixMode(GL_MODELVIEW);
5637 glPushMatrix();
5638 glLoadIdentity();
5639 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5640 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5641 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5642 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5643 glPopMatrix();
5645 glEnable(GL_TEXTURE_GEN_S);
5646 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5647 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5648 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5649 glEnable(GL_TEXTURE_GEN_T);
5650 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5651 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5652 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5653 glEnable(GL_TEXTURE_GEN_R);
5654 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5655 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5656 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5659 break;
5661 /* Unhandled types: */
5662 default:
5663 /* Todo: */
5664 /* ? disable GL_TEXTURE_GEN_n ? */
5665 glDisable(GL_TEXTURE_GEN_S);
5666 glDisable(GL_TEXTURE_GEN_T);
5667 glDisable(GL_TEXTURE_GEN_R);
5668 glDisable(GL_TEXTURE_GEN_Q);
5669 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
5670 break;
5673 break;
5675 /* Unhandled */
5676 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5677 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU);
5678 break;
5680 case WINED3DTSS_BUMPENVMAT00 :
5681 case WINED3DTSS_BUMPENVMAT01 :
5682 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5683 break;
5684 case WINED3DTSS_BUMPENVMAT10 :
5685 case WINED3DTSS_BUMPENVMAT11 :
5686 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5687 break;
5689 case WINED3DTSS_BUMPENVLSCALE :
5690 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5691 break;
5693 case WINED3DTSS_BUMPENVLOFFSET :
5694 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5695 break;
5697 case WINED3DTSS_RESULTARG :
5698 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5699 break;
5701 default:
5702 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
5703 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5706 LEAVE_GL();
5708 return;
5711 /*****
5712 * Get / Set Texture Stage States
5713 * TODO: Verify against dx9 definitions
5714 *****/
5715 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5718 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5720 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5722 /* Reject invalid texture units */
5723 if (Stage >= GL_LIMITS(texture_stages)) {
5724 TRACE("Attempt to access invalid texture rejected\n");
5725 return WINED3DERR_INVALIDCALL;
5728 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5729 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5730 This->updateStateBlock->textureState[Stage][Type] = Value;
5732 return WINED3D_OK;
5735 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5738 *pValue = This->updateStateBlock->textureState[Stage][Type];
5739 return WINED3D_OK;
5742 /*****
5743 * Get / Set Texture
5744 *****/
5745 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5748 IWineD3DBaseTexture *oldTexture;
5750 oldTexture = This->updateStateBlock->textures[Stage];
5751 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
5753 #if 0 /* TODO: check so vertex textures */
5754 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5755 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5756 return WINED3D_OK;
5758 #endif
5760 /* Reject invalid texture units */
5761 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5762 WARN("Attempt to access invalid texture rejected\n");
5763 return WINED3DERR_INVALIDCALL;
5766 if(pTexture != NULL) {
5767 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5769 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5770 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5771 return WINED3DERR_INVALIDCALL;
5775 oldTexture = This->updateStateBlock->textures[Stage];
5776 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5777 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5779 This->updateStateBlock->set.textures[Stage] = TRUE;
5780 This->updateStateBlock->changed.textures[Stage] = TRUE;
5781 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5782 This->updateStateBlock->textures[Stage] = pTexture;
5784 /* Handle recording of state blocks */
5785 if (This->isRecordingState) {
5786 TRACE("Recording... not performing anything\n");
5787 return WINED3D_OK;
5790 /** NOTE: MSDN says that setTexture increases the reference count,
5791 * and the the application nust set the texture back to null (or have a leaky application),
5792 * This means we should pass the refcount up to the parent
5793 *******************************/
5794 if (NULL != This->updateStateBlock->textures[Stage]) {
5795 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5798 if (NULL != oldTexture) {
5799 IWineD3DBaseTexture_Release(oldTexture);
5802 /* Reset color keying */
5803 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5804 BOOL enable_ckey = FALSE;
5806 if(pTexture) {
5807 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5808 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5811 if(enable_ckey) {
5812 glAlphaFunc(GL_NOTEQUAL, 0.0);
5813 checkGLcall("glAlphaFunc");
5817 return WINED3D_OK;
5820 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5824 /* Reject invalid texture units */
5825 if (Stage >= GL_LIMITS(sampler_stages)) {
5826 TRACE("Attempt to access invalid texture rejected\n");
5827 return WINED3DERR_INVALIDCALL;
5829 *ppTexture=This->stateBlock->textures[Stage];
5830 if (*ppTexture)
5831 IWineD3DBaseTexture_AddRef(*ppTexture);
5833 return WINED3D_OK;
5836 /*****
5837 * Get Back Buffer
5838 *****/
5839 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5840 IWineD3DSurface **ppBackBuffer) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 IWineD3DSwapChain *swapChain;
5843 HRESULT hr;
5845 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5847 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5848 if (hr == WINED3D_OK) {
5849 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5850 IWineD3DSwapChain_Release(swapChain);
5851 } else {
5852 *ppBackBuffer = NULL;
5854 return hr;
5857 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5859 WARN("(%p) : stub, calling idirect3d for now\n", This);
5860 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5863 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5865 IWineD3DSwapChain *swapChain;
5866 HRESULT hr;
5868 if(iSwapChain > 0) {
5869 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5870 if (hr == WINED3D_OK) {
5871 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5872 IWineD3DSwapChain_Release(swapChain);
5873 } else {
5874 FIXME("(%p) Error getting display mode\n", This);
5876 } else {
5877 /* Don't read the real display mode,
5878 but return the stored mode instead. X11 can't change the color
5879 depth, and some apps are pretty angry if they SetDisplayMode from
5880 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5882 Also don't relay to the swapchain because with ddraw it's possible
5883 that there isn't a swapchain at all */
5884 pMode->Width = This->ddraw_width;
5885 pMode->Height = This->ddraw_height;
5886 pMode->Format = This->ddraw_format;
5887 pMode->RefreshRate = 0;
5888 hr = WINED3D_OK;
5891 return hr;
5894 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 TRACE("(%p)->(%p)\n", This, hWnd);
5898 This->ddraw_window = hWnd;
5899 return WINED3D_OK;
5902 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5904 TRACE("(%p)->(%p)\n", This, hWnd);
5906 *hWnd = This->ddraw_window;
5907 return WINED3D_OK;
5910 /*****
5911 * Stateblock related functions
5912 *****/
5914 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5916 IWineD3DStateBlockImpl *object;
5917 HRESULT temp_result;
5919 TRACE("(%p)\n", This);
5921 if (This->isRecordingState) {
5922 return WINED3DERR_INVALIDCALL;
5925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5926 if (NULL == object ) {
5927 FIXME("(%p)Error allocating memory for stateblock\n", This);
5928 return E_OUTOFMEMORY;
5930 TRACE("(%p) created object %p\n", This, object);
5931 object->wineD3DDevice= This;
5932 /** FIXME: object->parent = parent; **/
5933 object->parent = NULL;
5934 object->blockType = WINED3DSBT_ALL;
5935 object->ref = 1;
5936 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5938 temp_result = allocate_shader_constants(object);
5939 if (WINED3D_OK != temp_result)
5940 return temp_result;
5942 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5943 This->updateStateBlock = object;
5944 This->isRecordingState = TRUE;
5946 TRACE("(%p) recording stateblock %p\n",This , object);
5947 return WINED3D_OK;
5950 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5953 if (!This->isRecordingState) {
5954 FIXME("(%p) not recording! returning error\n", This);
5955 *ppStateBlock = NULL;
5956 return WINED3DERR_INVALIDCALL;
5959 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5960 This->isRecordingState = FALSE;
5961 This->updateStateBlock = This->stateBlock;
5962 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5963 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5964 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5965 return WINED3D_OK;
5968 /*****
5969 * Scene related functions
5970 *****/
5971 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5972 /* At the moment we have no need for any functionality at the beginning
5973 of a scene */
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 TRACE("(%p) : stub\n", This);
5976 return WINED3D_OK;
5979 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5981 TRACE("(%p)\n", This);
5982 ENTER_GL();
5983 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5984 glFlush();
5985 checkGLcall("glFlush");
5987 TRACE("End Scene\n");
5988 /* If we're using FBOs this isn't needed */
5989 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
5991 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5992 IUnknown *targetContainer = NULL;
5993 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5994 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5995 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5996 /** always dirtify for now. we must find a better way to see that surface have been modified
5997 (Modifications should will only occur via draw-primitive, but we do need better locking
5998 switching to render-to-texture should remove the overhead though.
6000 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
6001 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
6002 IWineD3DSurface_PreLoad(This->renderTarget);
6003 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
6004 IUnknown_Release(targetContainer);
6007 This->sceneEnded = TRUE;
6008 LEAVE_GL();
6009 return WINED3D_OK;
6012 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
6013 CONST RECT* pSourceRect, CONST RECT* pDestRect,
6014 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 IWineD3DSwapChain *swapChain = NULL;
6017 int i;
6018 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
6020 TRACE("(%p) Presenting the frame\n", This);
6022 for(i = 0 ; i < swapchains ; i ++) {
6024 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6025 TRACE("presentinng chain %d, %p\n", i, swapChain);
6026 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6027 IWineD3DSwapChain_Release(swapChain);
6030 return WINED3D_OK;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
6034 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
6035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
6038 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
6039 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6040 GLbitfield glMask = 0;
6041 GLboolean old_ztest;
6042 GLfloat old_z_clear_value;
6043 GLint old_stencil_clear_value;
6044 GLfloat old_color_clear_value[4];
6045 unsigned int i;
6046 CONST WINED3DRECT* curRect;
6048 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
6049 Count, pRects, Flags, Z, Stencil);
6051 ENTER_GL();
6053 glEnable(GL_SCISSOR_TEST);
6054 checkGLcall("glEnable GL_SCISSOR_TEST");
6056 if (Count > 0 && pRects) {
6057 curRect = pRects;
6058 } else {
6059 curRect = NULL;
6062 /* Only set the values up once, as they are not changing */
6063 if (Flags & WINED3DCLEAR_STENCIL) {
6064 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6065 glClearStencil(Stencil);
6066 checkGLcall("glClearStencil");
6067 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6068 glStencilMask(0xFFFFFFFF);
6071 if (Flags & WINED3DCLEAR_ZBUFFER) {
6072 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6073 glDepthMask(GL_TRUE);
6074 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6075 glClearDepth(Z);
6076 checkGLcall("glClearDepth");
6077 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6080 if (Flags & WINED3DCLEAR_TARGET) {
6081 TRACE("Clearing screen with glClear to color %x\n", Color);
6082 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6083 glClearColor(D3DCOLOR_R(Color),
6084 D3DCOLOR_G(Color),
6085 D3DCOLOR_B(Color),
6086 D3DCOLOR_A(Color));
6087 checkGLcall("glClearColor");
6089 /* Clear ALL colors! */
6090 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6091 glMask = glMask | GL_COLOR_BUFFER_BIT;
6094 /* Now process each rect in turn */
6095 for (i = 0; i < Count || i == 0; i++) {
6097 if (curRect) {
6098 /* Note gl uses lower left, width/height */
6099 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
6100 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6101 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6102 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6103 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6104 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6105 checkGLcall("glScissor");
6106 } else {
6107 glScissor(This->stateBlock->viewport.X,
6108 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6109 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6110 This->stateBlock->viewport.Width,
6111 This->stateBlock->viewport.Height);
6112 checkGLcall("glScissor");
6115 /* Clear the selected rectangle (or full screen) */
6116 glClear(glMask);
6117 checkGLcall("glClear");
6119 /* Step to the next rectangle */
6120 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
6123 /* Restore the old values (why..?) */
6124 if (Flags & WINED3DCLEAR_STENCIL) {
6125 glClearStencil(old_stencil_clear_value);
6126 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6128 if (Flags & WINED3DCLEAR_ZBUFFER) {
6129 glDepthMask(old_ztest);
6130 glClearDepth(old_z_clear_value);
6132 if (Flags & WINED3DCLEAR_TARGET) {
6133 glClearColor(old_color_clear_value[0],
6134 old_color_clear_value[1],
6135 old_color_clear_value[2],
6136 old_color_clear_value[3]);
6137 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6138 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6139 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6140 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6143 glDisable(GL_SCISSOR_TEST);
6144 checkGLcall("glDisable");
6145 LEAVE_GL();
6147 return WINED3D_OK;
6150 /*****
6151 * Drawing functions
6152 *****/
6153 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6154 UINT PrimitiveCount) {
6156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6157 This->stateBlock->streamIsUP = FALSE;
6159 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6160 debug_d3dprimitivetype(PrimitiveType),
6161 StartVertex, PrimitiveCount);
6162 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6163 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6166 return WINED3D_OK;
6169 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6170 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6171 WINED3DPRIMITIVETYPE PrimitiveType,
6172 INT baseVIndex, UINT minIndex,
6173 UINT NumVertices, UINT startIndex, UINT primCount) {
6175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6176 UINT idxStride = 2;
6177 IWineD3DIndexBuffer *pIB;
6178 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6180 pIB = This->stateBlock->pIndexData;
6181 This->stateBlock->streamIsUP = FALSE;
6183 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6184 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6185 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6187 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6188 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6189 idxStride = 2;
6190 } else {
6191 idxStride = 4;
6194 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6195 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6197 return WINED3D_OK;
6200 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6201 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6202 UINT VertexStreamZeroStride) {
6203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6205 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6206 debug_d3dprimitivetype(PrimitiveType),
6207 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6209 /* release the stream source */
6210 if (This->stateBlock->streamSource[0] != NULL) {
6211 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6214 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6215 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6216 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6217 This->stateBlock->streamIsUP = TRUE;
6219 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6220 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6222 /* MSDN specifies stream zero settings must be set to NULL */
6223 This->stateBlock->streamStride[0] = 0;
6224 This->stateBlock->streamSource[0] = NULL;
6226 /*stream zero settings set to null at end, as per the msdn */
6227 return WINED3D_OK;
6230 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6231 UINT MinVertexIndex, UINT NumVertices,
6232 UINT PrimitiveCount, CONST void* pIndexData,
6233 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6234 UINT VertexStreamZeroStride) {
6235 int idxStride;
6236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6238 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6239 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6240 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6241 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6243 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6244 idxStride = 2;
6245 } else {
6246 idxStride = 4;
6249 /* release the stream and index data */
6250 if (This->stateBlock->streamSource[0] != NULL) {
6251 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6253 if (This->stateBlock->pIndexData) {
6254 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6257 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6258 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6259 This->stateBlock->streamIsUP = TRUE;
6260 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6262 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6264 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6265 This->stateBlock->streamSource[0] = NULL;
6266 This->stateBlock->streamStride[0] = 0;
6267 This->stateBlock->pIndexData = NULL;
6269 return WINED3D_OK;
6272 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6274 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6275 return WINED3D_OK;
6277 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6278 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6280 HRESULT hr = WINED3D_OK;
6281 WINED3DRESOURCETYPE sourceType;
6282 WINED3DRESOURCETYPE destinationType;
6283 int i ,levels;
6285 /* TODO: think about moving the code into IWineD3DBaseTexture */
6287 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6289 /* verify that the source and destination textures aren't NULL */
6290 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6291 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6292 This, pSourceTexture, pDestinationTexture);
6293 hr = WINED3DERR_INVALIDCALL;
6296 if (pSourceTexture == pDestinationTexture) {
6297 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6298 This, pSourceTexture, pDestinationTexture);
6299 hr = WINED3DERR_INVALIDCALL;
6301 /* Verify that the source and destination textures are the same type */
6302 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6303 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6305 if (sourceType != destinationType) {
6306 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6307 This);
6308 hr = WINED3DERR_INVALIDCALL;
6311 /* check that both textures have the identical numbers of levels */
6312 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6313 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6314 hr = WINED3DERR_INVALIDCALL;
6317 if (WINED3D_OK == hr) {
6319 /* Make sure that the destination texture is loaded */
6320 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6322 /* Update every surface level of the texture */
6323 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6325 switch (sourceType) {
6326 case WINED3DRTYPE_TEXTURE:
6328 IWineD3DSurface *srcSurface;
6329 IWineD3DSurface *destSurface;
6331 for (i = 0 ; i < levels ; ++i) {
6332 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6333 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6334 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6335 IWineD3DSurface_Release(srcSurface);
6336 IWineD3DSurface_Release(destSurface);
6337 if (WINED3D_OK != hr) {
6338 WARN("(%p) : Call to update surface failed\n", This);
6339 return hr;
6343 break;
6344 case WINED3DRTYPE_CUBETEXTURE:
6346 IWineD3DSurface *srcSurface;
6347 IWineD3DSurface *destSurface;
6348 WINED3DCUBEMAP_FACES faceType;
6350 for (i = 0 ; i < levels ; ++i) {
6351 /* Update each cube face */
6352 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6353 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6354 if (WINED3D_OK != hr) {
6355 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6356 } else {
6357 TRACE("Got srcSurface %p\n", srcSurface);
6359 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6360 if (WINED3D_OK != hr) {
6361 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6362 } else {
6363 TRACE("Got desrSurface %p\n", destSurface);
6365 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6366 IWineD3DSurface_Release(srcSurface);
6367 IWineD3DSurface_Release(destSurface);
6368 if (WINED3D_OK != hr) {
6369 WARN("(%p) : Call to update surface failed\n", This);
6370 return hr;
6375 break;
6376 #if 0 /* TODO: Add support for volume textures */
6377 case WINED3DRTYPE_VOLUMETEXTURE:
6379 IWineD3DVolume srcVolume = NULL;
6380 IWineD3DSurface destVolume = NULL;
6382 for (i = 0 ; i < levels ; ++i) {
6383 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6384 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6385 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6386 IWineD3DVolume_Release(srcSurface);
6387 IWineD3DVolume_Release(destSurface);
6388 if (WINED3D_OK != hr) {
6389 WARN("(%p) : Call to update volume failed\n", This);
6390 return hr;
6394 break;
6395 #endif
6396 default:
6397 FIXME("(%p) : Unsupported source and destination type\n", This);
6398 hr = WINED3DERR_INVALIDCALL;
6402 return hr;
6405 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6406 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6407 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6410 TRACE("(%p) : stub\n", This);
6411 return WINED3D_OK;
6413 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6415 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6416 * NOTE It may be best to move the code into surface to occomplish this
6417 ****************************************/
6419 WINED3DSURFACE_DESC surfaceDesc;
6420 unsigned int surfaceWidth, surfaceHeight;
6421 glDescriptor *targetGlDescription = NULL;
6422 glDescriptor *surfaceGlDescription = NULL;
6423 IWineD3DSwapChainImpl *container = NULL;
6425 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6426 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6427 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6429 surfaceDesc.Width = &surfaceWidth;
6430 surfaceDesc.Height = &surfaceHeight;
6431 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6432 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6434 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6435 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6436 ENTER_GL();
6437 /* TODO: opengl Context switching for swapchains etc... */
6438 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6439 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6440 glReadBuffer(GL_BACK);
6441 vcheckGLcall("glReadBuffer(GL_BACK)");
6442 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6443 glReadBuffer(GL_FRONT);
6444 vcheckGLcall("glReadBuffer(GL_FRONT)");
6445 } else if (pRenderTarget == This->depthStencilBuffer) {
6446 FIXME("Reading of depthstencil not yet supported\n");
6449 glReadPixels(0,
6451 surfaceWidth,
6452 surfaceHeight,
6453 surfaceGlDescription->glFormat,
6454 surfaceGlDescription->glType,
6455 (void *)IWineD3DSurface_GetData(pSurface));
6456 vcheckGLcall("glReadPixels(...)");
6457 if(NULL != container ){
6458 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6460 } else {
6461 IWineD3DBaseTexture *container;
6462 GLenum textureDimensions = GL_TEXTURE_2D;
6464 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6465 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6466 IWineD3DBaseTexture_Release(container);
6468 /* TODO: 2D -> Cube surface coppies etc.. */
6469 if (surfaceGlDescription->target != textureDimensions) {
6470 FIXME("(%p) : Texture dimension mismatch\n", This);
6472 glEnable(textureDimensions);
6473 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6474 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6475 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6476 vcheckGLcall("glBindTexture");
6477 glGetTexImage(surfaceGlDescription->target,
6478 surfaceGlDescription->level,
6479 surfaceGlDescription->glFormat,
6480 surfaceGlDescription->glType,
6481 (void *)IWineD3DSurface_GetData(pSurface));
6482 glDisable(textureDimensions);
6483 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6486 LEAVE_GL();
6487 return WINED3D_OK;
6490 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6491 IWineD3DSwapChain *swapChain;
6492 HRESULT hr;
6493 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6494 if(hr == WINED3D_OK) {
6495 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6496 IWineD3DSwapChain_Release(swapChain);
6498 return hr;
6501 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6503 /* return a sensible default */
6504 *pNumPasses = 1;
6505 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6506 FIXME("(%p) : stub\n", This);
6507 return WINED3D_OK;
6510 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6512 int j;
6513 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6514 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6515 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6516 return WINED3DERR_INVALIDCALL;
6518 for (j = 0; j < 256; ++j) {
6519 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6520 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6521 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6522 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6524 TRACE("(%p) : returning\n", This);
6525 return WINED3D_OK;
6528 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6530 int j;
6531 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6532 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6533 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6534 return WINED3DERR_INVALIDCALL;
6536 for (j = 0; j < 256; ++j) {
6537 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6538 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6539 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6540 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6542 TRACE("(%p) : returning\n", This);
6543 return WINED3D_OK;
6546 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6548 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6549 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6550 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6551 return WINED3DERR_INVALIDCALL;
6553 /*TODO: stateblocks */
6554 This->currentPalette = PaletteNumber;
6555 TRACE("(%p) : returning\n", This);
6556 return WINED3D_OK;
6559 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6561 if (PaletteNumber == NULL) {
6562 WARN("(%p) : returning Invalid Call\n", This);
6563 return WINED3DERR_INVALIDCALL;
6565 /*TODO: stateblocks */
6566 *PaletteNumber = This->currentPalette;
6567 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6568 return WINED3D_OK;
6571 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6573 static BOOL showFixmes = TRUE;
6574 if (showFixmes) {
6575 FIXME("(%p) : stub\n", This);
6576 showFixmes = FALSE;
6579 This->softwareVertexProcessing = bSoftware;
6580 return WINED3D_OK;
6584 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6586 static BOOL showFixmes = TRUE;
6587 if (showFixmes) {
6588 FIXME("(%p) : stub\n", This);
6589 showFixmes = FALSE;
6591 return This->softwareVertexProcessing;
6595 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6597 IWineD3DSwapChain *swapChain;
6598 HRESULT hr;
6600 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6602 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6603 if(hr == WINED3D_OK){
6604 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6605 IWineD3DSwapChain_Release(swapChain);
6606 }else{
6607 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6609 return hr;
6613 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6615 static BOOL showfixmes = TRUE;
6616 if(nSegments != 0.0f) {
6617 if( showfixmes) {
6618 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6619 showfixmes = FALSE;
6622 return WINED3D_OK;
6625 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6627 static BOOL showfixmes = TRUE;
6628 if( showfixmes) {
6629 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6630 showfixmes = FALSE;
6632 return 0.0f;
6635 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6637 /** TODO: remove casts to IWineD3DSurfaceImpl
6638 * NOTE: move code to surface to accomplish this
6639 ****************************************/
6640 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6641 int srcWidth, srcHeight;
6642 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6643 WINED3DFORMAT destFormat, srcFormat;
6644 UINT destSize;
6645 int destLeft, destTop;
6646 WINED3DPOOL srcPool, destPool;
6647 int offset = 0;
6648 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6649 glDescriptor *glDescription = NULL;
6650 GLenum textureDimensions = GL_TEXTURE_2D;
6651 IWineD3DBaseTexture *baseTexture;
6653 WINED3DSURFACE_DESC winedesc;
6655 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6656 memset(&winedesc, 0, sizeof(winedesc));
6657 winedesc.Width = &srcSurfaceWidth;
6658 winedesc.Height = &srcSurfaceHeight;
6659 winedesc.Pool = &srcPool;
6660 winedesc.Format = &srcFormat;
6662 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6664 winedesc.Width = &destSurfaceWidth;
6665 winedesc.Height = &destSurfaceHeight;
6666 winedesc.Pool = &destPool;
6667 winedesc.Format = &destFormat;
6668 winedesc.Size = &destSize;
6670 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6672 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6673 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6674 return WINED3DERR_INVALIDCALL;
6677 if (destFormat == WINED3DFMT_UNKNOWN) {
6678 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6679 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6681 /* Get the update surface description */
6682 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6685 /* Make sure the surface is loaded and up to date */
6686 IWineD3DSurface_PreLoad(pDestinationSurface);
6688 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6690 ENTER_GL();
6692 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6693 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6694 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6695 destLeft = pDestPoint ? pDestPoint->x : 0;
6696 destTop = pDestPoint ? pDestPoint->y : 0;
6699 /* This function doesn't support compressed textures
6700 the pitch is just bytesPerPixel * width */
6701 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6702 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6703 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6704 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6706 /* TODO DXT formats */
6708 if(pSourceRect != NULL && pSourceRect->top != 0){
6709 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6711 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6712 ,This
6713 ,glDescription->level
6714 ,destLeft
6715 ,destTop
6716 ,srcWidth
6717 ,srcHeight
6718 ,glDescription->glFormat
6719 ,glDescription->glType
6720 ,IWineD3DSurface_GetData(pSourceSurface)
6723 /* Sanity check */
6724 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6726 /* need to lock the surface to get the data */
6727 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6730 /* TODO: Cube and volume support */
6731 if(rowoffset != 0){
6732 /* not a whole row so we have to do it a line at a time */
6733 int j;
6735 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6736 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6738 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6740 glTexSubImage2D(glDescription->target
6741 ,glDescription->level
6742 ,destLeft
6744 ,srcWidth
6746 ,glDescription->glFormat
6747 ,glDescription->glType
6748 ,data /* could be quicker using */
6750 data += rowoffset;
6753 } else { /* Full width, so just write out the whole texture */
6755 if (WINED3DFMT_DXT1 == destFormat ||
6756 WINED3DFMT_DXT2 == destFormat ||
6757 WINED3DFMT_DXT3 == destFormat ||
6758 WINED3DFMT_DXT4 == destFormat ||
6759 WINED3DFMT_DXT5 == destFormat) {
6760 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6761 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6762 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6763 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6764 } if (destFormat != srcFormat) {
6765 FIXME("Updating mixed format compressed texture is not curretly support\n");
6766 } else {
6767 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6768 glDescription->level,
6769 glDescription->glFormatInternal,
6770 srcWidth,
6771 srcHeight,
6773 destSize,
6774 IWineD3DSurface_GetData(pSourceSurface));
6776 } else {
6777 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6781 } else {
6782 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6784 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6785 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6786 data returned by GetData non-power2 width/height with hardware non-power2
6787 pow2Width/height are set to surface width height, repacking isn't needed so it
6788 doesn't matter which function gets called. */
6789 glTexSubImage2D(glDescription->target
6790 ,glDescription->level
6791 ,destLeft
6792 ,destTop
6793 ,srcWidth
6794 ,srcHeight
6795 ,glDescription->glFormat
6796 ,glDescription->glType
6797 ,IWineD3DSurface_GetData(pSourceSurface)
6799 } else {
6801 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6802 glTexSubImage2D(glDescription->target
6803 ,glDescription->level
6804 ,destLeft
6805 ,destTop
6806 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6807 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6808 ,glDescription->glFormat
6809 ,glDescription->glType
6810 ,IWineD3DSurface_GetData(pSourceSurface)
6816 checkGLcall("glTexSubImage2D");
6817 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6819 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6820 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6821 * surface bigger than it needs to be hmm.. */
6822 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6823 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6824 IWineD3DBaseTexture_Release(baseTexture);
6827 glDisable(textureDimensions); /* This needs to be managed better.... */
6828 LEAVE_GL();
6830 return WINED3D_OK;
6833 /* Implementation details at http://developer.nvidia.com/attach/6494
6835 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6836 hmm.. no longer supported use
6837 OpenGL evaluators or tessellate surfaces within your application.
6840 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6841 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6843 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6844 FIXME("(%p) : Stub\n", This);
6845 return WINED3D_OK;
6849 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6850 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6852 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6853 FIXME("(%p) : Stub\n", This);
6854 return WINED3D_OK;
6857 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6859 TRACE("(%p) Handle(%d)\n", This, Handle);
6860 FIXME("(%p) : Stub\n", This);
6861 return WINED3D_OK;
6864 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6866 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6867 DDBLTFX BltFx;
6868 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
6870 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6871 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6872 return WINED3DERR_INVALIDCALL;
6875 /* Just forward this to the DirectDraw blitting engine */
6876 memset(&BltFx, 0, sizeof(BltFx));
6877 BltFx.dwSize = sizeof(BltFx);
6878 BltFx.u5.dwFillColor = color;
6879 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6882 /* rendertarget and deptth stencil functions */
6883 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6886 /* FIXME: Implelent RenderTargetIndex >0 */
6887 if(RenderTargetIndex > 0)
6888 FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
6890 *ppRenderTarget = This->renderTarget;
6891 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6893 return WINED3D_OK;
6896 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6898 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6899 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6900 IWineD3DSwapChainImpl *Swapchain;
6901 HRESULT hr;
6903 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6905 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6906 if(hr != WINED3D_OK) {
6907 ERR("Can't get the swapchain\n");
6908 return hr;
6911 /* Make sure to release the swapchain */
6912 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6914 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6915 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6916 return WINED3DERR_INVALIDCALL;
6918 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6919 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6920 return WINED3DERR_INVALIDCALL;
6923 if(Swapchain->frontBuffer != Front) {
6924 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6926 if(Swapchain->frontBuffer)
6927 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6928 Swapchain->frontBuffer = Front;
6930 if(Swapchain->frontBuffer) {
6931 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6935 if(Back && !Swapchain->backBuffer) {
6936 /* We need memory for the back buffer array - only one back buffer this way */
6937 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6938 if(!Swapchain->backBuffer) {
6939 ERR("Out of memory\n");
6940 return E_OUTOFMEMORY;
6944 if(Swapchain->backBuffer[0] != Back) {
6945 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6946 ENTER_GL();
6947 if(!Swapchain->backBuffer[0]) {
6948 /* GL was told to draw to the front buffer at creation,
6949 * undo that
6951 glDrawBuffer(GL_BACK);
6952 checkGLcall("glDrawBuffer(GL_BACK)");
6953 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6954 Swapchain->presentParms.BackBufferCount = 1;
6955 } else if (!Back) {
6956 /* That makes problems - disable for now */
6957 /* glDrawBuffer(GL_FRONT); */
6958 checkGLcall("glDrawBuffer(GL_FRONT)");
6959 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6960 Swapchain->presentParms.BackBufferCount = 0;
6962 LEAVE_GL();
6964 if(Swapchain->backBuffer[0])
6965 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6966 Swapchain->backBuffer[0] = Back;
6968 if(Swapchain->backBuffer[0]) {
6969 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6970 } else {
6971 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6976 return WINED3D_OK;
6979 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6981 *ppZStencilSurface = This->depthStencilBuffer;
6982 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6984 return WINED3D_OK;
6987 static void bind_fbo(IWineD3DDevice *iface) {
6988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6990 if (!This->fbo) {
6991 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
6992 checkGLcall("glGenFramebuffersEXT()");
6994 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
6995 checkGLcall("glBindFramebuffer()");
6998 /* TODO: Handle stencil attachments */
6999 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
7000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7001 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
7003 This->depth_copy_state = WINED3D_DCS_NO_COPY;
7005 bind_fbo(iface);
7007 if (depth_stencil_impl) {
7008 GLenum texttarget, target;
7010 IWineD3DSurface_PreLoad(depth_stencil);
7011 texttarget = depth_stencil_impl->glDescription.target;
7012 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7014 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
7015 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
7016 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
7017 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
7018 glBindTexture(target, 0);
7020 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
7021 checkGLcall("glFramebufferTexture2DEXT()");
7022 } else {
7023 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
7024 checkGLcall("glFramebufferTexture2DEXT()");
7027 if (!This->render_offscreen) {
7028 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7029 checkGLcall("glBindFramebuffer()");
7033 static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7035 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
7037 if (This->render_offscreen) {
7038 GLenum texttarget, target;
7040 bind_fbo(iface);
7042 IWineD3DSurface_PreLoad(render_target);
7043 texttarget = rtimpl->glDescription.target;
7044 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7046 glBindTexture(target, rtimpl->glDescription.textureName);
7047 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
7048 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
7049 glBindTexture(target, 0);
7051 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texttarget, rtimpl->glDescription.textureName, 0));
7052 checkGLcall("glFramebufferTexture2DEXT()");
7053 } else {
7054 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7055 checkGLcall("glBindFramebuffer()");
7059 /* internal static helper functions */
7060 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7061 IWineD3DSurface *RenderSurface);
7063 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7065 HRESULT hr = WINED3D_OK;
7066 WINED3DVIEWPORT viewport;
7068 TRACE("(%p) Swapping rendertarget\n",This);
7069 if (RenderTargetIndex > 0) {
7070 FIXME("(%p) Render targets other than the first are not supported\n",This);
7071 RenderTargetIndex = 0;
7074 /* MSDN says that null disables the render target
7075 but a device must always be associated with a render target
7076 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7078 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7079 for more details
7081 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7082 FIXME("Trying to set render target 0 to NULL\n");
7083 return WINED3DERR_INVALIDCALL;
7085 /* TODO: replace Impl* usage with interface usage */
7086 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7087 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);
7088 return WINED3DERR_INVALIDCALL;
7090 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7091 * builds, but I think wine counts as a 'debug' build for now.
7092 ******************************/
7093 /* If we are trying to set what we already have, don't bother */
7094 if (pRenderTarget == This->renderTarget) {
7095 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7096 } else {
7097 /* Otherwise, set the render target up */
7099 if (!This->sceneEnded) {
7100 IWineD3DDevice_EndScene(iface);
7102 TRACE("clearing renderer\n");
7103 /* IWineD3DDeviceImpl_CleanRender(iface); */
7104 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7105 depending on the renter target implementation being used.
7106 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7107 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7108 stencil buffer and incure an extra memory overhead */
7109 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7110 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7111 set_render_target_fbo(iface, pRenderTarget);
7115 if (SUCCEEDED(hr)) {
7116 /* Finally, reset the viewport as the MSDN states. */
7117 /* TODO: Replace impl usage */
7118 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7119 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7120 viewport.X = 0;
7121 viewport.Y = 0;
7122 viewport.MaxZ = 1.0f;
7123 viewport.MinZ = 0.0f;
7124 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7125 } else {
7126 FIXME("Unknown error setting the render target\n");
7128 This->sceneEnded = FALSE;
7129 return hr;
7132 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7134 HRESULT hr = WINED3D_OK;
7135 IWineD3DSurface *tmp;
7137 TRACE("(%p) Swapping z-buffer\n",This);
7139 if (pNewZStencil == This->stencilBufferTarget) {
7140 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7141 } else {
7142 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7143 * depending on the renter target implementation being used.
7144 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7145 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7146 * stencil buffer and incure an extra memory overhead
7147 ******************************************************/
7150 tmp = This->stencilBufferTarget;
7151 This->stencilBufferTarget = pNewZStencil;
7152 /* should we be calling the parent or the wined3d surface? */
7153 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7154 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7155 hr = WINED3D_OK;
7156 /** TODO: glEnable/glDisable on depth/stencil depending on
7157 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7158 **********************************************************/
7159 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7160 set_depth_stencil_fbo(iface, pNewZStencil);
7164 return hr;
7168 #ifdef GL_VERSION_1_3
7169 /* Internal functions not in DirectX */
7170 /** TODO: move this off to the opengl context manager
7171 *(the swapchain doesn't need to know anything about offscreen rendering!)
7172 ****************************************************/
7174 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7178 TRACE("(%p), %p\n", This, swapchain);
7180 if (swapchain->win != swapchain->drawable) {
7181 /* Set everything back the way it ws */
7182 swapchain->render_ctx = swapchain->glCtx;
7183 swapchain->drawable = swapchain->win;
7185 return WINED3D_OK;
7188 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7189 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7191 int i;
7192 unsigned int width;
7193 unsigned int height;
7194 WINED3DFORMAT format;
7195 WINED3DSURFACE_DESC surfaceDesc;
7196 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7197 surfaceDesc.Width = &width;
7198 surfaceDesc.Height = &height;
7199 surfaceDesc.Format = &format;
7200 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7201 *context = NULL;
7202 /* I need a get width/height function (and should do something with the format) */
7203 for (i = 0; i < CONTEXT_CACHE; ++i) {
7204 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7205 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7206 the pSurface can be set to 0 allowing it to be reused from cache **/
7207 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7208 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7209 *context = &This->contextCache[i];
7210 break;
7212 if (This->contextCache[i].Width == 0) {
7213 This->contextCache[i].pSurface = pSurface;
7214 This->contextCache[i].Width = width;
7215 This->contextCache[i].Height = height;
7216 *context = &This->contextCache[i];
7217 break;
7220 if (i == CONTEXT_CACHE) {
7221 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7222 glContext *dropContext = 0;
7223 for (i = 0; i < CONTEXT_CACHE; i++) {
7224 if (This->contextCache[i].usedcount < minUsage) {
7225 dropContext = &This->contextCache[i];
7226 minUsage = This->contextCache[i].usedcount;
7229 /* clean up the context (this doesn't work for ATI at the moment */
7230 #if 0
7231 glXDestroyContext(swapchain->display, dropContext->context);
7232 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7233 #endif
7234 FIXME("Leak\n");
7235 dropContext->Width = 0;
7236 dropContext->pSurface = pSurface;
7237 *context = dropContext;
7238 } else {
7239 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7240 for (i = 0; i < CONTEXT_CACHE; i++) {
7241 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7245 if (*context != NULL)
7246 return WINED3D_OK;
7247 else
7248 return E_OUTOFMEMORY;
7250 #endif
7252 /* Reapply the device stateblock */
7253 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7255 BOOL oldRecording;
7256 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7258 /* Disable recording */
7259 oldUpdateStateBlock = This->updateStateBlock;
7260 oldRecording= This->isRecordingState;
7261 This->isRecordingState = FALSE;
7262 This->updateStateBlock = This->stateBlock;
7264 /* Reapply the state block */
7265 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7267 /* Restore recording */
7268 This->isRecordingState = oldRecording;
7269 This->updateStateBlock = oldUpdateStateBlock;
7272 /* Set offscreen rendering. When rendering offscreen the surface will be
7273 * rendered upside down to compensate for the fact that D3D texture coordinates
7274 * are flipped compared to GL texture coordinates. The cullmode is affected by
7275 * this, so it must be updated. To update the cullmode stateblock recording has
7276 * to be temporarily disabled. The new state management code will hopefully
7277 * make this unnecessary */
7278 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7280 DWORD cullMode;
7281 BOOL oldRecording;
7282 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7284 /* Nothing to update, return. */
7285 if (This->render_offscreen == isTexture) return;
7287 /* Disable recording */
7288 oldUpdateStateBlock = This->updateStateBlock;
7289 oldRecording= This->isRecordingState;
7290 This->isRecordingState = FALSE;
7291 This->updateStateBlock = This->stateBlock;
7293 This->render_offscreen = isTexture;
7294 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
7295 This->depth_copy_state = WINED3D_DCS_COPY;
7297 This->last_was_rhw = FALSE;
7298 This->proj_valid = FALSE;
7299 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7300 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7302 /* Restore recording */
7303 This->isRecordingState = oldRecording;
7304 This->updateStateBlock = oldUpdateStateBlock;
7307 /* Returns an array of compatible FBconfig(s).
7308 * The array must be freed with XFree. Requires ENTER_GL() */
7310 static GLXFBConfig* device_find_fbconfigs(
7311 IWineD3DDeviceImpl* This,
7312 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7313 IWineD3DSurface* RenderSurface) {
7315 GLXFBConfig* cfgs = NULL;
7316 int nCfgs = 0;
7317 int attribs[256];
7318 int nAttribs = 0;
7320 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7321 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7322 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7324 /**TODO:
7325 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7326 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7329 #define PUSH1(att) attribs[nAttribs++] = (att);
7330 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7332 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7334 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7335 PUSH2(GLX_X_RENDERABLE, TRUE);
7336 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7337 TRACE("calling makeglcfg\n");
7338 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7339 PUSH1(None);
7340 TRACE("calling chooseFGConfig\n");
7341 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7342 DefaultScreen(implicitSwapchainImpl->display),
7343 attribs, &nCfgs);
7344 if (cfgs == NULL) {
7345 /* OK we didn't find the exact config, so use any reasonable match */
7346 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
7347 why we failed. */
7348 static BOOL show_message = TRUE;
7349 if (show_message) {
7350 ERR("Failed to find exact match, finding alternative but you may "
7351 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7352 show_message = FALSE;
7354 nAttribs = 0;
7355 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7356 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7357 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7358 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7359 TRACE("calling makeglcfg\n");
7360 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7361 PUSH1(None);
7362 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7363 DefaultScreen(implicitSwapchainImpl->display),
7364 attribs, &nCfgs);
7367 if (cfgs == NULL) {
7368 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7369 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7370 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7371 } else {
7372 #ifdef EXTRA_TRACES
7373 int i;
7374 for (i = 0; i < nCfgs; ++i) {
7375 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7376 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7377 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7379 if (NULL != This->renderTarget) {
7380 glFlush();
7381 vcheckGLcall("glFlush");
7382 /** This is only useful if the old render target was a swapchain,
7383 * we need to supercede this with a function that displays
7384 * the current buffer on the screen. This is easy to do in glx1.3 but
7385 * we need to do copy-write pixels in glx 1.2.
7386 ************************************************/
7387 glXSwapBuffers(implicitSwapChainImpl->display,
7388 implicitSwapChainImpl->drawable);
7389 printf("Hit Enter to get next frame ...\n");
7390 getchar();
7392 #endif
7394 #undef PUSH1
7395 #undef PUSH2
7397 return cfgs;
7400 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7401 * the functionality needs splitting up so that we don't do more than we should do.
7402 * this only seems to impact performance a little.
7403 ******************************/
7404 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7405 IWineD3DSurface *RenderSurface) {
7408 * Currently only active for GLX >= 1.3
7409 * for others versions we'll have to use GLXPixmaps
7411 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7412 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7413 * so only check OpenGL version
7414 * ..........................
7415 * I don't believe that it is a problem with NVidia headers,
7416 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7417 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7418 * ATI Note:
7419 * Your application will report GLX version 1.2 on glXQueryVersion.
7420 * However, it is safe to call the GLX 1.3 functions as described below.
7422 #if defined(GL_VERSION_1_3)
7424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7425 GLXFBConfig* cfgs = NULL;
7426 IWineD3DSwapChain *currentSwapchain;
7427 IWineD3DSwapChainImpl *currentSwapchainImpl;
7428 IWineD3DSwapChain *implicitSwapchain;
7429 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7430 IWineD3DSwapChain *renderSurfaceSwapchain;
7431 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7433 /* Obtain a reference to the device implicit swapchain,
7434 * the swapchain of the current render target,
7435 * and the swapchain of the new render target.
7436 * Fallback to device implicit swapchain if the current render target doesn't have one */
7437 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7438 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7439 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7440 if (currentSwapchain == NULL)
7441 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7443 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7444 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7445 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7447 ENTER_GL();
7450 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7451 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7452 **********************************************************************/
7453 if (renderSurfaceSwapchain != NULL) {
7455 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7456 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
7457 TRACE("making swapchain active\n");
7458 if (RenderSurface != This->renderTarget) {
7459 BOOL backbuf = FALSE;
7460 int i;
7462 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7463 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7464 backbuf = TRUE;
7465 break;
7469 if (backbuf) {
7470 } else {
7471 /* This could be flagged so that some operations work directly with the front buffer */
7472 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7474 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7475 renderSurfaceSwapchainImpl->win,
7476 renderSurfaceSwapchainImpl->glCtx) == False) {
7478 TRACE("Error in setting current context: context %p drawable %ld !\n",
7479 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7481 checkGLcall("glXMakeContextCurrent");
7483 /* Clean up the old context */
7484 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7486 /* Reapply the stateblock, and set the device not to render to texture */
7487 device_reapply_stateblock(This);
7488 device_render_to_texture(This, FALSE);
7491 /* Offscreen rendering: PBuffers (currently disabled).
7492 * Also note that this path is never reached if FBOs are supported */
7493 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
7494 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7496 /** ********************************************************************
7497 * This is a quickly hacked out implementation of offscreen textures.
7498 * It will work in most cases but there may be problems if the client
7499 * modifies the texture directly, or expects the contents of the rendertarget
7500 * to be persistent.
7502 * There are some real speed vs compatibility issues here:
7503 * we should really use a new context for every texture, but that eats ram.
7504 * we should also be restoring the texture to the pbuffer but that eats CPU
7505 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7506 * but if this means reusing the display backbuffer then we need to make sure that
7507 * states are correctly preserved.
7508 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7509 * and gain a good performance increase at the cost of compatibility.
7510 * I would suggest that, when this is the case, a user configurable flag be made
7511 * available, allowing the user to choose the best emulated experience for them.
7512 *********************************************************************/
7514 XVisualInfo *visinfo;
7515 glContext *newContext;
7517 /* Here were using a shared context model */
7518 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7519 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7522 /* If the context doesn't exist then create a new one */
7523 /* TODO: This should really be part of findGlContext */
7524 if (NULL == newContext->context) {
7526 int attribs[256];
7527 int nAttribs = 0;
7529 TRACE("making new buffer\n");
7530 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7531 attribs[nAttribs++] = newContext->Width;
7532 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7533 attribs[nAttribs++] = newContext->Height;
7534 attribs[nAttribs++] = None;
7536 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7538 /** ****************************************
7539 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7540 *they note:
7541 * In future releases, we may provide the calls glXCreateNewContext,
7542 * glXQueryDrawable and glXMakeContextCurrent.
7543 * so until then we have to use glXGetVisualFromFBConfig &co..
7544 ********************************************/
7546 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7547 if (!visinfo) {
7548 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7549 } else {
7550 newContext->context = glXCreateContext(
7551 implicitSwapchainImpl->display, visinfo,
7552 implicitSwapchainImpl->glCtx, GL_TRUE);
7554 XFree(visinfo);
7557 if (NULL == newContext || NULL == newContext->context) {
7558 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7559 } else {
7560 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7561 if (glXMakeCurrent(implicitSwapchainImpl->display,
7562 newContext->drawable, newContext->context) == False) {
7564 TRACE("Error in setting current context: context %p drawable %ld\n",
7565 newContext->context, newContext->drawable);
7567 checkGLcall("glXMakeContextCurrent");
7569 /* Clean up the old context */
7570 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7572 /* Reapply stateblock, and set device to render to a texture */
7573 device_reapply_stateblock(This);
7574 device_render_to_texture(This, TRUE);
7576 /* Set the current context of the swapchain to the new context */
7577 implicitSwapchainImpl->drawable = newContext->drawable;
7578 implicitSwapchainImpl->render_ctx = newContext->context;
7580 } else {
7581 /* Same context, but update render_offscreen and cull mode */
7582 device_render_to_texture(This, TRUE);
7585 /* Replace the render target */
7586 if (This->renderTarget != RenderSurface) {
7587 IWineD3DSurface_Release(This->renderTarget);
7588 This->renderTarget = RenderSurface;
7589 IWineD3DSurface_AddRef(RenderSurface);
7592 if (cfgs != NULL) XFree(cfgs);
7593 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
7594 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7595 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7596 LEAVE_GL();
7597 #endif
7598 return WINED3D_OK;
7601 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7602 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7604 /* TODO: the use of Impl is deprecated. */
7605 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7607 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7609 /* some basic validation checks */
7610 if(This->cursorTexture) {
7611 ENTER_GL();
7612 glDeleteTextures(1, &This->cursorTexture);
7613 LEAVE_GL();
7614 This->cursorTexture = 0;
7617 if(pCursorBitmap) {
7618 /* MSDN: Cursor must be A8R8G8B8 */
7619 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7620 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7621 return WINED3DERR_INVALIDCALL;
7624 /* MSDN: Cursor must be smaller than the display mode */
7625 if(pSur->currentDesc.Width > This->ddraw_width ||
7626 pSur->currentDesc.Height > This->ddraw_height) {
7627 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7628 return WINED3DERR_INVALIDCALL;
7631 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7632 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7633 * Texture and Blitting code to draw the cursor
7635 pSur->Flags |= SFLAG_FORCELOAD;
7636 IWineD3DSurface_PreLoad(pCursorBitmap);
7637 pSur->Flags &= ~SFLAG_FORCELOAD;
7638 /* Do not store the surface's pointer because the application may release
7639 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7640 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7642 This->cursorTexture = pSur->glDescription.textureName;
7643 This->cursorWidth = pSur->currentDesc.Width;
7644 This->cursorHeight = pSur->currentDesc.Height;
7645 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7648 This->xHotSpot = XHotSpot;
7649 This->yHotSpot = YHotSpot;
7650 return WINED3D_OK;
7653 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7655 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7657 This->xScreenSpace = XScreenSpace;
7658 This->yScreenSpace = YScreenSpace;
7660 return;
7664 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7666 BOOL oldVisible = This->bCursorVisible;
7667 TRACE("(%p) : visible(%d)\n", This, bShow);
7669 if(This->cursorTexture)
7670 This->bCursorVisible = bShow;
7672 return oldVisible;
7675 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7677 TRACE("(%p) : state (%u)\n", This, This->state);
7678 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7679 switch (This->state) {
7680 case WINED3D_OK:
7681 return WINED3D_OK;
7682 case WINED3DERR_DEVICELOST:
7684 ResourceList *resourceList = This->resources;
7685 while (NULL != resourceList) {
7686 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7687 return WINED3DERR_DEVICENOTRESET;
7688 resourceList = resourceList->next;
7690 return WINED3DERR_DEVICELOST;
7692 case WINED3DERR_DRIVERINTERNALERROR:
7693 return WINED3DERR_DRIVERINTERNALERROR;
7696 /* Unknown state */
7697 return WINED3DERR_DRIVERINTERNALERROR;
7701 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7703 /** FIXME: Resource tracking needs to be done,
7704 * The closes we can do to this is set the priorities of all managed textures low
7705 * and then reset them.
7706 ***********************************************************/
7707 FIXME("(%p) : stub\n", This);
7708 return WINED3D_OK;
7711 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7713 /** FIXME: Resource trascking needs to be done.
7714 * in effect this pulls all non only default
7715 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7716 * and should clear down the context and set it up according to pPresentationParameters
7717 ***********************************************************/
7718 FIXME("(%p) : stub\n", This);
7719 return WINED3D_OK;
7722 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7724 /** FIXME: always true at the moment **/
7725 if(!bEnableDialogs) {
7726 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7728 return WINED3D_OK;
7732 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7734 TRACE("(%p) : pParameters %p\n", This, pParameters);
7736 *pParameters = This->createParms;
7737 return WINED3D_OK;
7740 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7741 IWineD3DSwapChain *swapchain;
7742 HRESULT hrc = WINED3D_OK;
7744 TRACE("Relaying to swapchain\n");
7746 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7747 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7748 IWineD3DSwapChain_Release(swapchain);
7750 return;
7753 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7754 IWineD3DSwapChain *swapchain;
7755 HRESULT hrc = WINED3D_OK;
7757 TRACE("Relaying to swapchain\n");
7759 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7760 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7761 IWineD3DSwapChain_Release(swapchain);
7763 return;
7767 /** ********************************************************
7768 * Notification functions
7769 ** ********************************************************/
7770 /** This function must be called in the release of a resource when ref == 0,
7771 * the contents of resource must still be correct,
7772 * any handels to other resource held by the caller must be closed
7773 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7774 *****************************************************/
7775 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7777 ResourceList* resourceList;
7779 TRACE("(%p) : resource %p\n", This, resource);
7780 #if 0
7781 EnterCriticalSection(&resourceStoreCriticalSection);
7782 #endif
7783 /* add a new texture to the frot of the linked list */
7784 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7785 resourceList->resource = resource;
7787 /* Get the old head */
7788 resourceList->next = This->resources;
7790 This->resources = resourceList;
7791 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7793 #if 0
7794 LeaveCriticalSection(&resourceStoreCriticalSection);
7795 #endif
7796 return;
7799 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7801 ResourceList* resourceList = NULL;
7802 ResourceList* previousResourceList = NULL;
7804 TRACE("(%p) : resource %p\n", This, resource);
7806 #if 0
7807 EnterCriticalSection(&resourceStoreCriticalSection);
7808 #endif
7809 resourceList = This->resources;
7811 while (resourceList != NULL) {
7812 if(resourceList->resource == resource) break;
7813 previousResourceList = resourceList;
7814 resourceList = resourceList->next;
7817 if (resourceList == NULL) {
7818 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7819 #if 0
7820 LeaveCriticalSection(&resourceStoreCriticalSection);
7821 #endif
7822 return;
7823 } else {
7824 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7826 /* make sure we don't leave a hole in the list */
7827 if (previousResourceList != NULL) {
7828 previousResourceList->next = resourceList->next;
7829 } else {
7830 This->resources = resourceList->next;
7833 #if 0
7834 LeaveCriticalSection(&resourceStoreCriticalSection);
7835 #endif
7836 return;
7840 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7842 int counter;
7844 TRACE("(%p) : resource %p\n", This, resource);
7845 switch(IWineD3DResource_GetType(resource)){
7846 case WINED3DRTYPE_SURFACE:
7847 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7848 break;
7849 case WINED3DRTYPE_TEXTURE:
7850 case WINED3DRTYPE_CUBETEXTURE:
7851 case WINED3DRTYPE_VOLUMETEXTURE:
7852 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7853 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7854 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7855 This->stateBlock->textures[counter] = NULL;
7857 if (This->updateStateBlock != This->stateBlock ){
7858 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7859 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7860 This->updateStateBlock->textures[counter] = NULL;
7864 break;
7865 case WINED3DRTYPE_VOLUME:
7866 /* TODO: nothing really? */
7867 break;
7868 case WINED3DRTYPE_VERTEXBUFFER:
7869 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7871 int streamNumber;
7872 TRACE("Cleaning up stream pointers\n");
7874 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7875 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7876 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7878 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7879 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7880 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7881 This->updateStateBlock->streamSource[streamNumber] = 0;
7882 /* Set changed flag? */
7885 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) */
7886 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7887 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7888 This->stateBlock->streamSource[streamNumber] = 0;
7891 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7892 else { /* This shouldn't happen */
7893 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7895 #endif
7899 break;
7900 case WINED3DRTYPE_INDEXBUFFER:
7901 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7902 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7903 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7904 This->updateStateBlock->pIndexData = NULL;
7907 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7908 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7909 This->stateBlock->pIndexData = NULL;
7913 break;
7914 default:
7915 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7916 break;
7920 /* Remove the resoruce from the resourceStore */
7921 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7923 TRACE("Resource released\n");
7927 /**********************************************************
7928 * IWineD3DDevice VTbl follows
7929 **********************************************************/
7931 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7933 /*** IUnknown methods ***/
7934 IWineD3DDeviceImpl_QueryInterface,
7935 IWineD3DDeviceImpl_AddRef,
7936 IWineD3DDeviceImpl_Release,
7937 /*** IWineD3DDevice methods ***/
7938 IWineD3DDeviceImpl_GetParent,
7939 /*** Creation methods**/
7940 IWineD3DDeviceImpl_CreateVertexBuffer,
7941 IWineD3DDeviceImpl_CreateIndexBuffer,
7942 IWineD3DDeviceImpl_CreateStateBlock,
7943 IWineD3DDeviceImpl_CreateSurface,
7944 IWineD3DDeviceImpl_CreateTexture,
7945 IWineD3DDeviceImpl_CreateVolumeTexture,
7946 IWineD3DDeviceImpl_CreateVolume,
7947 IWineD3DDeviceImpl_CreateCubeTexture,
7948 IWineD3DDeviceImpl_CreateQuery,
7949 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7950 IWineD3DDeviceImpl_CreateVertexDeclaration,
7951 IWineD3DDeviceImpl_CreateVertexShader,
7952 IWineD3DDeviceImpl_CreatePixelShader,
7953 IWineD3DDeviceImpl_CreatePalette,
7954 /*** Odd functions **/
7955 IWineD3DDeviceImpl_Init3D,
7956 IWineD3DDeviceImpl_Uninit3D,
7957 IWineD3DDeviceImpl_SetFullscreen,
7958 IWineD3DDeviceImpl_EnumDisplayModes,
7959 IWineD3DDeviceImpl_EvictManagedResources,
7960 IWineD3DDeviceImpl_GetAvailableTextureMem,
7961 IWineD3DDeviceImpl_GetBackBuffer,
7962 IWineD3DDeviceImpl_GetCreationParameters,
7963 IWineD3DDeviceImpl_GetDeviceCaps,
7964 IWineD3DDeviceImpl_GetDirect3D,
7965 IWineD3DDeviceImpl_GetDisplayMode,
7966 IWineD3DDeviceImpl_SetDisplayMode,
7967 IWineD3DDeviceImpl_GetHWND,
7968 IWineD3DDeviceImpl_SetHWND,
7969 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7970 IWineD3DDeviceImpl_GetRasterStatus,
7971 IWineD3DDeviceImpl_GetSwapChain,
7972 IWineD3DDeviceImpl_Reset,
7973 IWineD3DDeviceImpl_SetDialogBoxMode,
7974 IWineD3DDeviceImpl_SetCursorProperties,
7975 IWineD3DDeviceImpl_SetCursorPosition,
7976 IWineD3DDeviceImpl_ShowCursor,
7977 IWineD3DDeviceImpl_TestCooperativeLevel,
7978 /*** Getters and setters **/
7979 IWineD3DDeviceImpl_SetClipPlane,
7980 IWineD3DDeviceImpl_GetClipPlane,
7981 IWineD3DDeviceImpl_SetClipStatus,
7982 IWineD3DDeviceImpl_GetClipStatus,
7983 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7984 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7985 IWineD3DDeviceImpl_SetDepthStencilSurface,
7986 IWineD3DDeviceImpl_GetDepthStencilSurface,
7987 IWineD3DDeviceImpl_SetFVF,
7988 IWineD3DDeviceImpl_GetFVF,
7989 IWineD3DDeviceImpl_SetGammaRamp,
7990 IWineD3DDeviceImpl_GetGammaRamp,
7991 IWineD3DDeviceImpl_SetIndices,
7992 IWineD3DDeviceImpl_GetIndices,
7993 IWineD3DDeviceImpl_SetLight,
7994 IWineD3DDeviceImpl_GetLight,
7995 IWineD3DDeviceImpl_SetLightEnable,
7996 IWineD3DDeviceImpl_GetLightEnable,
7997 IWineD3DDeviceImpl_SetMaterial,
7998 IWineD3DDeviceImpl_GetMaterial,
7999 IWineD3DDeviceImpl_SetNPatchMode,
8000 IWineD3DDeviceImpl_GetNPatchMode,
8001 IWineD3DDeviceImpl_SetPaletteEntries,
8002 IWineD3DDeviceImpl_GetPaletteEntries,
8003 IWineD3DDeviceImpl_SetPixelShader,
8004 IWineD3DDeviceImpl_GetPixelShader,
8005 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8006 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8007 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8008 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8009 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8010 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8011 IWineD3DDeviceImpl_SetRenderState,
8012 IWineD3DDeviceImpl_GetRenderState,
8013 IWineD3DDeviceImpl_SetRenderTarget,
8014 IWineD3DDeviceImpl_GetRenderTarget,
8015 IWineD3DDeviceImpl_SetFrontBackBuffers,
8016 IWineD3DDeviceImpl_SetSamplerState,
8017 IWineD3DDeviceImpl_GetSamplerState,
8018 IWineD3DDeviceImpl_SetScissorRect,
8019 IWineD3DDeviceImpl_GetScissorRect,
8020 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8021 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8022 IWineD3DDeviceImpl_SetStreamSource,
8023 IWineD3DDeviceImpl_GetStreamSource,
8024 IWineD3DDeviceImpl_SetStreamSourceFreq,
8025 IWineD3DDeviceImpl_GetStreamSourceFreq,
8026 IWineD3DDeviceImpl_SetTexture,
8027 IWineD3DDeviceImpl_GetTexture,
8028 IWineD3DDeviceImpl_SetTextureStageState,
8029 IWineD3DDeviceImpl_GetTextureStageState,
8030 IWineD3DDeviceImpl_SetTransform,
8031 IWineD3DDeviceImpl_GetTransform,
8032 IWineD3DDeviceImpl_SetVertexDeclaration,
8033 IWineD3DDeviceImpl_GetVertexDeclaration,
8034 IWineD3DDeviceImpl_SetVertexShader,
8035 IWineD3DDeviceImpl_GetVertexShader,
8036 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8037 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8038 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8039 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8040 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8041 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8042 IWineD3DDeviceImpl_SetViewport,
8043 IWineD3DDeviceImpl_GetViewport,
8044 IWineD3DDeviceImpl_MultiplyTransform,
8045 IWineD3DDeviceImpl_ValidateDevice,
8046 IWineD3DDeviceImpl_ProcessVertices,
8047 /*** State block ***/
8048 IWineD3DDeviceImpl_BeginStateBlock,
8049 IWineD3DDeviceImpl_EndStateBlock,
8050 /*** Scene management ***/
8051 IWineD3DDeviceImpl_BeginScene,
8052 IWineD3DDeviceImpl_EndScene,
8053 IWineD3DDeviceImpl_Present,
8054 IWineD3DDeviceImpl_Clear,
8055 /*** Drawing ***/
8056 IWineD3DDeviceImpl_DrawPrimitive,
8057 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8058 IWineD3DDeviceImpl_DrawPrimitiveUP,
8059 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8060 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8061 IWineD3DDeviceImpl_DrawRectPatch,
8062 IWineD3DDeviceImpl_DrawTriPatch,
8063 IWineD3DDeviceImpl_DeletePatch,
8064 IWineD3DDeviceImpl_ColorFill,
8065 IWineD3DDeviceImpl_UpdateTexture,
8066 IWineD3DDeviceImpl_UpdateSurface,
8067 IWineD3DDeviceImpl_StretchRect,
8068 IWineD3DDeviceImpl_GetRenderTargetData,
8069 IWineD3DDeviceImpl_GetFrontBufferData,
8070 /*** Internal use IWineD3DDevice methods ***/
8071 IWineD3DDeviceImpl_SetupTextureStates,
8072 /*** object tracking ***/
8073 IWineD3DDeviceImpl_ResourceReleased
8077 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8078 WINED3DRS_ALPHABLENDENABLE ,
8079 WINED3DRS_ALPHAFUNC ,
8080 WINED3DRS_ALPHAREF ,
8081 WINED3DRS_ALPHATESTENABLE ,
8082 WINED3DRS_BLENDOP ,
8083 WINED3DRS_COLORWRITEENABLE ,
8084 WINED3DRS_DESTBLEND ,
8085 WINED3DRS_DITHERENABLE ,
8086 WINED3DRS_FILLMODE ,
8087 WINED3DRS_FOGDENSITY ,
8088 WINED3DRS_FOGEND ,
8089 WINED3DRS_FOGSTART ,
8090 WINED3DRS_LASTPIXEL ,
8091 WINED3DRS_SHADEMODE ,
8092 WINED3DRS_SRCBLEND ,
8093 WINED3DRS_STENCILENABLE ,
8094 WINED3DRS_STENCILFAIL ,
8095 WINED3DRS_STENCILFUNC ,
8096 WINED3DRS_STENCILMASK ,
8097 WINED3DRS_STENCILPASS ,
8098 WINED3DRS_STENCILREF ,
8099 WINED3DRS_STENCILWRITEMASK ,
8100 WINED3DRS_STENCILZFAIL ,
8101 WINED3DRS_TEXTUREFACTOR ,
8102 WINED3DRS_WRAP0 ,
8103 WINED3DRS_WRAP1 ,
8104 WINED3DRS_WRAP2 ,
8105 WINED3DRS_WRAP3 ,
8106 WINED3DRS_WRAP4 ,
8107 WINED3DRS_WRAP5 ,
8108 WINED3DRS_WRAP6 ,
8109 WINED3DRS_WRAP7 ,
8110 WINED3DRS_ZENABLE ,
8111 WINED3DRS_ZFUNC ,
8112 WINED3DRS_ZWRITEENABLE
8115 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8116 WINED3DTSS_ADDRESSW ,
8117 WINED3DTSS_ALPHAARG0 ,
8118 WINED3DTSS_ALPHAARG1 ,
8119 WINED3DTSS_ALPHAARG2 ,
8120 WINED3DTSS_ALPHAOP ,
8121 WINED3DTSS_BUMPENVLOFFSET ,
8122 WINED3DTSS_BUMPENVLSCALE ,
8123 WINED3DTSS_BUMPENVMAT00 ,
8124 WINED3DTSS_BUMPENVMAT01 ,
8125 WINED3DTSS_BUMPENVMAT10 ,
8126 WINED3DTSS_BUMPENVMAT11 ,
8127 WINED3DTSS_COLORARG0 ,
8128 WINED3DTSS_COLORARG1 ,
8129 WINED3DTSS_COLORARG2 ,
8130 WINED3DTSS_COLOROP ,
8131 WINED3DTSS_RESULTARG ,
8132 WINED3DTSS_TEXCOORDINDEX ,
8133 WINED3DTSS_TEXTURETRANSFORMFLAGS
8136 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8137 WINED3DSAMP_ADDRESSU ,
8138 WINED3DSAMP_ADDRESSV ,
8139 WINED3DSAMP_ADDRESSW ,
8140 WINED3DSAMP_BORDERCOLOR ,
8141 WINED3DSAMP_MAGFILTER ,
8142 WINED3DSAMP_MINFILTER ,
8143 WINED3DSAMP_MIPFILTER ,
8144 WINED3DSAMP_MIPMAPLODBIAS ,
8145 WINED3DSAMP_MAXMIPLEVEL ,
8146 WINED3DSAMP_MAXANISOTROPY ,
8147 WINED3DSAMP_SRGBTEXTURE ,
8148 WINED3DSAMP_ELEMENTINDEX
8151 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8152 WINED3DRS_AMBIENT ,
8153 WINED3DRS_AMBIENTMATERIALSOURCE ,
8154 WINED3DRS_CLIPPING ,
8155 WINED3DRS_CLIPPLANEENABLE ,
8156 WINED3DRS_COLORVERTEX ,
8157 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8158 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8159 WINED3DRS_FOGDENSITY ,
8160 WINED3DRS_FOGEND ,
8161 WINED3DRS_FOGSTART ,
8162 WINED3DRS_FOGTABLEMODE ,
8163 WINED3DRS_FOGVERTEXMODE ,
8164 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8165 WINED3DRS_LIGHTING ,
8166 WINED3DRS_LOCALVIEWER ,
8167 WINED3DRS_MULTISAMPLEANTIALIAS ,
8168 WINED3DRS_MULTISAMPLEMASK ,
8169 WINED3DRS_NORMALIZENORMALS ,
8170 WINED3DRS_PATCHEDGESTYLE ,
8171 WINED3DRS_POINTSCALE_A ,
8172 WINED3DRS_POINTSCALE_B ,
8173 WINED3DRS_POINTSCALE_C ,
8174 WINED3DRS_POINTSCALEENABLE ,
8175 WINED3DRS_POINTSIZE ,
8176 WINED3DRS_POINTSIZE_MAX ,
8177 WINED3DRS_POINTSIZE_MIN ,
8178 WINED3DRS_POINTSPRITEENABLE ,
8179 WINED3DRS_RANGEFOGENABLE ,
8180 WINED3DRS_SPECULARMATERIALSOURCE ,
8181 WINED3DRS_TWEENFACTOR ,
8182 WINED3DRS_VERTEXBLEND
8185 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8186 WINED3DTSS_TEXCOORDINDEX ,
8187 WINED3DTSS_TEXTURETRANSFORMFLAGS
8190 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8191 WINED3DSAMP_DMAPOFFSET