wined3d: Delete the device's FBO when destroying the device.
[wine/hacks.git] / dlls / wined3d / device.c
blobf06b9cb0086e1e75409570797568811c8e93a294
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 if (This->fbo) {
570 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
573 /* TODO: Clean up all the surfaces and textures! */
574 /* NOTE: You must release the parent if the object was created via a callback
575 ** ***************************/
577 /* Delete any GLSL shader programs that may exist */
578 if (This->vs_selected_mode == SHADER_GLSL ||
579 This->ps_selected_mode == SHADER_GLSL)
580 delete_glsl_shader_list(iface);
582 /* Release the update stateblock */
583 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
584 if(This->updateStateBlock != This->stateBlock)
585 FIXME("(%p) Something's still holding the Update stateblock\n",This);
587 This->updateStateBlock = NULL;
588 { /* because were not doing proper internal refcounts releasing the primary state block
589 causes recursion with the extra checks in ResourceReleased, to avoid this we have
590 to set this->stateBlock = NULL; first */
591 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
592 This->stateBlock = NULL;
594 /* Release the stateblock */
595 if(IWineD3DStateBlock_Release(stateBlock) > 0){
596 FIXME("(%p) Something's still holding the Update stateblock\n",This);
600 if (This->resources != NULL ) {
601 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
602 dumpResources(This->resources);
606 IWineD3D_Release(This->wineD3D);
607 This->wineD3D = NULL;
608 HeapFree(GetProcessHeap(), 0, This);
609 TRACE("Freed device %p\n", This);
610 This = NULL;
612 return refCount;
615 /**********************************************************
616 * IWineD3DDevice implementation follows
617 **********************************************************/
618 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
620 *pParent = This->parent;
621 IUnknown_AddRef(This->parent);
622 return WINED3D_OK;
625 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
626 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
627 GLenum error, glUsage;
628 DWORD vboUsage = object->resource.usage;
629 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
630 WARN("Creating a vbo failed once, not trying again\n");
631 return;
634 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
636 ENTER_GL();
637 /* Make sure that the gl error is cleared. Do not use checkGLcall
638 * here because checkGLcall just prints a fixme and continues. However,
639 * if an error during VBO creation occurs we can fall back to non-vbo operation
640 * with full functionality(but performance loss)
642 while(glGetError() != GL_NO_ERROR);
644 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
645 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
646 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
647 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
648 * to check if the rhw and color values are in the correct format.
651 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
652 error = glGetError();
653 if(object->vbo == 0 || error != GL_NO_ERROR) {
654 WARN("Failed to create a VBO with error %d\n", error);
655 goto error;
658 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
659 error = glGetError();
660 if(error != GL_NO_ERROR) {
661 WARN("Failed to bind the VBO, error %d\n", error);
662 goto error;
665 /* Transformed vertices are horribly inflexible. If the app specifies an
666 * vertex buffer with transformed vertices in default pool without DYNAMIC
667 * usage assume DYNAMIC usage and print a warning. The app will have to update
668 * the vertices regularily for them to be useful
670 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
671 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
672 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
673 vboUsage |= WINED3DUSAGE_DYNAMIC;
676 /* Don't use static, because dx apps tend to update the buffer
677 * quite often even if they specify 0 usage
679 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
680 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
681 TRACE("Gl usage = GL_STREAM_DRAW\n");
682 glUsage = GL_STREAM_DRAW_ARB;
683 break;
684 case D3DUSAGE_WRITEONLY:
685 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
686 glUsage = GL_DYNAMIC_DRAW_ARB;
687 break;
688 case D3DUSAGE_DYNAMIC:
689 TRACE("Gl usage = GL_STREAM_COPY\n");
690 glUsage = GL_STREAM_COPY_ARB;
691 break;
692 default:
693 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
694 glUsage = GL_DYNAMIC_COPY_ARB;
695 break;
698 /* Reserve memory for the buffer. The amount of data won't change
699 * so we are safe with calling glBufferData once with a NULL ptr and
700 * calling glBufferSubData on updates
702 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
703 error = glGetError();
704 if(error != GL_NO_ERROR) {
705 WARN("glBufferDataARB failed with error %d\n", error);
706 goto error;
709 LEAVE_GL();
711 return;
712 error:
713 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
714 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
715 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
716 object->vbo = 0;
717 object->Flags |= VBFLAG_VBOCREATEFAIL;
718 LEAVE_GL();
719 return;
722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
723 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
724 IUnknown *parent) {
725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
726 IWineD3DVertexBufferImpl *object;
727 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
728 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
729 BOOL conv;
730 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
732 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
733 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
735 if(Size == 0) return WINED3DERR_INVALIDCALL;
737 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
738 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
740 object->fvf = FVF;
742 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
743 * drawStridedFast (half-life 2).
745 * Basically converting the vertices in the buffer is quite expensive, and observations
746 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
747 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
749 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
750 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
751 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
752 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
753 * dx7 apps.
754 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
755 * more. In this call we can convert dx7 buffers too.
757 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
758 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
759 (dxVersion > 7 || !conv) ) {
760 CreateVBO(object);
762 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
763 if(dxVersion == 7 && object->vbo) {
764 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
765 object->resource.allocatedMemory = NULL;
769 return WINED3D_OK;
772 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
773 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
774 HANDLE *sharedHandle, IUnknown *parent) {
775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
776 IWineD3DIndexBufferImpl *object;
777 TRACE("(%p) Creating index buffer\n", This);
779 /* Allocate the storage for the device */
780 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
782 /*TODO: use VBO's */
783 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
784 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
787 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
788 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
789 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
791 return WINED3D_OK;
794 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
797 IWineD3DStateBlockImpl *object;
798 int i, j;
799 HRESULT temp_result;
801 D3DCREATEOBJECTINSTANCE(object, StateBlock)
802 object->blockType = Type;
804 /* Special case - Used during initialization to produce a placeholder stateblock
805 so other functions called can update a state block */
806 if (Type == WINED3DSBT_INIT) {
807 /* Don't bother increasing the reference count otherwise a device will never
808 be freed due to circular dependencies */
809 return WINED3D_OK;
812 temp_result = allocate_shader_constants(object);
813 if (WINED3D_OK != temp_result)
814 return temp_result;
816 /* Otherwise, might as well set the whole state block to the appropriate values */
817 if (This->stateBlock != NULL)
818 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
819 else
820 memset(object->streamFreq, 1, sizeof(object->streamFreq));
822 /* Reset the ref and type after kludging it */
823 object->wineD3DDevice = This;
824 object->ref = 1;
825 object->blockType = Type;
827 TRACE("Updating changed flags appropriate for type %d\n", Type);
829 if (Type == WINED3DSBT_ALL) {
831 TRACE("ALL => Pretend everything has changed\n");
832 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
834 } else if (Type == WINED3DSBT_PIXELSTATE) {
836 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
837 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
839 object->changed.pixelShader = TRUE;
841 /* Pixel Shader Constants */
842 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
843 object->changed.pixelShaderConstantsF[i] = TRUE;
844 for (i = 0; i < MAX_CONST_B; ++i)
845 object->changed.pixelShaderConstantsB[i] = TRUE;
846 for (i = 0; i < MAX_CONST_I; ++i)
847 object->changed.pixelShaderConstantsI[i] = TRUE;
849 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
850 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
852 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
853 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
854 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
857 for (j = 0 ; j < 16; j++) {
858 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
860 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
864 } else if (Type == WINED3DSBT_VERTEXSTATE) {
866 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
867 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
869 object->changed.vertexShader = TRUE;
871 /* Vertex Shader Constants */
872 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
873 object->changed.vertexShaderConstantsF[i] = TRUE;
874 for (i = 0; i < MAX_CONST_B; ++i)
875 object->changed.vertexShaderConstantsB[i] = TRUE;
876 for (i = 0; i < MAX_CONST_I; ++i)
877 object->changed.vertexShaderConstantsI[i] = TRUE;
879 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
880 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
882 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
883 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
884 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
887 for (j = 0 ; j < 16; j++){
888 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
889 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
893 /* Duplicate light chain */
895 PLIGHTINFOEL *src = NULL;
896 PLIGHTINFOEL *dst = NULL;
897 PLIGHTINFOEL *newEl = NULL;
898 src = This->stateBlock->lights;
899 object->lights = NULL;
902 while (src) {
903 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
904 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
905 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
906 newEl->prev = dst;
907 newEl->changed = TRUE;
908 newEl->enabledChanged = TRUE;
909 if (dst == NULL) {
910 object->lights = newEl;
911 } else {
912 dst->next = newEl;
914 dst = newEl;
915 src = src->next;
920 } else {
921 FIXME("Unrecognized state block type %d\n", Type);
924 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
925 return WINED3D_OK;
929 /* ************************************
930 MSDN:
931 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
933 Discard
934 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
936 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.
938 ******************************** */
940 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) {
941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
942 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
943 unsigned int pow2Width, pow2Height;
944 unsigned int Size = 1;
945 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
946 TRACE("(%p) Create surface\n",This);
948 /** FIXME: Check ranges on the inputs are valid
949 * MSDN
950 * MultisampleQuality
951 * [in] Quality level. The valid range is between zero and one less than the level
952 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
953 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
954 * values of paired render targets, depth stencil surfaces, and the MultiSample type
955 * must all match.
956 *******************************/
960 * TODO: Discard MSDN
961 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
963 * If this flag is set, the contents of the depth stencil buffer will be
964 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
965 * with a different depth surface.
967 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
968 ***************************/
970 if(MultisampleQuality < 0) {
971 FIXME("Invalid multisample level %d\n", MultisampleQuality);
972 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
975 if(MultisampleQuality > 0) {
976 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
977 MultisampleQuality=0;
980 /** FIXME: Check that the format is supported
981 * by the device.
982 *******************************/
984 /* Non-power2 support */
985 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
986 pow2Width = Width;
987 pow2Height = Height;
988 } else {
989 /* Find the nearest pow2 match */
990 pow2Width = pow2Height = 1;
991 while (pow2Width < Width) pow2Width <<= 1;
992 while (pow2Height < Height) pow2Height <<= 1;
995 if (pow2Width > Width || pow2Height > Height) {
996 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
997 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
998 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
999 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1000 This, Width, Height);
1001 return WINED3DERR_NOTAVAILABLE;
1005 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1006 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1007 * space!
1008 *********************************/
1009 if (WINED3DFMT_UNKNOWN == Format) {
1010 Size = 0;
1011 } else if (Format == WINED3DFMT_DXT1) {
1012 /* DXT1 is half byte per pixel */
1013 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1015 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1016 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1017 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1018 } else {
1019 /* The pitch is a multiple of 4 bytes */
1020 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1021 Size *= pow2Height;
1024 /** Create and initialise the surface resource **/
1025 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1026 /* "Standalone" surface */
1027 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1029 object->currentDesc.Width = Width;
1030 object->currentDesc.Height = Height;
1031 object->currentDesc.MultiSampleType = MultiSample;
1032 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1034 /* Setup some glformat defaults */
1035 object->glDescription.glFormat = tableEntry->glFormat;
1036 object->glDescription.glFormatInternal = tableEntry->glInternal;
1037 object->glDescription.glType = tableEntry->glType;
1039 object->glDescription.textureName = 0;
1040 object->glDescription.level = Level;
1041 object->glDescription.target = GL_TEXTURE_2D;
1043 /* Internal data */
1044 object->pow2Width = pow2Width;
1045 object->pow2Height = pow2Height;
1047 /* Flags */
1048 object->Flags = 0; /* We start without flags set */
1049 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1050 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1051 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1052 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1055 if (WINED3DFMT_UNKNOWN != Format) {
1056 object->bytesPerPixel = tableEntry->bpp;
1057 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1058 object->pow2Size *= pow2Height;
1059 } else {
1060 object->bytesPerPixel = 0;
1061 object->pow2Size = 0;
1064 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1066 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1068 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1069 * this function is too deep to need to care about things like this.
1070 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1071 * ****************************************/
1072 switch(Pool) {
1073 case WINED3DPOOL_SCRATCH:
1074 if(!Lockable)
1075 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1076 which are mutually exclusive, setting lockable to true\n");
1077 Lockable = TRUE;
1078 break;
1079 case WINED3DPOOL_SYSTEMMEM:
1080 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1081 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1082 case WINED3DPOOL_MANAGED:
1083 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1084 Usage of DYNAMIC which are mutually exclusive, not doing \
1085 anything just telling you.\n");
1086 break;
1087 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1088 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1089 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1090 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1091 break;
1092 default:
1093 FIXME("(%p) Unknown pool %d\n", This, Pool);
1094 break;
1097 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1098 FIXME("Trying to create a render target that isn't in the default pool\n");
1101 /* mark the texture as dirty so that it gets loaded first time around*/
1102 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1103 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1104 This, Width, Height, Format, debug_d3dformat(Format),
1105 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1107 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1108 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1109 This->ddraw_primary = (IWineD3DSurface *) object;
1111 /* Look at the implementation and set the correct Vtable */
1112 switch(Impl) {
1113 case SURFACE_OPENGL:
1114 /* Nothing to do, it's set already */
1115 break;
1117 case SURFACE_GDI:
1118 object->lpVtbl = &IWineGDISurface_Vtbl;
1119 break;
1121 default:
1122 /* To be sure to catch this */
1123 ERR("Unknown requested surface implementation %d!\n", Impl);
1124 IWineD3DSurface_Release((IWineD3DSurface *) object);
1125 return WINED3DERR_INVALIDCALL;
1128 /* Call the private setup routine */
1129 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1133 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1134 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1135 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1136 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1139 IWineD3DTextureImpl *object;
1140 unsigned int i;
1141 UINT tmpW;
1142 UINT tmpH;
1143 HRESULT hr;
1144 unsigned int pow2Width;
1145 unsigned int pow2Height;
1148 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1149 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1150 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1152 /* TODO: It should only be possible to create textures for formats
1153 that are reported as supported */
1154 if (WINED3DFMT_UNKNOWN >= Format) {
1155 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1156 return WINED3DERR_INVALIDCALL;
1159 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1160 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1161 object->width = Width;
1162 object->height = Height;
1164 /** Non-power2 support **/
1165 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1166 pow2Width = Width;
1167 pow2Height = Height;
1168 } else {
1169 /* Find the nearest pow2 match */
1170 pow2Width = pow2Height = 1;
1171 while (pow2Width < Width) pow2Width <<= 1;
1172 while (pow2Height < Height) pow2Height <<= 1;
1175 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1176 /* Precalculated scaling for 'faked' non power of two texture coords */
1177 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1178 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1179 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1181 /* Calculate levels for mip mapping */
1182 if (Levels == 0) {
1183 TRACE("calculating levels %d\n", object->baseTexture.levels);
1184 object->baseTexture.levels++;
1185 tmpW = Width;
1186 tmpH = Height;
1187 while (tmpW > 1 || tmpH > 1) {
1188 tmpW = max(1, tmpW >> 1);
1189 tmpH = max(1, tmpH >> 1);
1190 object->baseTexture.levels++;
1192 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1195 /* Generate all the surfaces */
1196 tmpW = Width;
1197 tmpH = Height;
1198 for (i = 0; i < object->baseTexture.levels; i++)
1200 /* use the callback to create the texture surface */
1201 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1202 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1203 FIXME("Failed to create surface %p\n", object);
1204 /* clean up */
1205 object->surfaces[i] = NULL;
1206 IWineD3DTexture_Release((IWineD3DTexture *)object);
1208 *ppTexture = NULL;
1209 return hr;
1212 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1213 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1214 /* calculate the next mipmap level */
1215 tmpW = max(1, tmpW >> 1);
1216 tmpH = max(1, tmpH >> 1);
1219 TRACE("(%p) : Created texture %p\n", This, object);
1220 return WINED3D_OK;
1223 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1224 UINT Width, UINT Height, UINT Depth,
1225 UINT Levels, DWORD Usage,
1226 WINED3DFORMAT Format, WINED3DPOOL Pool,
1227 IWineD3DVolumeTexture **ppVolumeTexture,
1228 HANDLE *pSharedHandle, IUnknown *parent,
1229 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1232 IWineD3DVolumeTextureImpl *object;
1233 unsigned int i;
1234 UINT tmpW;
1235 UINT tmpH;
1236 UINT tmpD;
1238 /* TODO: It should only be possible to create textures for formats
1239 that are reported as supported */
1240 if (WINED3DFMT_UNKNOWN >= Format) {
1241 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1242 return WINED3DERR_INVALIDCALL;
1245 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1246 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1248 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1249 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1251 object->width = Width;
1252 object->height = Height;
1253 object->depth = Depth;
1255 /* Calculate levels for mip mapping */
1256 if (Levels == 0) {
1257 object->baseTexture.levels++;
1258 tmpW = Width;
1259 tmpH = Height;
1260 tmpD = Depth;
1261 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1262 tmpW = max(1, tmpW >> 1);
1263 tmpH = max(1, tmpH >> 1);
1264 tmpD = max(1, tmpD >> 1);
1265 object->baseTexture.levels++;
1267 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1270 /* Generate all the surfaces */
1271 tmpW = Width;
1272 tmpH = Height;
1273 tmpD = Depth;
1275 for (i = 0; i < object->baseTexture.levels; i++)
1277 /* Create the volume */
1278 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1279 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1281 /* Set its container to this object */
1282 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1284 /* calcualte the next mipmap level */
1285 tmpW = max(1, tmpW >> 1);
1286 tmpH = max(1, tmpH >> 1);
1287 tmpD = max(1, tmpD >> 1);
1290 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1291 TRACE("(%p) : Created volume texture %p\n", This, object);
1292 return WINED3D_OK;
1295 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1296 UINT Width, UINT Height, UINT Depth,
1297 DWORD Usage,
1298 WINED3DFORMAT Format, WINED3DPOOL Pool,
1299 IWineD3DVolume** ppVolume,
1300 HANDLE* pSharedHandle, IUnknown *parent) {
1302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1304 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1306 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1308 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1309 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1311 object->currentDesc.Width = Width;
1312 object->currentDesc.Height = Height;
1313 object->currentDesc.Depth = Depth;
1314 object->bytesPerPixel = formatDesc->bpp;
1316 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1317 object->lockable = TRUE;
1318 object->locked = FALSE;
1319 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1320 object->dirty = TRUE;
1322 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1326 UINT Levels, DWORD Usage,
1327 WINED3DFORMAT Format, WINED3DPOOL Pool,
1328 IWineD3DCubeTexture **ppCubeTexture,
1329 HANDLE *pSharedHandle, IUnknown *parent,
1330 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1333 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1334 unsigned int i, j;
1335 UINT tmpW;
1336 HRESULT hr;
1337 unsigned int pow2EdgeLength = EdgeLength;
1339 /* TODO: It should only be possible to create textures for formats
1340 that are reported as supported */
1341 if (WINED3DFMT_UNKNOWN >= Format) {
1342 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1343 return WINED3DERR_INVALIDCALL;
1346 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1347 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1349 TRACE("(%p) Create Cube Texture\n", This);
1351 /** Non-power2 support **/
1353 /* Find the nearest pow2 match */
1354 pow2EdgeLength = 1;
1355 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1357 object->edgeLength = EdgeLength;
1358 /* TODO: support for native non-power 2 */
1359 /* Precalculated scaling for 'faked' non power of two texture coords */
1360 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1362 /* Calculate levels for mip mapping */
1363 if (Levels == 0) {
1364 object->baseTexture.levels++;
1365 tmpW = EdgeLength;
1366 while (tmpW > 1) {
1367 tmpW = max(1, tmpW >> 1);
1368 object->baseTexture.levels++;
1370 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1373 /* Generate all the surfaces */
1374 tmpW = EdgeLength;
1375 for (i = 0; i < object->baseTexture.levels; i++) {
1377 /* Create the 6 faces */
1378 for (j = 0; j < 6; j++) {
1380 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1381 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1383 if(hr!= WINED3D_OK) {
1384 /* clean up */
1385 int k;
1386 int l;
1387 for (l = 0; l < j; l++) {
1388 IWineD3DSurface_Release(object->surfaces[j][i]);
1390 for (k = 0; k < i; k++) {
1391 for (l = 0; l < 6; l++) {
1392 IWineD3DSurface_Release(object->surfaces[l][j]);
1396 FIXME("(%p) Failed to create surface\n",object);
1397 HeapFree(GetProcessHeap(),0,object);
1398 *ppCubeTexture = NULL;
1399 return hr;
1401 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1402 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1404 tmpW = max(1, tmpW >> 1);
1407 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1408 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1409 return WINED3D_OK;
1412 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1414 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1416 if (NULL == ppQuery) {
1417 /* Just a check to see if we support this type of query */
1418 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1419 switch(Type) {
1420 case WINED3DQUERYTYPE_OCCLUSION:
1421 TRACE("(%p) occlusion query\n", This);
1422 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1423 hr = WINED3D_OK;
1424 else
1425 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1426 break;
1427 case WINED3DQUERYTYPE_VCACHE:
1428 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1429 case WINED3DQUERYTYPE_VERTEXSTATS:
1430 case WINED3DQUERYTYPE_EVENT:
1431 case WINED3DQUERYTYPE_TIMESTAMP:
1432 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1433 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1434 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1435 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1436 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1437 case WINED3DQUERYTYPE_PIXELTIMINGS:
1438 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1439 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1440 default:
1441 FIXME("(%p) Unhandled query type %d\n", This, Type);
1443 return hr;
1446 D3DCREATEOBJECTINSTANCE(object, Query)
1447 object->type = Type;
1448 /* allocated the 'extended' data based on the type of query requested */
1449 switch(Type){
1450 case WINED3DQUERYTYPE_OCCLUSION:
1451 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1452 TRACE("(%p) Allocating data for an occlusion query\n", This);
1453 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1454 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1455 break;
1457 case WINED3DQUERYTYPE_VCACHE:
1458 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1459 case WINED3DQUERYTYPE_VERTEXSTATS:
1460 case WINED3DQUERYTYPE_EVENT:
1461 case WINED3DQUERYTYPE_TIMESTAMP:
1462 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1463 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1464 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1465 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1466 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1467 case WINED3DQUERYTYPE_PIXELTIMINGS:
1468 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1469 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1470 default:
1471 object->extendedData = 0;
1472 FIXME("(%p) Unhandled query type %d\n",This , Type);
1474 TRACE("(%p) : Created Query %p\n", This, object);
1475 return WINED3D_OK;
1478 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1479 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1480 IUnknown* parent,
1481 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1482 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1485 HDC hDc;
1486 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1487 int num;
1488 XVisualInfo template;
1489 GLXContext oldContext;
1490 Drawable oldDrawable;
1491 HRESULT hr = WINED3D_OK;
1493 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1495 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1496 * does a device hold a reference to a swap chain giving them a lifetime of the device
1497 * or does the swap chain notify the device of its destruction.
1498 *******************************/
1500 /* Check the params */
1501 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1502 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1503 return WINED3DERR_INVALIDCALL;
1504 } else if (*pPresentationParameters->BackBufferCount > 1) {
1505 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");
1508 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1510 /*********************
1511 * Lookup the window Handle and the relating X window handle
1512 ********************/
1514 /* Setup hwnd we are using, plus which display this equates to */
1515 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1516 if (!object->win_handle) {
1517 object->win_handle = This->createParms.hFocusWindow;
1520 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1521 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1522 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1523 return WINED3DERR_NOTAVAILABLE;
1525 hDc = GetDC(object->win_handle);
1526 object->display = get_display(hDc);
1527 ReleaseDC(object->win_handle, hDc);
1528 TRACE("Using a display of %p %p\n", object->display, hDc);
1530 if (NULL == object->display || NULL == hDc) {
1531 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1532 return WINED3DERR_NOTAVAILABLE;
1535 if (object->win == 0) {
1536 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1537 return WINED3DERR_NOTAVAILABLE;
1540 * Create an opengl context for the display visual
1541 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1542 * use different properties after that point in time. FIXME: How to handle when requested format
1543 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1544 * it chooses is identical to the one already being used!
1545 **********************************/
1547 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1548 ENTER_GL();
1550 /* Create a new context for this swapchain */
1551 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1552 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1553 (or the best possible if none is requested) */
1554 TRACE("Found x visual ID : %ld\n", template.visualid);
1556 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1557 if (NULL == object->visInfo) {
1558 ERR("cannot really get XVisual\n");
1559 LEAVE_GL();
1560 return WINED3DERR_NOTAVAILABLE;
1561 } else {
1562 int n, value;
1563 /* Write out some debug info about the visual/s */
1564 TRACE("Using x visual ID : %ld\n", template.visualid);
1565 TRACE(" visual info: %p\n", object->visInfo);
1566 TRACE(" num items : %d\n", num);
1567 for (n = 0;n < num; n++) {
1568 TRACE("=====item=====: %d\n", n + 1);
1569 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1570 TRACE(" screen : %d\n", object->visInfo[n].screen);
1571 TRACE(" depth : %u\n", object->visInfo[n].depth);
1572 TRACE(" class : %d\n", object->visInfo[n].class);
1573 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1574 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1575 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1576 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1577 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1578 /* log some extra glx info */
1579 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1580 TRACE(" gl_aux_buffers : %d\n", value);
1581 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1582 TRACE(" gl_buffer_size : %d\n", value);
1583 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1584 TRACE(" gl_red_size : %d\n", value);
1585 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1586 TRACE(" gl_green_size : %d\n", value);
1587 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1588 TRACE(" gl_blue_size : %d\n", value);
1589 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1590 TRACE(" gl_alpha_size : %d\n", value);
1591 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1592 TRACE(" gl_depth_size : %d\n", value);
1593 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1594 TRACE(" gl_stencil_size : %d\n", value);
1596 /* Now choose a similar visual ID*/
1598 #ifdef USE_CONTEXT_MANAGER
1600 /** TODO: use a context mamager **/
1601 #endif
1604 IWineD3DSwapChain *implSwapChain;
1605 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1606 /* The first time around we create the context that is shared with all other swapchains and render targets */
1607 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1608 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1609 } else {
1611 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1612 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1613 /* and create a new context with the implicit swapchains context as the shared context */
1614 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1618 /* Cleanup */
1619 XFree(object->visInfo);
1620 object->visInfo = NULL;
1622 LEAVE_GL();
1624 if (!object->glCtx) {
1625 ERR("Failed to create GLX context\n");
1626 return WINED3DERR_NOTAVAILABLE;
1627 } else {
1628 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1629 object->win_handle, object->glCtx, object->win, object->visInfo);
1632 /*********************
1633 * Windowed / Fullscreen
1634 *******************/
1637 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1638 * so we should really check to see if there is a fullscreen swapchain already
1639 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1640 **************************************/
1642 if (!*(pPresentationParameters->Windowed)) {
1644 DEVMODEW devmode;
1645 HDC hdc;
1646 int bpp = 0;
1648 /* Get info on the current display setup */
1649 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1650 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1651 DeleteDC(hdc);
1653 /* Change the display settings */
1654 memset(&devmode, 0, sizeof(DEVMODEW));
1655 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1656 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1657 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1658 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1659 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1660 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1662 /* Make popup window */
1663 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1664 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1665 *(pPresentationParameters->BackBufferWidth),
1666 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1668 /* For GetDisplayMode */
1669 This->ddraw_width = devmode.dmPelsWidth;
1670 This->ddraw_height = devmode.dmPelsHeight;
1671 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1675 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1676 * then the corresponding dimension of the client area of the hDeviceWindow
1677 * (or the focus window, if hDeviceWindow is NULL) is taken.
1678 **********************/
1680 if (*(pPresentationParameters->Windowed) &&
1681 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1682 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1684 RECT Rect;
1685 GetClientRect(object->win_handle, &Rect);
1687 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1688 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1689 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1691 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1692 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1693 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1697 /*********************
1698 * finish off parameter initialization
1699 *******************/
1701 /* Put the correct figures in the presentation parameters */
1702 TRACE("Copying across presentation parameters\n");
1703 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1704 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1705 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1706 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1707 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1708 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1709 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1710 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1711 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1712 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1713 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1714 object->presentParms.Flags = *(pPresentationParameters->Flags);
1715 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1716 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1719 /*********************
1720 * Create the back, front and stencil buffers
1721 *******************/
1723 TRACE("calling rendertarget CB\n");
1724 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1725 object->presentParms.BackBufferWidth,
1726 object->presentParms.BackBufferHeight,
1727 object->presentParms.BackBufferFormat,
1728 object->presentParms.MultiSampleType,
1729 object->presentParms.MultiSampleQuality,
1730 TRUE /* Lockable */,
1731 &object->frontBuffer,
1732 NULL /* pShared (always null)*/);
1733 if (object->frontBuffer != NULL)
1734 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1736 if(object->presentParms.BackBufferCount > 0) {
1737 int i;
1739 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1740 if(!object->backBuffer) {
1741 ERR("Out of memory\n");
1743 if (object->frontBuffer) {
1744 IUnknown *bufferParent;
1745 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1746 IUnknown_Release(bufferParent); /* once for the get parent */
1747 if (IUnknown_Release(bufferParent) > 0) {
1748 FIXME("(%p) Something's still holding the front buffer\n",This);
1751 HeapFree(GetProcessHeap(), 0, object);
1752 return E_OUTOFMEMORY;
1755 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1756 TRACE("calling rendertarget CB\n");
1757 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1758 object->presentParms.BackBufferWidth,
1759 object->presentParms.BackBufferHeight,
1760 object->presentParms.BackBufferFormat,
1761 object->presentParms.MultiSampleType,
1762 object->presentParms.MultiSampleQuality,
1763 TRUE /* Lockable */,
1764 &object->backBuffer[i],
1765 NULL /* pShared (always null)*/);
1766 if(hr == WINED3D_OK && object->backBuffer[i]) {
1767 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1768 } else {
1769 break;
1772 } else {
1773 object->backBuffer = NULL;
1776 if (object->backBuffer != NULL) {
1777 ENTER_GL();
1778 glDrawBuffer(GL_BACK);
1779 checkGLcall("glDrawBuffer(GL_BACK)");
1780 LEAVE_GL();
1781 } else {
1782 /* Single buffering - draw to front buffer */
1783 ENTER_GL();
1784 glDrawBuffer(GL_FRONT);
1785 checkGLcall("glDrawBuffer(GL_FRONT)");
1786 LEAVE_GL();
1789 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1790 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1791 TRACE("Creating depth stencil buffer\n");
1792 if (This->depthStencilBuffer == NULL ) {
1793 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1794 object->presentParms.BackBufferWidth,
1795 object->presentParms.BackBufferHeight,
1796 object->presentParms.AutoDepthStencilFormat,
1797 object->presentParms.MultiSampleType,
1798 object->presentParms.MultiSampleQuality,
1799 FALSE /* FIXME: Discard */,
1800 &This->depthStencilBuffer,
1801 NULL /* pShared (always null)*/ );
1802 if (This->depthStencilBuffer != NULL)
1803 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1806 /** TODO: A check on width, height and multisample types
1807 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1808 ****************************/
1809 object->wantsDepthStencilBuffer = TRUE;
1810 } else {
1811 object->wantsDepthStencilBuffer = FALSE;
1814 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1817 /*********************
1818 * init the default renderTarget management
1819 *******************/
1820 object->drawable = object->win;
1821 object->render_ctx = object->glCtx;
1823 if (hr == WINED3D_OK) {
1824 /*********************
1825 * Setup some defaults and clear down the buffers
1826 *******************/
1827 ENTER_GL();
1828 /** save current context and drawable **/
1829 oldContext = glXGetCurrentContext();
1830 oldDrawable = glXGetCurrentDrawable();
1832 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1833 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1834 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1836 checkGLcall("glXMakeCurrent");
1838 TRACE("Setting up the screen\n");
1839 /* Clear the screen */
1840 glClearColor(1.0, 0.0, 0.0, 0.0);
1841 checkGLcall("glClearColor");
1842 glClearIndex(0);
1843 glClearDepth(1);
1844 glClearStencil(0xffff);
1846 checkGLcall("glClear");
1848 glColor3f(1.0, 1.0, 1.0);
1849 checkGLcall("glColor3f");
1851 glEnable(GL_LIGHTING);
1852 checkGLcall("glEnable");
1854 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1855 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1857 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1858 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1860 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1861 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1863 /* switch back to the original context (if there was one)*/
1864 if (This->swapchains) {
1865 /** TODO: restore the context and drawable **/
1866 glXMakeCurrent(object->display, oldDrawable, oldContext);
1869 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1870 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1871 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1872 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1873 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1875 LEAVE_GL();
1877 TRACE("Set swapchain to %p\n", object);
1878 } else { /* something went wrong so clean up */
1879 IUnknown* bufferParent;
1880 if (object->frontBuffer) {
1882 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1883 IUnknown_Release(bufferParent); /* once for the get parent */
1884 if (IUnknown_Release(bufferParent) > 0) {
1885 FIXME("(%p) Something's still holding the front buffer\n",This);
1888 if (object->backBuffer) {
1889 int i;
1890 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1891 if(object->backBuffer[i]) {
1892 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1893 IUnknown_Release(bufferParent); /* once for the get parent */
1894 if (IUnknown_Release(bufferParent) > 0) {
1895 FIXME("(%p) Something's still holding the back buffer\n",This);
1899 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1900 object->backBuffer = NULL;
1902 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1903 /* Clean up the context */
1904 /* check that we are the current context first (we shouldn't be though!) */
1905 if (object->glCtx != 0) {
1906 if(glXGetCurrentContext() == object->glCtx) {
1907 glXMakeCurrent(object->display, None, NULL);
1909 glXDestroyContext(object->display, object->glCtx);
1911 HeapFree(GetProcessHeap(), 0, object);
1915 return hr;
1918 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1919 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1921 TRACE("(%p)\n", This);
1923 return This->NumberOfSwapChains;
1926 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1928 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1930 if(iSwapChain < This->NumberOfSwapChains) {
1931 *pSwapChain = This->swapchains[iSwapChain];
1932 TRACE("(%p) returning %p\n", This, *pSwapChain);
1933 return WINED3D_OK;
1934 } else {
1935 TRACE("Swapchain out of range\n");
1936 *pSwapChain = NULL;
1937 return WINED3DERR_INVALIDCALL;
1941 /*****
1942 * Vertex Declaration
1943 *****/
1944 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1946 IWineD3DVertexDeclarationImpl *object = NULL;
1947 HRESULT hr = WINED3D_OK;
1948 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1949 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1950 object->allFVF = 0;
1952 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1954 return hr;
1957 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1958 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1960 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1961 HRESULT hr = WINED3D_OK;
1962 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1963 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1965 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1967 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1968 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1969 if (pDeclaration != NULL) {
1970 IWineD3DVertexDeclaration *vertexDeclaration;
1971 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1972 if (WINED3D_OK == hr) {
1973 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1974 object->vertexDeclaration = vertexDeclaration;
1975 } else {
1976 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1977 IWineD3DVertexShader_Release(*ppVertexShader);
1978 return WINED3DERR_INVALIDCALL;
1982 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1984 if (WINED3D_OK != hr) {
1985 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1986 IWineD3DVertexShader_Release(*ppVertexShader);
1987 return WINED3DERR_INVALIDCALL;
1990 #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. */
1991 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1992 /* Foo */
1993 } else {
1994 /* Bar */
1997 #endif
1999 return WINED3D_OK;
2002 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2004 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2005 HRESULT hr = WINED3D_OK;
2007 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2008 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2009 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2010 if (WINED3D_OK == hr) {
2011 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2012 } else {
2013 WARN("(%p) : Failed to create pixel shader\n", This);
2016 return hr;
2019 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2021 IWineD3DPaletteImpl *object;
2022 HRESULT hr;
2023 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2025 /* Create the new object */
2026 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2027 if(!object) {
2028 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2029 return E_OUTOFMEMORY;
2032 object->lpVtbl = &IWineD3DPalette_Vtbl;
2033 object->ref = 1;
2034 object->Flags = Flags;
2035 object->parent = Parent;
2036 object->wineD3DDevice = This;
2037 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2039 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2041 if(!object->hpal) {
2042 HeapFree( GetProcessHeap(), 0, object);
2043 return E_OUTOFMEMORY;
2046 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2047 if(FAILED(hr)) {
2048 IWineD3DPalette_Release((IWineD3DPalette *) object);
2049 return hr;
2052 *Palette = (IWineD3DPalette *) object;
2054 return WINED3D_OK;
2057 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2059 IWineD3DSwapChainImpl *swapchain;
2061 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2062 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2064 /* TODO: Test if OpenGL is compiled in and loaded */
2066 /* Setup the implicit swapchain */
2067 TRACE("Creating implicit swapchain\n");
2068 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2069 WARN("Failed to create implicit swapchain\n");
2070 return WINED3DERR_INVALIDCALL;
2073 This->NumberOfSwapChains = 1;
2074 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2075 if(!This->swapchains) {
2076 ERR("Out of memory!\n");
2077 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2078 return E_OUTOFMEMORY;
2080 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2082 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2083 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2084 This->renderTarget = swapchain->backBuffer[0];
2086 else {
2087 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2088 This->renderTarget = swapchain->frontBuffer;
2090 IWineD3DSurface_AddRef(This->renderTarget);
2091 /* Depth Stencil support */
2092 This->stencilBufferTarget = This->depthStencilBuffer;
2093 if (NULL != This->stencilBufferTarget) {
2094 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2097 /* Set up some starting GL setup */
2098 ENTER_GL();
2100 * Initialize openGL extension related variables
2101 * with Default values
2104 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2105 /* Setup all the devices defaults */
2106 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2107 #if 0
2108 IWineD3DImpl_CheckGraphicsMemory();
2109 #endif
2110 LEAVE_GL();
2112 /* Initialize our list of GLSL programs */
2113 list_init(&This->glsl_shader_progs);
2115 { /* Set a default viewport */
2116 WINED3DVIEWPORT vp;
2117 vp.X = 0;
2118 vp.Y = 0;
2119 vp.Width = *(pPresentationParameters->BackBufferWidth);
2120 vp.Height = *(pPresentationParameters->BackBufferHeight);
2121 vp.MinZ = 0.0f;
2122 vp.MaxZ = 1.0f;
2123 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2126 /* Initialize the current view state */
2127 This->modelview_valid = 1;
2128 This->proj_valid = 0;
2129 This->view_ident = 1;
2130 This->last_was_rhw = 0;
2131 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2132 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2134 /* Clear the screen */
2135 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2137 This->d3d_initialized = TRUE;
2138 return WINED3D_OK;
2141 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2143 int sampler;
2144 IUnknown* stencilBufferParent;
2145 IUnknown* swapChainParent;
2146 uint i;
2147 TRACE("(%p)\n", This);
2149 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2151 /* Delete the mouse cursor texture */
2152 if(This->cursorTexture) {
2153 ENTER_GL();
2154 glDeleteTextures(1, &This->cursorTexture);
2155 LEAVE_GL();
2156 This->cursorTexture = 0;
2159 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2160 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2163 /* Release the buffers (with sanity checks)*/
2164 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2165 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2166 if(This->depthStencilBuffer != This->stencilBufferTarget)
2167 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2169 This->stencilBufferTarget = NULL;
2171 TRACE("Releasing the render target at %p\n", This->renderTarget);
2172 if(IWineD3DSurface_Release(This->renderTarget) >0){
2173 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2175 TRACE("Setting rendertarget to NULL\n");
2176 This->renderTarget = NULL;
2178 if (This->depthStencilBuffer) {
2179 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2180 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2181 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2182 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2184 This->depthStencilBuffer = NULL;
2187 for(i=0; i < This->NumberOfSwapChains; i++) {
2188 TRACE("Releasing the implicit swapchain %d\n", i);
2189 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2190 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2191 IUnknown_Release(swapChainParent); /* once for the get parent */
2192 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2193 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2197 HeapFree(GetProcessHeap(), 0, This->swapchains);
2198 This->swapchains = NULL;
2199 This->NumberOfSwapChains = 0;
2201 This->d3d_initialized = FALSE;
2202 return WINED3D_OK;
2205 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2207 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2209 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2210 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2211 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2212 * separately.
2214 This->ddraw_fullscreen = fullscreen;
2217 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2220 DEVMODEW DevModeW;
2221 int i;
2222 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2224 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2226 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2227 /* Ignore some modes if a description was passed */
2228 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2229 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2230 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2232 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2234 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2235 return D3D_OK;
2238 return D3D_OK;
2241 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2242 DEVMODEW devmode;
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 LONG ret;
2245 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2247 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2249 /* Resize the screen even without a window:
2250 * The app could have unset it with SetCooperativeLevel, but not called
2251 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2252 * but we don't have any hwnd
2255 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2256 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2257 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2258 devmode.dmPelsWidth = pMode->Width;
2259 devmode.dmPelsHeight = pMode->Height;
2261 devmode.dmDisplayFrequency = pMode->RefreshRate;
2262 if (pMode->RefreshRate != 0) {
2263 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2266 /* Only change the mode if necessary */
2267 if( (This->ddraw_width == pMode->Width) &&
2268 (This->ddraw_height == pMode->Height) &&
2269 (This->ddraw_format == pMode->Format) &&
2270 (pMode->RefreshRate == 0) ) {
2271 return D3D_OK;
2274 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2275 if (ret != DISP_CHANGE_SUCCESSFUL) {
2276 if(devmode.dmDisplayFrequency != 0) {
2277 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2278 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2279 devmode.dmDisplayFrequency = 0;
2280 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2282 if(ret != DISP_CHANGE_SUCCESSFUL) {
2283 return DDERR_INVALIDMODE;
2287 /* Store the new values */
2288 This->ddraw_width = pMode->Width;
2289 This->ddraw_height = pMode->Height;
2290 This->ddraw_format = pMode->Format;
2292 /* Only do this with a window of course */
2293 if(This->ddraw_window)
2294 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2296 return WINED3D_OK;
2299 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2301 *ppD3D= This->wineD3D;
2302 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2303 return WINED3D_OK;
2306 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2307 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2308 * into the video ram as possible and seeing how many fit
2309 * you can also get the correct initial value from nvidia and ATI's driver via X
2310 * texture memory is video memory + AGP memory
2311 *******************/
2312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 static BOOL showfixmes = TRUE;
2314 if (showfixmes) {
2315 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2316 (wined3d_settings.emulated_textureram/(1024*1024)),
2317 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2318 showfixmes = FALSE;
2320 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2321 (wined3d_settings.emulated_textureram/(1024*1024)),
2322 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2323 /* return simulated texture memory left */
2324 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2329 /*****
2330 * Get / Set FVF
2331 *****/
2332 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 HRESULT hr = WINED3D_OK;
2336 /* Update the current state block */
2337 This->updateStateBlock->fvf = fvf;
2338 This->updateStateBlock->changed.fvf = TRUE;
2339 This->updateStateBlock->set.fvf = TRUE;
2341 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2342 return hr;
2346 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2349 *pfvf = This->stateBlock->fvf;
2350 return WINED3D_OK;
2353 /*****
2354 * Get / Set Stream Source
2355 *****/
2356 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2358 IWineD3DVertexBuffer *oldSrc;
2360 /**TODO: instance and index data, see
2361 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2363 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2364 **************/
2366 /* D3d9 only, but shouldn't hurt d3d8 */
2367 UINT streamFlags;
2369 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2370 if (streamFlags) {
2371 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2372 FIXME("stream index data not supported\n");
2374 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2375 FIXME("stream instance data not supported\n");
2379 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2381 if (StreamNumber >= MAX_STREAMS) {
2382 WARN("Stream out of range %d\n", StreamNumber);
2383 return WINED3DERR_INVALIDCALL;
2386 oldSrc = This->stateBlock->streamSource[StreamNumber];
2387 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2389 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2390 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2391 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2392 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2393 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2394 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2396 /* Handle recording of state blocks */
2397 if (This->isRecordingState) {
2398 TRACE("Recording... not performing anything\n");
2399 return WINED3D_OK;
2402 /* Same stream object: no action */
2403 if (oldSrc == pStreamData)
2404 return WINED3D_OK;
2406 /* Need to do a getParent and pass the reffs up */
2407 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2408 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2409 so for now, just count internally */
2410 if (pStreamData != NULL) {
2411 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2412 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2413 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2415 vbImpl->stream = StreamNumber;
2416 vbImpl->Flags |= VBFLAG_STREAM;
2417 IWineD3DVertexBuffer_AddRef(pStreamData);
2419 if (oldSrc != NULL) {
2420 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2421 IWineD3DVertexBuffer_Release(oldSrc);
2424 return WINED3D_OK;
2427 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2429 UINT streamFlags;
2431 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2432 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2435 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2436 if (streamFlags) {
2437 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2438 FIXME("stream index data not supported\n");
2440 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2441 FIXME("stream instance data not supported\n");
2445 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2447 if (StreamNumber >= MAX_STREAMS) {
2448 WARN("Stream out of range %d\n", StreamNumber);
2449 return WINED3DERR_INVALIDCALL;
2451 *pStream = This->stateBlock->streamSource[StreamNumber];
2452 *pStride = This->stateBlock->streamStride[StreamNumber];
2453 if (pOffset) {
2454 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2457 if (*pStream == NULL) {
2458 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2459 return WINED3DERR_INVALIDCALL;
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((const 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, (const 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 if (*ppIndexData) {
3240 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3241 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3242 }else{
3243 TRACE("(%p) No index data set\n", This);
3245 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3247 return WINED3D_OK;
3250 /*****
3251 * Get / Set Viewports
3252 *****/
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 TRACE("(%p)\n", This);
3257 This->updateStateBlock->changed.viewport = TRUE;
3258 This->updateStateBlock->set.viewport = TRUE;
3259 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3261 /* Handle recording of state blocks */
3262 if (This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3264 return WINED3D_OK;
3266 This->viewport_changed = TRUE;
3268 ENTER_GL();
3270 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3271 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3273 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3274 checkGLcall("glDepthRange");
3275 /* Note: GL requires lower left, DirectX supplies upper left */
3276 /* TODO: replace usage of renderTarget with context management */
3277 glViewport(pViewport->X,
3278 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3279 pViewport->Width, pViewport->Height);
3281 checkGLcall("glViewport");
3283 LEAVE_GL();
3285 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 TRACE("(%p)\n", This);
3292 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3293 return WINED3D_OK;
3296 static void renderstate_stencil_twosided(
3297 IWineD3DDeviceImpl *This,
3298 GLint face,
3299 GLint func,
3300 GLint ref,
3301 GLuint mask,
3302 GLint stencilFail,
3303 GLint depthFail,
3304 GLint stencilPass ) {
3305 #if 0 /* Don't use OpenGL 2.0 calls for now */
3306 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3307 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3308 checkGLcall("glStencilFuncSeparate(...)");
3309 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3310 checkGLcall("glStencilOpSeparate(...)");
3312 else
3313 #endif
3314 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3315 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3316 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3317 GL_EXTCALL(glActiveStencilFaceEXT(face));
3318 checkGLcall("glActiveStencilFaceEXT(...)");
3319 glStencilFunc(func, ref, mask);
3320 checkGLcall("glStencilFunc(...)");
3321 glStencilOp(stencilFail, depthFail, stencilPass);
3322 checkGLcall("glStencilOp(...)");
3323 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3324 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3325 checkGLcall("glStencilFuncSeparateATI(...)");
3326 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3327 checkGLcall("glStencilOpSeparateATI(...)");
3328 } else {
3329 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3333 static void renderstate_stencil(IWineD3DDeviceImpl *This, WINED3DRENDERSTATETYPE State, DWORD Value) {
3334 DWORD onesided_enable = FALSE;
3335 DWORD twosided_enable = FALSE;
3336 GLint func = GL_ALWAYS;
3337 GLint func_ccw = GL_ALWAYS;
3338 GLint ref = 0;
3339 GLuint mask = 0;
3340 GLint stencilFail = GL_KEEP;
3341 GLint depthFail = GL_KEEP;
3342 GLint stencilPass = GL_KEEP;
3343 GLint stencilFail_ccw = GL_KEEP;
3344 GLint depthFail_ccw = GL_KEEP;
3345 GLint stencilPass_ccw = GL_KEEP;
3347 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3348 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3349 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3350 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3351 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3352 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3353 func = GL_ALWAYS;
3354 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3355 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3356 func = GL_ALWAYS;
3357 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3358 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3359 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3360 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3361 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3362 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3363 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3364 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3365 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3366 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3367 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3368 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3369 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3370 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3371 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3372 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3374 TRACE("(onesided %d, twosided %d, ref %x, mask %x, \
3375 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3376 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3377 onesided_enable, twosided_enable, ref, mask,
3378 func, stencilFail, depthFail, stencilPass,
3379 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3381 if (twosided_enable) {
3382 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3383 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3384 } else {
3385 if (onesided_enable) {
3386 glEnable(GL_STENCIL_TEST);
3387 checkGLcall("glEnable GL_STENCIL_TEST");
3388 glStencilFunc(func, ref, mask);
3389 checkGLcall("glStencilFunc(...)");
3390 glStencilOp(stencilFail, depthFail, stencilPass);
3391 checkGLcall("glStencilOp(...)");
3392 } else {
3393 glDisable(GL_STENCIL_TEST);
3394 checkGLcall("glDisable GL_STENCIL_TEST");
3399 /*****
3400 * Get / Set Render States
3401 * TODO: Verify against dx9 definitions
3402 *****/
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3406 DWORD OldValue = This->stateBlock->renderState[State];
3408 /* Simple way of referring to either a DWORD or a 4 byte float */
3409 union {
3410 DWORD d;
3411 float f;
3412 } tmpvalue;
3414 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3415 This->updateStateBlock->changed.renderState[State] = TRUE;
3416 This->updateStateBlock->set.renderState[State] = TRUE;
3417 This->updateStateBlock->renderState[State] = Value;
3419 /* Handle recording of state blocks */
3420 if (This->isRecordingState) {
3421 TRACE("Recording... not performing anything\n");
3422 return WINED3D_OK;
3425 ENTER_GL();
3427 switch (State) {
3428 case WINED3DRS_FILLMODE :
3429 switch ((WINED3DFILLMODE) Value) {
3430 case WINED3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3431 case WINED3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3432 case WINED3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3433 default:
3434 FIXME("Unrecognized WINED3DRS_FILLMODE value %d\n", Value);
3436 checkGLcall("glPolygonMode (fillmode)");
3437 break;
3439 case WINED3DRS_LIGHTING :
3440 if (Value) {
3441 glEnable(GL_LIGHTING);
3442 checkGLcall("glEnable GL_LIGHTING");
3443 } else {
3444 glDisable(GL_LIGHTING);
3445 checkGLcall("glDisable GL_LIGHTING");
3447 break;
3449 case WINED3DRS_ZENABLE :
3450 switch ((WINED3DZBUFFERTYPE) Value) {
3451 case WINED3DZB_FALSE:
3452 glDisable(GL_DEPTH_TEST);
3453 checkGLcall("glDisable GL_DEPTH_TEST");
3454 break;
3455 case WINED3DZB_TRUE:
3456 glEnable(GL_DEPTH_TEST);
3457 checkGLcall("glEnable GL_DEPTH_TEST");
3458 break;
3459 case WINED3DZB_USEW:
3460 glEnable(GL_DEPTH_TEST);
3461 checkGLcall("glEnable GL_DEPTH_TEST");
3462 FIXME("W buffer is not well handled\n");
3463 break;
3464 default:
3465 FIXME("Unrecognized WINED3DZBUFFERTYPE value %d\n", Value);
3467 break;
3469 case WINED3DRS_CULLMODE :
3471 /* If we are culling "back faces with clockwise vertices" then
3472 set front faces to be counter clockwise and enable culling
3473 of back faces */
3474 switch ((WINED3DCULL) Value) {
3475 case WINED3DCULL_NONE:
3476 glDisable(GL_CULL_FACE);
3477 checkGLcall("glDisable GL_CULL_FACE");
3478 break;
3479 case WINED3DCULL_CW:
3480 glEnable(GL_CULL_FACE);
3481 checkGLcall("glEnable GL_CULL_FACE");
3482 if (This->render_offscreen) {
3483 glFrontFace(GL_CW);
3484 checkGLcall("glFrontFace GL_CW");
3485 } else {
3486 glFrontFace(GL_CCW);
3487 checkGLcall("glFrontFace GL_CCW");
3489 glCullFace(GL_BACK);
3490 break;
3491 case WINED3DCULL_CCW:
3492 glEnable(GL_CULL_FACE);
3493 checkGLcall("glEnable GL_CULL_FACE");
3494 if (This->render_offscreen) {
3495 glFrontFace(GL_CCW);
3496 checkGLcall("glFrontFace GL_CCW");
3497 } else {
3498 glFrontFace(GL_CW);
3499 checkGLcall("glFrontFace GL_CW");
3501 glCullFace(GL_BACK);
3502 break;
3503 default:
3504 FIXME("Unrecognized/Unhandled WINED3DCULL value %d\n", Value);
3506 break;
3508 case WINED3DRS_SHADEMODE :
3509 switch ((WINED3DSHADEMODE) Value) {
3510 case WINED3DSHADE_FLAT:
3511 glShadeModel(GL_FLAT);
3512 checkGLcall("glShadeModel");
3513 break;
3514 case WINED3DSHADE_GOURAUD:
3515 glShadeModel(GL_SMOOTH);
3516 checkGLcall("glShadeModel");
3517 break;
3518 case WINED3DSHADE_PHONG:
3519 FIXME("WINED3DSHADE_PHONG isn't supported\n");
3520 break;
3521 default:
3522 FIXME("Unrecognized/Unhandled WINED3DSHADEMODE value %d\n", Value);
3524 break;
3526 case WINED3DRS_DITHERENABLE :
3527 if (Value) {
3528 glEnable(GL_DITHER);
3529 checkGLcall("glEnable GL_DITHER");
3530 } else {
3531 glDisable(GL_DITHER);
3532 checkGLcall("glDisable GL_DITHER");
3534 break;
3536 case WINED3DRS_ZWRITEENABLE :
3537 if (Value) {
3538 glDepthMask(1);
3539 checkGLcall("glDepthMask");
3540 } else {
3541 glDepthMask(0);
3542 checkGLcall("glDepthMask");
3544 break;
3546 case WINED3DRS_ZFUNC :
3548 int glParm = CompareFunc(Value);
3550 if(glParm) {
3551 glDepthFunc(glParm);
3552 checkGLcall("glDepthFunc");
3555 break;
3557 case WINED3DRS_AMBIENT :
3559 float col[4];
3560 D3DCOLORTOGLFLOAT4(Value, col);
3561 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3562 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3563 checkGLcall("glLightModel for MODEL_AMBIENT");
3566 break;
3568 case WINED3DRS_ALPHABLENDENABLE :
3569 if (Value) {
3570 glEnable(GL_BLEND);
3571 checkGLcall("glEnable GL_BLEND");
3572 } else {
3573 glDisable(GL_BLEND);
3574 checkGLcall("glDisable GL_BLEND");
3576 break;
3578 case WINED3DRS_SRCBLEND :
3579 case WINED3DRS_DESTBLEND :
3581 int newVal = GL_ZERO;
3582 switch (Value) {
3583 case WINED3DBLEND_ZERO : newVal = GL_ZERO; break;
3584 case WINED3DBLEND_ONE : newVal = GL_ONE; break;
3585 case WINED3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3586 case WINED3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3587 case WINED3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3588 case WINED3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3589 case WINED3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3590 case WINED3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3591 case WINED3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3592 case WINED3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3593 case WINED3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3595 case WINED3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3596 This->srcBlend = newVal;
3597 This->dstBlend = newVal;
3598 break;
3600 case WINED3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3601 This->srcBlend = newVal;
3602 This->dstBlend = newVal;
3603 break;
3604 case WINED3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3605 case WINED3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3606 default:
3607 FIXME("Unrecognized src/dest blend value %d (%d)\n", Value, State);
3610 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3611 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3612 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3613 glBlendFunc(This->srcBlend, This->dstBlend);
3615 checkGLcall("glBlendFunc");
3617 break;
3619 case WINED3DRS_ALPHATESTENABLE :
3620 case WINED3DRS_ALPHAFUNC :
3621 case WINED3DRS_ALPHAREF :
3622 case WINED3DRS_COLORKEYENABLE :
3624 int glParm = 0;
3625 float ref;
3626 BOOL enable_ckey = FALSE;
3628 IWineD3DSurfaceImpl *surf;
3630 /* Find out if the texture on the first stage has a ckey set */
3631 if(This->stateBlock->textures[0]) {
3632 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3633 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3636 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3637 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3638 glEnable(GL_ALPHA_TEST);
3639 checkGLcall("glEnable GL_ALPHA_TEST");
3640 } else {
3641 glDisable(GL_ALPHA_TEST);
3642 checkGLcall("glDisable GL_ALPHA_TEST");
3643 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3644 * enable call
3646 break;
3649 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3650 glParm = GL_NOTEQUAL;
3651 ref = 0.0;
3652 } else {
3653 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3654 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3656 if(glParm) {
3657 This->alphafunc = glParm;
3658 glAlphaFunc(glParm, ref);
3659 checkGLcall("glAlphaFunc");
3662 break;
3664 case WINED3DRS_CLIPPLANEENABLE :
3665 case WINED3DRS_CLIPPING :
3667 /* Ensure we only do the changed clip planes */
3668 DWORD enable = 0xFFFFFFFF;
3669 DWORD disable = 0x00000000;
3671 /* If enabling / disabling all */
3672 if (State == WINED3DRS_CLIPPING) {
3673 if (Value) {
3674 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3675 disable = 0x00;
3676 } else {
3677 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3678 enable = 0x00;
3680 } else {
3681 enable = Value & ~OldValue;
3682 disable = ~Value & OldValue;
3685 if (enable & WINED3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3686 if (enable & WINED3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3687 if (enable & WINED3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3688 if (enable & WINED3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3689 if (enable & WINED3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3690 if (enable & WINED3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3692 if (disable & WINED3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3693 if (disable & WINED3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3694 if (disable & WINED3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3695 if (disable & WINED3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3696 if (disable & WINED3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3697 if (disable & WINED3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3699 /** update clipping status */
3700 if (enable) {
3701 This->stateBlock->clip_status.ClipUnion = 0;
3702 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3703 } else {
3704 This->stateBlock->clip_status.ClipUnion = 0;
3705 This->stateBlock->clip_status.ClipIntersection = 0;
3708 break;
3710 case WINED3DRS_BLENDOP :
3712 int glParm = GL_FUNC_ADD;
3714 switch ((WINED3DBLENDOP) Value) {
3715 case WINED3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3716 case WINED3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3717 case WINED3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3718 case WINED3DBLENDOP_MIN : glParm = GL_MIN; break;
3719 case WINED3DBLENDOP_MAX : glParm = GL_MAX; break;
3720 default:
3721 FIXME("Unrecognized/Unhandled WINED3DBLENDOP value %d\n", Value);
3724 if(GL_SUPPORT(EXT_BLEND_MINMAX)) {
3725 TRACE("glBlendEquation(%x)\n", glParm);
3726 GL_EXTCALL(glBlendEquation(glParm));
3727 checkGLcall("glBlendEquation");
3728 } else {
3729 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3732 break;
3734 case WINED3DRS_TEXTUREFACTOR :
3736 unsigned int i;
3738 /* Note the texture color applies to all textures whereas
3739 GL_TEXTURE_ENV_COLOR applies to active only */
3740 float col[4];
3741 D3DCOLORTOGLFLOAT4(Value, col);
3743 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3744 /* And now the default texture color as well */
3745 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3746 /* Note the WINED3DRS value applies to all textures, but GL has one
3747 per texture, so apply it now ready to be used! */
3748 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3749 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3750 checkGLcall("glActiveTextureARB");
3751 } else if (i>0) {
3752 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3755 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3756 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3760 break;
3762 case WINED3DRS_SPECULARENABLE :
3764 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3765 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3766 specular color. This is wrong:
3767 Separate specular color means the specular colour is maintained separately, whereas
3768 single color means it is merged in. However in both cases they are being used to
3769 some extent.
3770 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3771 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3772 running 1.4 yet!
3775 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3776 * Instead, we need to setup the FinalCombiner properly.
3778 * The default setup for the FinalCombiner is:
3780 * <variable> <input> <mapping> <usage>
3781 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3782 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3783 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3784 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3785 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3786 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3787 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3789 * That's pretty much fine as it is, except for variable B, which needs to take
3790 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3791 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3794 if (Value) {
3795 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3796 checkGLcall("glMaterialfv");
3797 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3798 glEnable(GL_COLOR_SUM_EXT);
3799 } else {
3800 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3802 checkGLcall("glEnable(GL_COLOR_SUM)");
3804 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3805 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3806 checkGLcall("glFinalCombinerInputNV()");
3808 } else {
3809 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3811 /* for the case of enabled lighting: */
3812 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3813 checkGLcall("glMaterialfv");
3815 /* for the case of disabled lighting: */
3816 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3817 glDisable(GL_COLOR_SUM_EXT);
3818 } else {
3819 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3821 checkGLcall("glDisable(GL_COLOR_SUM)");
3823 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3824 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3825 checkGLcall("glFinalCombinerInputNV()");
3829 break;
3831 case WINED3DRS_STENCILENABLE :
3832 case WINED3DRS_TWOSIDEDSTENCILMODE :
3833 case WINED3DRS_STENCILFUNC :
3834 case WINED3DRS_CCW_STENCILFUNC :
3835 case WINED3DRS_STENCILREF :
3836 case WINED3DRS_STENCILMASK :
3837 case WINED3DRS_STENCILFAIL :
3838 case WINED3DRS_STENCILZFAIL :
3839 case WINED3DRS_STENCILPASS :
3840 case WINED3DRS_CCW_STENCILFAIL :
3841 case WINED3DRS_CCW_STENCILZFAIL :
3842 case WINED3DRS_CCW_STENCILPASS :
3843 renderstate_stencil(This, State, Value);
3844 break;
3845 case WINED3DRS_STENCILWRITEMASK :
3847 glStencilMask(Value);
3848 TRACE("glStencilMask(%u)\n", Value);
3849 checkGLcall("glStencilMask");
3851 break;
3853 case WINED3DRS_FOGENABLE :
3855 if (Value) {
3856 glEnable(GL_FOG);
3857 checkGLcall("glEnable GL_FOG");
3858 } else {
3859 glDisable(GL_FOG);
3860 checkGLcall("glDisable GL_FOG");
3863 break;
3865 case WINED3DRS_RANGEFOGENABLE :
3867 if (Value) {
3868 TRACE("Enabled RANGEFOG\n");
3869 } else {
3870 TRACE("Disabled RANGEFOG\n");
3873 break;
3875 case WINED3DRS_FOGCOLOR :
3877 float col[4];
3878 D3DCOLORTOGLFLOAT4(Value, col);
3879 /* Set the default alpha blend color */
3880 glFogfv(GL_FOG_COLOR, &col[0]);
3881 checkGLcall("glFog GL_FOG_COLOR");
3883 break;
3885 case WINED3DRS_FOGTABLEMODE :
3886 case WINED3DRS_FOGVERTEXMODE :
3888 /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */
3889 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
3890 glHint(GL_FOG_HINT, GL_FASTEST);
3891 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3892 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3893 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3894 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3896 case WINED3DFOG_EXP: {
3897 if(!This->last_was_rhw) {
3898 glFogi(GL_FOG_MODE, GL_EXP);
3899 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3900 if(GL_SUPPORT(EXT_FOG_COORD)) {
3901 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3902 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3903 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3904 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3906 break;
3909 case WINED3DFOG_EXP2: {
3910 if(!This->last_was_rhw) {
3911 glFogi(GL_FOG_MODE, GL_EXP2);
3912 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3913 if(GL_SUPPORT(EXT_FOG_COORD)) {
3914 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3915 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3916 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3917 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3919 break;
3922 case WINED3DFOG_LINEAR: {
3923 if(!This->last_was_rhw) {
3924 glFogi(GL_FOG_MODE, GL_LINEAR);
3925 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3926 if(GL_SUPPORT(EXT_FOG_COORD)) {
3927 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3928 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3929 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3930 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3932 break;
3935 case WINED3DFOG_NONE: {
3936 /* Both are none? According to msdn the alpha channel of the specular
3937 * color contains a fog factor. Set it in drawStridedSlow.
3938 * Same happens with Vertexfog on transformed vertices
3940 if(GL_SUPPORT(EXT_FOG_COORD)) {
3941 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3942 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3943 glFogi(GL_FOG_MODE, GL_LINEAR);
3944 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3945 glFogf(GL_FOG_START, (float) 0xff);
3946 checkGLcall("glFogfv GL_FOG_START");
3947 glFogf(GL_FOG_END, 0.0);
3948 checkGLcall("glFogfv GL_FOG_END");
3949 } else {
3950 /* Disable GL fog, handle this in software in drawStridedSlow */
3951 glDisable(GL_FOG);
3952 checkGLcall("glDisable(GL_FOG)");
3954 break;
3956 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3958 } else {
3959 glHint(GL_FOG_HINT, GL_NICEST);
3960 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3961 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3962 case WINED3DFOG_EXP:
3963 glFogi(GL_FOG_MODE, GL_EXP);
3964 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3965 if(GL_SUPPORT(EXT_FOG_COORD)) {
3966 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3967 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3968 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3969 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3971 break;
3972 case WINED3DFOG_EXP2:
3973 glFogi(GL_FOG_MODE, GL_EXP2);
3974 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3975 if(GL_SUPPORT(EXT_FOG_COORD)) {
3976 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3977 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3978 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3979 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3981 break;
3982 case WINED3DFOG_LINEAR:
3983 glFogi(GL_FOG_MODE, GL_LINEAR);
3984 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3985 if(GL_SUPPORT(EXT_FOG_COORD)) {
3986 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3987 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3989 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3991 break;
3992 case WINED3DFOG_NONE:
3993 default: /* Won't happen */
3994 FIXME("Unexpected WINED3DRS_FOGTABLEMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3997 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3998 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4001 break;
4003 case WINED3DRS_FOGSTART :
4005 tmpvalue.d = Value;
4006 glFogfv(GL_FOG_START, &tmpvalue.f);
4007 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4008 TRACE("Fog Start == %f\n", tmpvalue.f);
4010 break;
4012 case WINED3DRS_FOGEND :
4014 tmpvalue.d = Value;
4015 glFogfv(GL_FOG_END, &tmpvalue.f);
4016 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4017 TRACE("Fog End == %f\n", tmpvalue.f);
4019 break;
4021 case WINED3DRS_FOGDENSITY :
4023 tmpvalue.d = Value;
4024 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4025 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4027 break;
4029 case WINED3DRS_VERTEXBLEND :
4031 This->updateStateBlock->vertex_blend = (WINED3DVERTEXBLENDFLAGS) Value;
4032 TRACE("Vertex Blending state to %d\n", Value);
4034 break;
4036 case WINED3DRS_TWEENFACTOR :
4038 tmpvalue.d = Value;
4039 This->updateStateBlock->tween_factor = tmpvalue.f;
4040 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4042 break;
4044 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4046 TRACE("Indexed Vertex Blend Enable to %u\n", (BOOL) Value);
4048 break;
4050 case WINED3DRS_COLORVERTEX :
4051 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4052 case WINED3DRS_SPECULARMATERIALSOURCE :
4053 case WINED3DRS_AMBIENTMATERIALSOURCE :
4054 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4056 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4058 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4059 TRACE("diff %d, amb %d, emis %d, spec %d\n",
4060 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4061 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4062 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4063 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4065 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4066 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4067 Parm = GL_AMBIENT_AND_DIFFUSE;
4068 } else {
4069 Parm = GL_DIFFUSE;
4071 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4072 Parm = GL_AMBIENT;
4073 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4074 Parm = GL_EMISSION;
4075 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4076 Parm = GL_SPECULAR;
4077 } else {
4078 Parm = -1;
4081 if (Parm == -1) {
4082 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4083 } else {
4084 This->tracking_color = NEEDS_TRACKING;
4085 This->tracking_parm = Parm;
4088 } else {
4089 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4092 break;
4094 case WINED3DRS_LINEPATTERN :
4096 union {
4097 DWORD d;
4098 WINED3DLINEPATTERN lp;
4099 } tmppattern;
4100 tmppattern.d = Value;
4102 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4104 if (tmppattern.lp.wRepeatFactor) {
4105 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4106 checkGLcall("glLineStipple(repeat, linepattern)");
4107 glEnable(GL_LINE_STIPPLE);
4108 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4109 } else {
4110 glDisable(GL_LINE_STIPPLE);
4111 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4114 break;
4116 case WINED3DRS_ZBIAS : /* D3D8 only */
4118 if (Value) {
4119 tmpvalue.d = Value;
4120 TRACE("ZBias value %f\n", tmpvalue.f);
4121 glPolygonOffset(0, -tmpvalue.f);
4122 checkGLcall("glPolygonOffset(0, -Value)");
4123 glEnable(GL_POLYGON_OFFSET_FILL);
4124 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4125 glEnable(GL_POLYGON_OFFSET_LINE);
4126 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4127 glEnable(GL_POLYGON_OFFSET_POINT);
4128 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4129 } else {
4130 glDisable(GL_POLYGON_OFFSET_FILL);
4131 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4132 glDisable(GL_POLYGON_OFFSET_LINE);
4133 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4134 glDisable(GL_POLYGON_OFFSET_POINT);
4135 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4138 break;
4140 case WINED3DRS_NORMALIZENORMALS :
4141 if (Value) {
4142 glEnable(GL_NORMALIZE);
4143 checkGLcall("glEnable(GL_NORMALIZE);");
4144 } else {
4145 glDisable(GL_NORMALIZE);
4146 checkGLcall("glDisable(GL_NORMALIZE);");
4148 break;
4150 case WINED3DRS_POINTSIZE :
4151 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4152 tmpvalue.d = Value;
4153 TRACE("Set point size to %f\n", tmpvalue.f);
4154 glPointSize(tmpvalue.f);
4155 checkGLcall("glPointSize(...);");
4156 break;
4158 case WINED3DRS_POINTSIZE_MIN :
4159 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4160 tmpvalue.d = Value;
4161 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4162 checkGLcall("glPointParameterfEXT(...);");
4163 } else {
4164 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4166 break;
4168 case WINED3DRS_POINTSIZE_MAX :
4169 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4170 tmpvalue.d = Value;
4171 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4172 checkGLcall("glPointParameterfEXT(...);");
4173 } else {
4174 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4176 break;
4178 case WINED3DRS_POINTSCALE_A :
4179 case WINED3DRS_POINTSCALE_B :
4180 case WINED3DRS_POINTSCALE_C :
4181 case WINED3DRS_POINTSCALEENABLE :
4184 * POINTSCALEENABLE controls how point size value is treated. If set to
4185 * true, the point size is scaled with respect to height of viewport.
4186 * When set to false point size is in pixels.
4188 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4191 /* Default values */
4192 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4195 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4196 * This means that OpenGL will clamp really small point sizes to 1.0f.
4197 * To correct for this we need to multiply by the scale factor when sizes
4198 * are less than 1.0f. scale_factor = 1.0f / point_size.
4200 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4201 if(pointSize > 0.0f) {
4202 GLfloat scaleFactor;
4204 if(pointSize < 1.0f) {
4205 scaleFactor = pointSize * pointSize;
4206 } else {
4207 scaleFactor = 1.0f;
4210 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4211 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4212 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4213 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4214 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4215 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4216 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4220 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4221 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4222 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4224 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4225 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4226 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4227 } else {
4228 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4230 break;
4232 case WINED3DRS_COLORWRITEENABLE :
4234 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4235 Value & WINED3DCOLORWRITEENABLE_RED ? 1 : 0,
4236 Value & WINED3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4237 Value & WINED3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4238 Value & WINED3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4239 glColorMask(Value & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4240 Value & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4241 Value & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4242 Value & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4243 checkGLcall("glColorMask(...)");
4245 break;
4247 case WINED3DRS_LOCALVIEWER :
4249 GLint state = (Value) ? 1 : 0;
4250 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4251 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4253 break;
4255 case WINED3DRS_LASTPIXEL :
4257 if (Value) {
4258 TRACE("Last Pixel Drawing Enabled\n");
4259 } else {
4260 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4263 break;
4265 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4267 if (Value) {
4268 TRACE("Software Processing Enabled\n");
4269 } else {
4270 TRACE("Software Processing Disabled\n");
4273 break;
4275 /** not supported */
4276 case WINED3DRS_ZVISIBLE :
4278 LEAVE_GL();
4279 return WINED3DERR_INVALIDCALL;
4281 case WINED3DRS_POINTSPRITEENABLE :
4283 /* TODO: NV_POINT_SPRITE */
4284 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4285 TRACE("Point sprites not supported\n");
4286 break;
4290 * Point sprites are always enabled. Value controls texture coordinate
4291 * replacement mode. Must be set true for point sprites to use
4292 * textures.
4294 glEnable(GL_POINT_SPRITE_ARB);
4295 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4297 if (Value) {
4298 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4299 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4300 } else {
4301 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4302 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4304 break;
4306 case WINED3DRS_EDGEANTIALIAS :
4308 if(Value) {
4309 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4310 glEnable(GL_BLEND);
4311 checkGLcall("glEnable(GL_BLEND)");
4312 glEnable(GL_LINE_SMOOTH);
4313 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4314 } else {
4315 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4316 glDisable(GL_BLEND);
4317 checkGLcall("glDisable(GL_BLEND)");
4319 glDisable(GL_LINE_SMOOTH);
4320 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4322 break;
4324 case WINED3DRS_WRAP0 :
4325 case WINED3DRS_WRAP1 :
4326 case WINED3DRS_WRAP2 :
4327 case WINED3DRS_WRAP3 :
4328 case WINED3DRS_WRAP4 :
4329 case WINED3DRS_WRAP5 :
4330 case WINED3DRS_WRAP6 :
4331 case WINED3DRS_WRAP7 :
4332 case WINED3DRS_WRAP8 :
4333 case WINED3DRS_WRAP9 :
4334 case WINED3DRS_WRAP10 :
4335 case WINED3DRS_WRAP11 :
4336 case WINED3DRS_WRAP12 :
4337 case WINED3DRS_WRAP13 :
4338 case WINED3DRS_WRAP14 :
4339 case WINED3DRS_WRAP15 :
4341 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4342 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4343 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4344 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4345 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4347 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4350 if(Value) {
4351 ERR("(%p)->(%s,%d) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4353 break;
4356 case WINED3DRS_MULTISAMPLEANTIALIAS :
4358 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4359 if(Value) {
4360 glEnable(GL_MULTISAMPLE_ARB);
4361 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4362 } else {
4363 glDisable(GL_MULTISAMPLE_ARB);
4364 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4366 } else {
4367 if(Value) {
4368 ERR("Multisample antialiasing not supported by gl\n");
4371 break;
4374 case WINED3DRS_SCISSORTESTENABLE :
4376 if(Value) {
4377 glEnable(GL_SCISSOR_TEST);
4378 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4379 } else {
4380 glDisable(GL_SCISSOR_TEST);
4381 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4383 break;
4385 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4387 if(Value) {
4388 tmpvalue.d = Value;
4389 glEnable(GL_POLYGON_OFFSET_FILL);
4390 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4391 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4392 checkGLcall("glPolygonOffset(...)");
4393 } else {
4394 glDisable(GL_POLYGON_OFFSET_FILL);
4395 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4397 break;
4399 case WINED3DRS_ANTIALIASEDLINEENABLE :
4401 if(Value) {
4402 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4403 glEnable(GL_BLEND);
4404 checkGLcall("glEnable(GL_BLEND)");
4405 glEnable(GL_LINE_SMOOTH);
4406 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4407 } else {
4408 glDisable(GL_BLEND);
4409 checkGLcall("glDisable(GL_BLEND)");
4410 glDisable(GL_LINE_SMOOTH);
4411 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4413 break;
4415 case WINED3DRS_DEPTHBIAS :
4417 if(Value) {
4418 tmpvalue.d = Value;
4419 glEnable(GL_POLYGON_OFFSET_FILL);
4420 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4421 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4422 checkGLcall("glPolygonOffset(...)");
4423 } else {
4424 glDisable(GL_POLYGON_OFFSET_FILL);
4425 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4427 break;
4430 case WINED3DRS_TEXTUREPERSPECTIVE :
4432 if (Value)
4433 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4434 else
4435 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4436 break;
4439 case WINED3DRS_STIPPLEDALPHA :
4441 if (Value)
4442 ERR(" Stippled Alpha not supported yet.\n");
4443 break;
4445 case WINED3DRS_ANTIALIAS :
4447 if (Value)
4448 ERR(" Antialias not supported yet.\n");
4449 break;
4452 case WINED3DRS_MULTISAMPLEMASK :
4454 if(0xFFFFFFFF != Value)
4455 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4456 break;
4459 case WINED3DRS_PATCHEDGESTYLE :
4461 if(WINED3DPATCHEDGE_DISCRETE != Value)
4462 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4463 break;
4466 case WINED3DRS_PATCHSEGMENTS :
4468 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4469 tmpvalue.f = 1.0f;
4470 if(tmpvalue.d != Value)
4471 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4472 break;
4475 case WINED3DRS_DEBUGMONITORTOKEN :
4477 /* Only useful for "debug builds". */
4478 if(0xbaadcafe != Value) {
4479 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4480 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4481 * but our tests disagree.
4482 * We do not claim to implement a debugging lib, so do not write an ERR
4484 WARN("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4486 break;
4489 case WINED3DRS_POSITIONDEGREE :
4491 if(WINED3DDEGREE_CUBIC != Value)
4492 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4493 break;
4496 case WINED3DRS_NORMALDEGREE :
4498 if(WINED3DDEGREE_LINEAR != Value)
4499 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4500 break;
4503 case WINED3DRS_MINTESSELLATIONLEVEL :
4504 case WINED3DRS_MAXTESSELLATIONLEVEL :
4505 case WINED3DRS_ADAPTIVETESS_X :
4506 case WINED3DRS_ADAPTIVETESS_Y :
4507 case WINED3DRS_ADAPTIVETESS_Z :
4508 case WINED3DRS_ADAPTIVETESS_W :
4510 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4511 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4512 else
4513 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4514 break;
4517 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4519 if(Value)
4520 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4521 break;
4524 case WINED3DRS_COLORWRITEENABLE1 :
4525 case WINED3DRS_COLORWRITEENABLE2 :
4526 case WINED3DRS_COLORWRITEENABLE3 :
4528 /* depends on WINED3DRS_COLORWRITEENABLE. */
4529 if(0x0000000F != Value)
4530 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4531 break;
4534 case WINED3DRS_BLENDFACTOR :
4536 float col[4];
4538 TRACE("Setting BlendFactor to %d\n", Value);
4540 D3DCOLORTOGLFLOAT4(Value, col);
4541 if (0xFFFFFFFF != Value) {
4542 glEnable(GL_BLEND);
4543 checkGLcall("glEnable(GL_BLEND)");
4545 else {
4546 glDisable(GL_BLEND);
4547 checkGLcall("glDisable(GL_BLEND)");
4549 glBlendColor (col[0],col[1],col[2],col[3]);
4550 break;
4553 case WINED3DRS_SRGBWRITEENABLE :
4555 if(Value)
4556 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4557 break;
4560 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4562 if(Value)
4563 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4564 break;
4567 case WINED3DRS_SRCBLENDALPHA :
4568 case WINED3DRS_DESTBLENDALPHA :
4569 case WINED3DRS_BLENDOPALPHA :
4571 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4572 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4573 else
4574 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4575 break;
4578 default:
4579 FIXME("(%p)->(%s,%d) unknown state\n", This, debug_d3drenderstate(State), Value);
4582 LEAVE_GL();
4584 return WINED3D_OK;
4587 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
4588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4589 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
4590 *pValue = This->stateBlock->renderState[State];
4591 return WINED3D_OK;
4594 /*****
4595 * Get / Set Sampler States
4596 * TODO: Verify against dx9 definitions
4597 *****/
4599 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 * SetSampler is designed to allow for more than the standard up to 8 textures
4603 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4604 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4606 * http://developer.nvidia.com/object/General_FAQ.html#t6
4608 * There are two new settings for GForce
4609 * the sampler one:
4610 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4611 * and the texture one:
4612 * GL_MAX_TEXTURE_COORDS_ARB.
4613 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4614 ******************/
4615 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4616 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4617 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4618 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4619 return WINED3DERR_INVALIDCALL;
4622 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
4623 debug_d3dsamplerstate(Type), Type, Value);
4624 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4625 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4626 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4628 /* Handle recording of state blocks */
4629 if (This->isRecordingState) {
4630 TRACE("Recording... not performing anything\n");
4631 return WINED3D_OK;
4634 return WINED3D_OK;
4637 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4639 /** TODO: check that sampler is in range **/
4640 *Value = This->stateBlock->samplerState[Sampler][Type];
4641 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
4643 return WINED3D_OK;
4646 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4648 RECT windowRect;
4649 UINT winHeight;
4651 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
4652 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
4653 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
4655 winHeight = windowRect.bottom - windowRect.top;
4656 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
4657 pRect->right - pRect->left, pRect->bottom - pRect->top);
4658 ENTER_GL();
4659 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
4660 checkGLcall("glScissor");
4661 LEAVE_GL();
4663 return WINED3D_OK;
4666 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 GLint scissorBox[4];
4670 ENTER_GL();
4671 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4672 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4673 pRect->left = scissorBox[0];
4674 pRect->top = scissorBox[1];
4675 pRect->right = scissorBox[0] + scissorBox[2];
4676 pRect->bottom = scissorBox[1] + scissorBox[3];
4677 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4678 LEAVE_GL();
4679 return WINED3D_OK;
4682 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4684 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4686 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4688 This->updateStateBlock->vertexDecl = pDecl;
4689 This->updateStateBlock->changed.vertexDecl = TRUE;
4690 This->updateStateBlock->set.vertexDecl = TRUE;
4692 if (This->isRecordingState) {
4693 TRACE("Recording... not performing anything\n");
4696 if (NULL != pDecl) {
4697 IWineD3DVertexDeclaration_AddRef(pDecl);
4699 if (NULL != oldDecl) {
4700 IWineD3DVertexDeclaration_Release(oldDecl);
4702 return WINED3D_OK;
4705 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4710 *ppDecl = This->stateBlock->vertexDecl;
4711 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4712 return WINED3D_OK;
4715 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4719 This->updateStateBlock->vertexShader = pShader;
4720 This->updateStateBlock->changed.vertexShader = TRUE;
4721 This->updateStateBlock->set.vertexShader = TRUE;
4723 if (This->isRecordingState) {
4724 TRACE("Recording... not performing anything\n");
4727 if (NULL != pShader) {
4728 IWineD3DVertexShader_AddRef(pShader);
4730 if (NULL != oldShader) {
4731 IWineD3DVertexShader_Release(oldShader);
4734 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4736 * TODO: merge HAL shaders context switching from prototype
4738 return WINED3D_OK;
4741 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 if (NULL == ppShader) {
4745 return WINED3DERR_INVALIDCALL;
4747 *ppShader = This->stateBlock->vertexShader;
4748 if( NULL != *ppShader)
4749 IWineD3DVertexShader_AddRef(*ppShader);
4751 TRACE("(%p) : returning %p\n", This, *ppShader);
4752 return WINED3D_OK;
4755 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4756 IWineD3DDevice *iface,
4757 UINT start,
4758 CONST BOOL *srcData,
4759 UINT count) {
4761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4762 int i, cnt = min(count, MAX_CONST_B - start);
4764 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4765 iface, srcData, start, count);
4767 if (srcData == NULL || cnt < 0)
4768 return WINED3DERR_INVALIDCALL;
4770 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4771 for (i = 0; i < cnt; i++)
4772 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4774 for (i = start; i < cnt + start; ++i) {
4775 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4776 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4779 return WINED3D_OK;
4782 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4783 IWineD3DDevice *iface,
4784 UINT start,
4785 BOOL *dstData,
4786 UINT count) {
4788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4789 int cnt = min(count, MAX_CONST_B - start);
4791 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4792 iface, dstData, start, count);
4794 if (dstData == NULL || cnt < 0)
4795 return WINED3DERR_INVALIDCALL;
4797 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4798 return WINED3D_OK;
4801 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4802 IWineD3DDevice *iface,
4803 UINT start,
4804 CONST int *srcData,
4805 UINT count) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 int i, cnt = min(count, MAX_CONST_I - start);
4810 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4811 iface, srcData, start, count);
4813 if (srcData == NULL || cnt < 0)
4814 return WINED3DERR_INVALIDCALL;
4816 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4817 for (i = 0; i < cnt; i++)
4818 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4819 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4821 for (i = start; i < cnt + start; ++i) {
4822 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4823 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4826 return WINED3D_OK;
4829 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4830 IWineD3DDevice *iface,
4831 UINT start,
4832 int *dstData,
4833 UINT count) {
4835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4836 int cnt = min(count, MAX_CONST_I - start);
4838 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4839 iface, dstData, start, count);
4841 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4842 return WINED3DERR_INVALIDCALL;
4844 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4849 IWineD3DDevice *iface,
4850 UINT start,
4851 CONST float *srcData,
4852 UINT count) {
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4857 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4858 iface, srcData, start, count);
4860 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4861 return WINED3DERR_INVALIDCALL;
4863 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4864 for (i = 0; i < cnt; i++)
4865 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4866 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4868 for (i = start; i < cnt + start; ++i) {
4869 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4870 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4871 ptr->idx = i;
4872 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4873 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4875 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4878 return WINED3D_OK;
4881 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4882 IWineD3DDevice *iface,
4883 UINT start,
4884 float *dstData,
4885 UINT count) {
4887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4888 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4890 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4891 iface, dstData, start, count);
4893 if (dstData == NULL || cnt < 0)
4894 return WINED3DERR_INVALIDCALL;
4896 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4897 return WINED3D_OK;
4900 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4902 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4903 This->updateStateBlock->pixelShader = pShader;
4904 This->updateStateBlock->changed.pixelShader = TRUE;
4905 This->updateStateBlock->set.pixelShader = TRUE;
4907 /* Handle recording of state blocks */
4908 if (This->isRecordingState) {
4909 TRACE("Recording... not performing anything\n");
4912 if (NULL != pShader) {
4913 IWineD3DPixelShader_AddRef(pShader);
4915 if (NULL != oldShader) {
4916 IWineD3DPixelShader_Release(oldShader);
4919 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4921 * TODO: merge HAL shaders context switching from prototype
4923 return WINED3D_OK;
4926 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4929 if (NULL == ppShader) {
4930 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4931 return WINED3DERR_INVALIDCALL;
4934 *ppShader = This->stateBlock->pixelShader;
4935 if (NULL != *ppShader) {
4936 IWineD3DPixelShader_AddRef(*ppShader);
4938 TRACE("(%p) : returning %p\n", This, *ppShader);
4939 return WINED3D_OK;
4942 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4943 IWineD3DDevice *iface,
4944 UINT start,
4945 CONST BOOL *srcData,
4946 UINT count) {
4948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4949 int i, cnt = min(count, MAX_CONST_B - start);
4951 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4952 iface, srcData, start, count);
4954 if (srcData == NULL || cnt < 0)
4955 return WINED3DERR_INVALIDCALL;
4957 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4958 for (i = 0; i < cnt; i++)
4959 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4961 for (i = start; i < cnt + start; ++i) {
4962 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4963 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4966 return WINED3D_OK;
4969 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4970 IWineD3DDevice *iface,
4971 UINT start,
4972 BOOL *dstData,
4973 UINT count) {
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4976 int cnt = min(count, MAX_CONST_B - start);
4978 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4979 iface, dstData, start, count);
4981 if (dstData == NULL || cnt < 0)
4982 return WINED3DERR_INVALIDCALL;
4984 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4985 return WINED3D_OK;
4988 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4989 IWineD3DDevice *iface,
4990 UINT start,
4991 CONST int *srcData,
4992 UINT count) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 int i, cnt = min(count, MAX_CONST_I - start);
4997 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4998 iface, srcData, start, count);
5000 if (srcData == NULL || cnt < 0)
5001 return WINED3DERR_INVALIDCALL;
5003 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
5004 for (i = 0; i < cnt; i++)
5005 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
5006 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5008 for (i = start; i < cnt + start; ++i) {
5009 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
5010 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
5013 return WINED3D_OK;
5016 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
5017 IWineD3DDevice *iface,
5018 UINT start,
5019 int *dstData,
5020 UINT count) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5023 int cnt = min(count, MAX_CONST_I - start);
5025 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5026 iface, dstData, start, count);
5028 if (dstData == NULL || cnt < 0)
5029 return WINED3DERR_INVALIDCALL;
5031 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5032 return WINED3D_OK;
5035 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5036 IWineD3DDevice *iface,
5037 UINT start,
5038 CONST float *srcData,
5039 UINT count) {
5041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5042 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5044 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5045 iface, srcData, start, count);
5047 if (srcData == NULL || cnt < 0)
5048 return WINED3DERR_INVALIDCALL;
5050 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5051 for (i = 0; i < cnt; i++)
5052 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5053 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5055 for (i = start; i < cnt + start; ++i) {
5056 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5057 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5058 ptr->idx = i;
5059 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5060 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5062 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5065 return WINED3D_OK;
5068 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5069 IWineD3DDevice *iface,
5070 UINT start,
5071 float *dstData,
5072 UINT count) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5075 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5077 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5078 iface, dstData, start, count);
5080 if (dstData == NULL || cnt < 0)
5081 return WINED3DERR_INVALIDCALL;
5083 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5084 return WINED3D_OK;
5087 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5088 static HRESULT
5089 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5090 char *dest_ptr, *dest_conv = NULL;
5091 unsigned int i;
5092 DWORD DestFVF = dest->fvf;
5093 WINED3DVIEWPORT vp;
5094 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
5095 BOOL doClip;
5096 int numTextures;
5098 if (SrcFVF & WINED3DFVF_NORMAL) {
5099 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5102 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
5103 ERR("Source has no position mask\n");
5104 return WINED3DERR_INVALIDCALL;
5107 /* We might access VBOs from this code, so hold the lock */
5108 ENTER_GL();
5110 if (dest->resource.allocatedMemory == NULL) {
5111 /* This may happen if we do direct locking into a vbo. Unlikely,
5112 * but theoretically possible(ddraw processvertices test)
5114 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5115 if(!dest->resource.allocatedMemory) {
5116 LEAVE_GL();
5117 ERR("Out of memory\n");
5118 return E_OUTOFMEMORY;
5120 if(dest->vbo) {
5121 void *src;
5122 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5123 checkGLcall("glBindBufferARB");
5124 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5125 if(src) {
5126 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5128 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5129 checkGLcall("glUnmapBufferARB");
5133 /* Get a pointer into the destination vbo(create one if none exists) and
5134 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5136 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5137 CreateVBO(dest);
5140 if(dest->vbo) {
5141 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5142 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5143 if(!dest_conv) {
5144 ERR("glMapBuffer failed\n");
5145 /* Continue without storing converted vertices */
5149 /* Should I clip?
5150 * a) WINED3DRS_CLIPPING is enabled
5151 * b) WINED3DVOP_CLIP is passed
5153 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5154 static BOOL warned = FALSE;
5156 * The clipping code is not quite correct. Some things need
5157 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5158 * so disable clipping for now.
5159 * (The graphics in Half-Life are broken, and my processvertices
5160 * test crashes with IDirect3DDevice3)
5161 doClip = TRUE;
5163 doClip = FALSE;
5164 if(!warned) {
5165 warned = TRUE;
5166 FIXME("Clipping is broken and disabled for now\n");
5168 } else doClip = FALSE;
5169 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5170 if(dest_conv) {
5171 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5174 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5175 WINED3DTS_VIEW,
5176 &view_mat);
5177 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5178 WINED3DTS_PROJECTION,
5179 &proj_mat);
5180 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5181 WINED3DTS_WORLDMATRIX(0),
5182 &world_mat);
5184 TRACE("View mat:\n");
5185 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); \
5186 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); \
5187 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); \
5188 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); \
5190 TRACE("Proj mat:\n");
5191 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); \
5192 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); \
5193 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); \
5194 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); \
5196 TRACE("World mat:\n");
5197 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); \
5198 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); \
5199 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); \
5200 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); \
5202 /* Get the viewport */
5203 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5204 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
5205 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5207 multiply_matrix(&mat,&view_mat,&world_mat);
5208 multiply_matrix(&mat,&proj_mat,&mat);
5210 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
5212 for (i = 0; i < dwCount; i+= 1) {
5213 unsigned int tex_index;
5215 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
5216 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
5217 /* The position first */
5218 float *p =
5219 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5220 float x, y, z, rhw;
5221 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5223 /* Multiplication with world, view and projection matrix */
5224 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);
5225 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);
5226 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);
5227 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);
5229 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5231 /* WARNING: The following things are taken from d3d7 and were not yet checked
5232 * against d3d8 or d3d9!
5235 /* Clipping conditions: From
5236 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5238 * A vertex is clipped if it does not match the following requirements
5239 * -rhw < x <= rhw
5240 * -rhw < y <= rhw
5241 * 0 < z <= rhw
5242 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5244 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5245 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5249 if( !doClip ||
5250 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5251 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5252 ( rhw > eps ) ) ) {
5254 /* "Normal" viewport transformation (not clipped)
5255 * 1) The values are divided by rhw
5256 * 2) The y axis is negative, so multiply it with -1
5257 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5258 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5259 * 4) Multiply x with Width/2 and add Width/2
5260 * 5) The same for the height
5261 * 6) Add the viewpoint X and Y to the 2D coordinates and
5262 * The minimum Z value to z
5263 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5265 * Well, basically it's simply a linear transformation into viewport
5266 * coordinates
5269 x /= rhw;
5270 y /= rhw;
5271 z /= rhw;
5273 y *= -1;
5275 x *= vp.Width / 2;
5276 y *= vp.Height / 2;
5277 z *= vp.MaxZ - vp.MinZ;
5279 x += vp.Width / 2 + vp.X;
5280 y += vp.Height / 2 + vp.Y;
5281 z += vp.MinZ;
5283 rhw = 1 / rhw;
5284 } else {
5285 /* That vertex got clipped
5286 * Contrary to OpenGL it is not dropped completely, it just
5287 * undergoes a different calculation.
5289 TRACE("Vertex got clipped\n");
5290 x += rhw;
5291 y += rhw;
5293 x /= 2;
5294 y /= 2;
5296 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5297 * outside of the main vertex buffer memory. That needs some more
5298 * investigation...
5302 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5305 ( (float *) dest_ptr)[0] = x;
5306 ( (float *) dest_ptr)[1] = y;
5307 ( (float *) dest_ptr)[2] = z;
5308 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5310 dest_ptr += 3 * sizeof(float);
5312 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5313 dest_ptr += sizeof(float);
5316 if(dest_conv) {
5317 float w = 1 / rhw;
5318 ( (float *) dest_conv)[0] = x * w;
5319 ( (float *) dest_conv)[1] = y * w;
5320 ( (float *) dest_conv)[2] = z * w;
5321 ( (float *) dest_conv)[3] = w;
5323 dest_conv += 3 * sizeof(float);
5325 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5326 dest_conv += sizeof(float);
5330 if (DestFVF & WINED3DFVF_PSIZE) {
5331 dest_ptr += sizeof(DWORD);
5332 if(dest_conv) dest_conv += sizeof(DWORD);
5334 if (DestFVF & WINED3DFVF_NORMAL) {
5335 float *normal =
5336 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5337 /* AFAIK this should go into the lighting information */
5338 FIXME("Didn't expect the destination to have a normal\n");
5339 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5340 if(dest_conv) {
5341 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5345 if (DestFVF & WINED3DFVF_DIFFUSE) {
5346 DWORD *color_d =
5347 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5348 if(!color_d) {
5349 static BOOL warned = FALSE;
5351 if(!warned) {
5352 ERR("No diffuse color in source, but destination has one\n");
5353 warned = TRUE;
5356 *( (DWORD *) dest_ptr) = 0xffffffff;
5357 dest_ptr += sizeof(DWORD);
5359 if(dest_conv) {
5360 *( (DWORD *) dest_conv) = 0xffffffff;
5361 dest_conv += sizeof(DWORD);
5364 else {
5365 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5366 if(dest_conv) {
5367 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5368 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5369 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5370 dest_conv += sizeof(DWORD);
5375 if (DestFVF & WINED3DFVF_SPECULAR) {
5376 /* What's the color value in the feedback buffer? */
5377 DWORD *color_s =
5378 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5379 if(!color_s) {
5380 static BOOL warned = FALSE;
5382 if(!warned) {
5383 ERR("No specular color in source, but destination has one\n");
5384 warned = TRUE;
5387 *( (DWORD *) dest_ptr) = 0xFF000000;
5388 dest_ptr += sizeof(DWORD);
5390 if(dest_conv) {
5391 *( (DWORD *) dest_conv) = 0xFF000000;
5392 dest_conv += sizeof(DWORD);
5395 else {
5396 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5397 if(dest_conv) {
5398 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5399 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5400 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5401 dest_conv += sizeof(DWORD);
5406 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5407 float *tex_coord =
5408 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5409 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5410 if(!tex_coord) {
5411 ERR("No source texture, but destination requests one\n");
5412 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5413 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5415 else {
5416 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5417 if(dest_conv) {
5418 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5424 if(dest_conv) {
5425 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5426 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5429 LEAVE_GL();
5431 return WINED3D_OK;
5433 #undef copy_and_next
5435 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5437 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5438 WineDirect3DVertexStridedData strided;
5439 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5441 if (!SrcImpl) {
5442 WARN("NULL source vertex buffer\n");
5443 return WINED3DERR_INVALIDCALL;
5445 /* We don't need the source vbo because this buffer is only used as
5446 * a source for ProcessVertices. Avoid wasting resources by converting the
5447 * buffer and loading the VBO
5449 if(SrcImpl->vbo) {
5450 TRACE("Releasing the source vbo, it won't be needed\n");
5452 if(!SrcImpl->resource.allocatedMemory) {
5453 /* Rescue the data from the buffer */
5454 void *src;
5455 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5456 if(!SrcImpl->resource.allocatedMemory) {
5457 ERR("Out of memory\n");
5458 return E_OUTOFMEMORY;
5461 ENTER_GL();
5462 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5463 checkGLcall("glBindBufferARB");
5465 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5466 if(src) {
5467 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5470 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5471 checkGLcall("glUnmapBufferARB");
5472 } else {
5473 ENTER_GL();
5476 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5477 checkGLcall("glBindBufferARB");
5478 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5479 checkGLcall("glDeleteBuffersARB");
5480 LEAVE_GL();
5482 SrcImpl->vbo = 0;
5485 memset(&strided, 0, sizeof(strided));
5486 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5488 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5491 /*****
5492 * Apply / Get / Set Texture Stage States
5493 * TODO: Verify against dx9 definitions
5494 *****/
5496 /* 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 */
5497 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5499 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5500 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5502 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5504 /* Check that the stage is within limits */
5505 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5506 TRACE("Attempt to access invalid texture rejected\n");
5507 return;
5510 ENTER_GL();
5512 switch (Type) {
5513 case WINED3DTSS_ALPHAOP :
5514 case WINED3DTSS_COLOROP :
5515 /* nothing to do as moved to drawprim for now */
5516 break;
5517 case WINED3DTSS_ADDRESSW :
5518 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5519 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5520 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
5522 } else {
5523 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5524 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5525 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5526 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5528 #endif
5529 case WINED3DTSS_TEXCOORDINDEX :
5531 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5533 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5534 one flag, you can still specify an index value, which the system uses to
5535 determine the texture wrapping mode.
5536 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5537 means use the vertex position (camera-space) as the input texture coordinates
5538 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5539 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
5540 to the TEXCOORDINDEX value */
5543 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5545 switch (Value & 0xFFFF0000) {
5546 case WINED3DTSS_TCI_PASSTHRU:
5547 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5548 glDisable(GL_TEXTURE_GEN_S);
5549 glDisable(GL_TEXTURE_GEN_T);
5550 glDisable(GL_TEXTURE_GEN_R);
5551 glDisable(GL_TEXTURE_GEN_Q);
5552 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5553 break;
5555 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
5556 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5557 as the input texture coordinates for this stage's texture transformation. This
5558 equates roughly to EYE_LINEAR */
5560 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5561 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5562 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5563 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5564 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5566 glMatrixMode(GL_MODELVIEW);
5567 glPushMatrix();
5568 glLoadIdentity();
5569 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5570 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5571 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5572 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5573 glPopMatrix();
5575 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5576 glEnable(GL_TEXTURE_GEN_S);
5577 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5578 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5579 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5580 glEnable(GL_TEXTURE_GEN_T);
5581 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5582 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5583 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5584 glEnable(GL_TEXTURE_GEN_R);
5585 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5586 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5587 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5589 break;
5591 case WINED3DTSS_TCI_CAMERASPACENORMAL:
5593 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5594 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5595 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5596 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5597 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5598 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5600 glMatrixMode(GL_MODELVIEW);
5601 glPushMatrix();
5602 glLoadIdentity();
5603 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5604 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5605 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5606 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5607 glPopMatrix();
5609 glEnable(GL_TEXTURE_GEN_S);
5610 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5611 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5612 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5613 glEnable(GL_TEXTURE_GEN_T);
5614 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5615 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5616 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5617 glEnable(GL_TEXTURE_GEN_R);
5618 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5619 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5620 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5623 break;
5625 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5627 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5628 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5629 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5630 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5631 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5632 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5634 glMatrixMode(GL_MODELVIEW);
5635 glPushMatrix();
5636 glLoadIdentity();
5637 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5638 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5639 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5640 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5641 glPopMatrix();
5643 glEnable(GL_TEXTURE_GEN_S);
5644 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5645 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5646 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5647 glEnable(GL_TEXTURE_GEN_T);
5648 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5649 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5650 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5651 glEnable(GL_TEXTURE_GEN_R);
5652 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5653 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5654 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5657 break;
5659 /* Unhandled types: */
5660 default:
5661 /* Todo: */
5662 /* ? disable GL_TEXTURE_GEN_n ? */
5663 glDisable(GL_TEXTURE_GEN_S);
5664 glDisable(GL_TEXTURE_GEN_T);
5665 glDisable(GL_TEXTURE_GEN_R);
5666 glDisable(GL_TEXTURE_GEN_Q);
5667 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
5668 break;
5671 break;
5673 /* Unhandled */
5674 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5675 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);
5676 break;
5678 case WINED3DTSS_BUMPENVMAT00 :
5679 case WINED3DTSS_BUMPENVMAT01 :
5680 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5681 break;
5682 case WINED3DTSS_BUMPENVMAT10 :
5683 case WINED3DTSS_BUMPENVMAT11 :
5684 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5685 break;
5687 case WINED3DTSS_BUMPENVLSCALE :
5688 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5689 break;
5691 case WINED3DTSS_BUMPENVLOFFSET :
5692 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5693 break;
5695 case WINED3DTSS_RESULTARG :
5696 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5697 break;
5699 default:
5700 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
5701 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5704 LEAVE_GL();
5706 return;
5709 /*****
5710 * Get / Set Texture Stage States
5711 * TODO: Verify against dx9 definitions
5712 *****/
5713 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5718 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5720 /* Reject invalid texture units */
5721 if (Stage >= GL_LIMITS(texture_stages)) {
5722 TRACE("Attempt to access invalid texture rejected\n");
5723 return WINED3DERR_INVALIDCALL;
5726 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5727 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5728 This->updateStateBlock->textureState[Stage][Type] = Value;
5730 return WINED3D_OK;
5733 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5735 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5736 *pValue = This->updateStateBlock->textureState[Stage][Type];
5737 return WINED3D_OK;
5740 /*****
5741 * Get / Set Texture
5742 *****/
5743 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5746 IWineD3DBaseTexture *oldTexture;
5748 oldTexture = This->updateStateBlock->textures[Stage];
5749 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
5751 #if 0 /* TODO: check so vertex textures */
5752 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5753 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5754 return WINED3D_OK;
5756 #endif
5758 /* Reject invalid texture units */
5759 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5760 WARN("Attempt to access invalid texture rejected\n");
5761 return WINED3DERR_INVALIDCALL;
5764 if(pTexture != NULL) {
5765 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5767 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5768 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5769 return WINED3DERR_INVALIDCALL;
5773 oldTexture = This->updateStateBlock->textures[Stage];
5774 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5775 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5777 This->updateStateBlock->set.textures[Stage] = TRUE;
5778 This->updateStateBlock->changed.textures[Stage] = TRUE;
5779 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5780 This->updateStateBlock->textures[Stage] = pTexture;
5782 /* Handle recording of state blocks */
5783 if (This->isRecordingState) {
5784 TRACE("Recording... not performing anything\n");
5785 return WINED3D_OK;
5788 /** NOTE: MSDN says that setTexture increases the reference count,
5789 * and the the application nust set the texture back to null (or have a leaky application),
5790 * This means we should pass the refcount up to the parent
5791 *******************************/
5792 if (NULL != This->updateStateBlock->textures[Stage]) {
5793 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5796 if (NULL != oldTexture) {
5797 IWineD3DBaseTexture_Release(oldTexture);
5800 /* Reset color keying */
5801 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5802 BOOL enable_ckey = FALSE;
5804 if(pTexture) {
5805 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5806 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5809 if(enable_ckey) {
5810 glAlphaFunc(GL_NOTEQUAL, 0.0);
5811 checkGLcall("glAlphaFunc");
5815 return WINED3D_OK;
5818 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5820 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5822 /* Reject invalid texture units */
5823 if (Stage >= GL_LIMITS(sampler_stages)) {
5824 TRACE("Attempt to access invalid texture rejected\n");
5825 return WINED3DERR_INVALIDCALL;
5827 *ppTexture=This->stateBlock->textures[Stage];
5829 return WINED3D_OK;
5832 /*****
5833 * Get Back Buffer
5834 *****/
5835 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5836 IWineD3DSurface **ppBackBuffer) {
5837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5838 IWineD3DSwapChain *swapChain;
5839 HRESULT hr;
5841 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5843 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5844 if (hr == WINED3D_OK) {
5845 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5846 } else {
5847 *ppBackBuffer = NULL;
5849 return hr;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 WARN("(%p) : stub, calling idirect3d for now\n", This);
5855 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5858 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5860 IWineD3DSwapChain *swapChain;
5861 HRESULT hr;
5863 if(iSwapChain > 0) {
5864 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5865 if (hr == WINED3D_OK) {
5866 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5867 } else {
5868 FIXME("(%p) Error getting display mode\n", This);
5870 } else {
5871 /* Don't read the real display mode,
5872 but return the stored mode instead. X11 can't change the color
5873 depth, and some apps are pretty angry if they SetDisplayMode from
5874 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5876 Also don't relay to the swapchain because with ddraw it's possible
5877 that there isn't a swapchain at all */
5878 pMode->Width = This->ddraw_width;
5879 pMode->Height = This->ddraw_height;
5880 pMode->Format = This->ddraw_format;
5881 pMode->RefreshRate = 0;
5882 hr = WINED3D_OK;
5885 return hr;
5888 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5890 TRACE("(%p)->(%p)\n", This, hWnd);
5892 This->ddraw_window = hWnd;
5893 return WINED3D_OK;
5896 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 TRACE("(%p)->(%p)\n", This, hWnd);
5900 *hWnd = This->ddraw_window;
5901 return WINED3D_OK;
5904 /*****
5905 * Stateblock related functions
5906 *****/
5908 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5910 IWineD3DStateBlockImpl *object;
5911 HRESULT temp_result;
5913 TRACE("(%p)\n", This);
5915 if (This->isRecordingState) {
5916 return WINED3DERR_INVALIDCALL;
5919 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5920 if (NULL == object ) {
5921 FIXME("(%p)Error allocating memory for stateblock\n", This);
5922 return E_OUTOFMEMORY;
5924 TRACE("(%p) created object %p\n", This, object);
5925 object->wineD3DDevice= This;
5926 /** FIXME: object->parent = parent; **/
5927 object->parent = NULL;
5928 object->blockType = WINED3DSBT_ALL;
5929 object->ref = 1;
5930 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5932 temp_result = allocate_shader_constants(object);
5933 if (WINED3D_OK != temp_result)
5934 return temp_result;
5936 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5937 This->updateStateBlock = object;
5938 This->isRecordingState = TRUE;
5940 TRACE("(%p) recording stateblock %p\n",This , object);
5941 return WINED3D_OK;
5944 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5947 if (!This->isRecordingState) {
5948 FIXME("(%p) not recording! returning error\n", This);
5949 *ppStateBlock = NULL;
5950 return WINED3DERR_INVALIDCALL;
5953 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5954 This->isRecordingState = FALSE;
5955 This->updateStateBlock = This->stateBlock;
5956 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5957 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5958 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5959 return WINED3D_OK;
5962 /*****
5963 * Scene related functions
5964 *****/
5965 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5966 /* At the moment we have no need for any functionality at the beginning
5967 of a scene */
5968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5969 TRACE("(%p) : stub\n", This);
5970 return WINED3D_OK;
5973 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 TRACE("(%p)\n", This);
5976 ENTER_GL();
5977 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5978 glFlush();
5979 checkGLcall("glFlush");
5981 TRACE("End Scene\n");
5982 /* If we're using FBOs this isn't needed */
5983 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
5985 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5986 IUnknown *targetContainer = NULL;
5987 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5988 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5989 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5990 /** always dirtify for now. we must find a better way to see that surface have been modified
5991 (Modifications should will only occur via draw-primitive, but we do need better locking
5992 switching to render-to-texture should remove the overhead though.
5994 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5995 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5996 IWineD3DSurface_PreLoad(This->renderTarget);
5997 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5998 IUnknown_Release(targetContainer);
6001 This->sceneEnded = TRUE;
6002 LEAVE_GL();
6003 return WINED3D_OK;
6006 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
6007 CONST RECT* pSourceRect, CONST RECT* pDestRect,
6008 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
6009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6010 IWineD3DSwapChain *swapChain = NULL;
6011 int i;
6012 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
6014 TRACE("(%p) Presenting the frame\n", This);
6016 for(i = 0 ; i < swapchains ; i ++) {
6018 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6019 TRACE("presentinng chain %d, %p\n", i, swapChain);
6020 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6023 return WINED3D_OK;
6026 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
6027 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
6028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6030 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
6031 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
6032 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6033 GLbitfield glMask = 0;
6034 GLboolean old_ztest;
6035 GLfloat old_z_clear_value;
6036 GLint old_stencil_clear_value;
6037 GLfloat old_color_clear_value[4];
6038 unsigned int i;
6039 CONST WINED3DRECT* curRect;
6041 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
6042 Count, pRects, Flags, Z, Stencil);
6044 ENTER_GL();
6046 glEnable(GL_SCISSOR_TEST);
6047 checkGLcall("glEnable GL_SCISSOR_TEST");
6049 if (Count > 0 && pRects) {
6050 curRect = pRects;
6051 } else {
6052 curRect = NULL;
6055 /* Only set the values up once, as they are not changing */
6056 if (Flags & WINED3DCLEAR_STENCIL) {
6057 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6058 glClearStencil(Stencil);
6059 checkGLcall("glClearStencil");
6060 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6061 glStencilMask(0xFFFFFFFF);
6064 if (Flags & WINED3DCLEAR_ZBUFFER) {
6065 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6066 glDepthMask(GL_TRUE);
6067 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6068 glClearDepth(Z);
6069 checkGLcall("glClearDepth");
6070 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6073 if (Flags & WINED3DCLEAR_TARGET) {
6074 TRACE("Clearing screen with glClear to color %x\n", Color);
6075 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6076 glClearColor(D3DCOLOR_R(Color),
6077 D3DCOLOR_G(Color),
6078 D3DCOLOR_B(Color),
6079 D3DCOLOR_A(Color));
6080 checkGLcall("glClearColor");
6082 /* Clear ALL colors! */
6083 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6084 glMask = glMask | GL_COLOR_BUFFER_BIT;
6087 /* Now process each rect in turn */
6088 for (i = 0; i < Count || i == 0; i++) {
6090 if (curRect) {
6091 /* Note gl uses lower left, width/height */
6092 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
6093 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6094 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6095 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6096 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6097 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6098 checkGLcall("glScissor");
6099 } else {
6100 glScissor(This->stateBlock->viewport.X,
6101 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6102 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6103 This->stateBlock->viewport.Width,
6104 This->stateBlock->viewport.Height);
6105 checkGLcall("glScissor");
6108 /* Clear the selected rectangle (or full screen) */
6109 glClear(glMask);
6110 checkGLcall("glClear");
6112 /* Step to the next rectangle */
6113 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
6116 /* Restore the old values (why..?) */
6117 if (Flags & WINED3DCLEAR_STENCIL) {
6118 glClearStencil(old_stencil_clear_value);
6119 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6121 if (Flags & WINED3DCLEAR_ZBUFFER) {
6122 glDepthMask(old_ztest);
6123 glClearDepth(old_z_clear_value);
6125 if (Flags & WINED3DCLEAR_TARGET) {
6126 glClearColor(old_color_clear_value[0],
6127 old_color_clear_value[1],
6128 old_color_clear_value[2],
6129 old_color_clear_value[3]);
6130 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6131 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6132 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6133 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6136 glDisable(GL_SCISSOR_TEST);
6137 checkGLcall("glDisable");
6138 LEAVE_GL();
6140 return WINED3D_OK;
6143 /*****
6144 * Drawing functions
6145 *****/
6146 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6147 UINT PrimitiveCount) {
6149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6150 This->stateBlock->streamIsUP = FALSE;
6152 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6153 debug_d3dprimitivetype(PrimitiveType),
6154 StartVertex, PrimitiveCount);
6155 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6156 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6159 return WINED3D_OK;
6162 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6163 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6164 WINED3DPRIMITIVETYPE PrimitiveType,
6165 INT baseVIndex, UINT minIndex,
6166 UINT NumVertices, UINT startIndex, UINT primCount) {
6168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6169 UINT idxStride = 2;
6170 IWineD3DIndexBuffer *pIB;
6171 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6173 pIB = This->stateBlock->pIndexData;
6174 This->stateBlock->streamIsUP = FALSE;
6176 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6177 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6178 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6180 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6181 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6182 idxStride = 2;
6183 } else {
6184 idxStride = 4;
6187 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6188 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6190 return WINED3D_OK;
6193 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6194 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6195 UINT VertexStreamZeroStride) {
6196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6198 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6199 debug_d3dprimitivetype(PrimitiveType),
6200 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6202 /* release the stream source */
6203 if (This->stateBlock->streamSource[0] != NULL) {
6204 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6207 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6208 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6209 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6210 This->stateBlock->streamIsUP = TRUE;
6212 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6213 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6215 /* MSDN specifies stream zero settings must be set to NULL */
6216 This->stateBlock->streamStride[0] = 0;
6217 This->stateBlock->streamSource[0] = NULL;
6219 /*stream zero settings set to null at end, as per the msdn */
6220 return WINED3D_OK;
6223 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6224 UINT MinVertexIndex, UINT NumVertices,
6225 UINT PrimitiveCount, CONST void* pIndexData,
6226 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6227 UINT VertexStreamZeroStride) {
6228 int idxStride;
6229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6231 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6232 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6233 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6234 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6236 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6237 idxStride = 2;
6238 } else {
6239 idxStride = 4;
6242 /* release the stream and index data */
6243 if (This->stateBlock->streamSource[0] != NULL) {
6244 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6246 if (This->stateBlock->pIndexData) {
6247 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6250 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6251 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6252 This->stateBlock->streamIsUP = TRUE;
6253 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6255 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6257 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6258 This->stateBlock->streamSource[0] = NULL;
6259 This->stateBlock->streamStride[0] = 0;
6260 This->stateBlock->pIndexData = NULL;
6262 return WINED3D_OK;
6265 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6267 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6268 return WINED3D_OK;
6270 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6271 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6273 HRESULT hr = WINED3D_OK;
6274 WINED3DRESOURCETYPE sourceType;
6275 WINED3DRESOURCETYPE destinationType;
6276 int i ,levels;
6278 /* TODO: think about moving the code into IWineD3DBaseTexture */
6280 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6282 /* verify that the source and destination textures aren't NULL */
6283 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6284 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6285 This, pSourceTexture, pDestinationTexture);
6286 hr = WINED3DERR_INVALIDCALL;
6289 if (pSourceTexture == pDestinationTexture) {
6290 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6291 This, pSourceTexture, pDestinationTexture);
6292 hr = WINED3DERR_INVALIDCALL;
6294 /* Verify that the source and destination textures are the same type */
6295 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6296 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6298 if (sourceType != destinationType) {
6299 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6300 This);
6301 hr = WINED3DERR_INVALIDCALL;
6304 /* check that both textures have the identical numbers of levels */
6305 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6306 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6307 hr = WINED3DERR_INVALIDCALL;
6310 if (WINED3D_OK == hr) {
6312 /* Make sure that the destination texture is loaded */
6313 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6315 /* Update every surface level of the texture */
6316 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6318 switch (sourceType) {
6319 case WINED3DRTYPE_TEXTURE:
6321 IWineD3DSurface *srcSurface;
6322 IWineD3DSurface *destSurface;
6324 for (i = 0 ; i < levels ; ++i) {
6325 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6326 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6327 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6328 IWineD3DSurface_Release(srcSurface);
6329 IWineD3DSurface_Release(destSurface);
6330 if (WINED3D_OK != hr) {
6331 WARN("(%p) : Call to update surface failed\n", This);
6332 return hr;
6336 break;
6337 case WINED3DRTYPE_CUBETEXTURE:
6339 IWineD3DSurface *srcSurface;
6340 IWineD3DSurface *destSurface;
6341 WINED3DCUBEMAP_FACES faceType;
6343 for (i = 0 ; i < levels ; ++i) {
6344 /* Update each cube face */
6345 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6346 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6347 if (WINED3D_OK != hr) {
6348 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6349 } else {
6350 TRACE("Got srcSurface %p\n", srcSurface);
6352 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6353 if (WINED3D_OK != hr) {
6354 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6355 } else {
6356 TRACE("Got desrSurface %p\n", destSurface);
6358 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6359 IWineD3DSurface_Release(srcSurface);
6360 IWineD3DSurface_Release(destSurface);
6361 if (WINED3D_OK != hr) {
6362 WARN("(%p) : Call to update surface failed\n", This);
6363 return hr;
6368 break;
6369 #if 0 /* TODO: Add support for volume textures */
6370 case WINED3DRTYPE_VOLUMETEXTURE:
6372 IWineD3DVolume srcVolume = NULL;
6373 IWineD3DSurface destVolume = NULL;
6375 for (i = 0 ; i < levels ; ++i) {
6376 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6377 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6378 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6379 IWineD3DVolume_Release(srcSurface);
6380 IWineD3DVolume_Release(destSurface);
6381 if (WINED3D_OK != hr) {
6382 WARN("(%p) : Call to update volume failed\n", This);
6383 return hr;
6387 break;
6388 #endif
6389 default:
6390 FIXME("(%p) : Unsupported source and destination type\n", This);
6391 hr = WINED3DERR_INVALIDCALL;
6395 return hr;
6398 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6399 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6400 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6403 TRACE("(%p) : stub\n", This);
6404 return WINED3D_OK;
6406 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6408 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6409 * NOTE It may be best to move the code into surface to occomplish this
6410 ****************************************/
6412 WINED3DSURFACE_DESC surfaceDesc;
6413 unsigned int surfaceWidth, surfaceHeight;
6414 glDescriptor *targetGlDescription = NULL;
6415 glDescriptor *surfaceGlDescription = NULL;
6416 IWineD3DSwapChainImpl *container = NULL;
6418 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6419 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6420 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6422 surfaceDesc.Width = &surfaceWidth;
6423 surfaceDesc.Height = &surfaceHeight;
6424 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6425 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6427 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6428 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6429 ENTER_GL();
6430 /* TODO: opengl Context switching for swapchains etc... */
6431 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6432 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6433 glReadBuffer(GL_BACK);
6434 vcheckGLcall("glReadBuffer(GL_BACK)");
6435 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6436 glReadBuffer(GL_FRONT);
6437 vcheckGLcall("glReadBuffer(GL_FRONT)");
6438 } else if (pRenderTarget == This->depthStencilBuffer) {
6439 FIXME("Reading of depthstencil not yet supported\n");
6442 glReadPixels(0,
6444 surfaceWidth,
6445 surfaceHeight,
6446 surfaceGlDescription->glFormat,
6447 surfaceGlDescription->glType,
6448 (void *)IWineD3DSurface_GetData(pSurface));
6449 vcheckGLcall("glReadPixels(...)");
6450 if(NULL != container ){
6451 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6453 } else {
6454 IWineD3DBaseTexture *container;
6455 GLenum textureDimensions = GL_TEXTURE_2D;
6457 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6458 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6459 IWineD3DBaseTexture_Release(container);
6461 /* TODO: 2D -> Cube surface coppies etc.. */
6462 if (surfaceGlDescription->target != textureDimensions) {
6463 FIXME("(%p) : Texture dimension mismatch\n", This);
6465 glEnable(textureDimensions);
6466 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6467 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6468 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6469 vcheckGLcall("glBindTexture");
6470 glGetTexImage(surfaceGlDescription->target,
6471 surfaceGlDescription->level,
6472 surfaceGlDescription->glFormat,
6473 surfaceGlDescription->glType,
6474 (void *)IWineD3DSurface_GetData(pSurface));
6475 glDisable(textureDimensions);
6476 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6479 LEAVE_GL();
6480 return WINED3D_OK;
6483 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6484 IWineD3DSwapChain *swapChain;
6485 HRESULT hr;
6486 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6487 if(hr == WINED3D_OK) {
6488 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6490 return hr;
6493 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6495 /* return a sensible default */
6496 *pNumPasses = 1;
6497 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6498 FIXME("(%p) : stub\n", This);
6499 return WINED3D_OK;
6502 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6504 int j;
6505 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6506 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6507 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6508 return WINED3DERR_INVALIDCALL;
6510 for (j = 0; j < 256; ++j) {
6511 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6512 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6513 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6514 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6516 TRACE("(%p) : returning\n", This);
6517 return WINED3D_OK;
6520 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6522 int j;
6523 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6524 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6525 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6526 return WINED3DERR_INVALIDCALL;
6528 for (j = 0; j < 256; ++j) {
6529 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6530 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6531 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6532 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6534 TRACE("(%p) : returning\n", This);
6535 return WINED3D_OK;
6538 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6541 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6542 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6543 return WINED3DERR_INVALIDCALL;
6545 /*TODO: stateblocks */
6546 This->currentPalette = PaletteNumber;
6547 TRACE("(%p) : returning\n", This);
6548 return WINED3D_OK;
6551 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6553 if (PaletteNumber == NULL) {
6554 WARN("(%p) : returning Invalid Call\n", This);
6555 return WINED3DERR_INVALIDCALL;
6557 /*TODO: stateblocks */
6558 *PaletteNumber = This->currentPalette;
6559 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6560 return WINED3D_OK;
6563 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6565 static BOOL showFixmes = TRUE;
6566 if (showFixmes) {
6567 FIXME("(%p) : stub\n", This);
6568 showFixmes = FALSE;
6571 This->softwareVertexProcessing = bSoftware;
6572 return WINED3D_OK;
6576 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6578 static BOOL showFixmes = TRUE;
6579 if (showFixmes) {
6580 FIXME("(%p) : stub\n", This);
6581 showFixmes = FALSE;
6583 return This->softwareVertexProcessing;
6587 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6589 IWineD3DSwapChain *swapChain;
6590 HRESULT hr;
6592 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6594 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6595 if(hr == WINED3D_OK){
6596 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6597 }else{
6598 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6600 return hr;
6604 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6606 static BOOL showfixmes = TRUE;
6607 if(nSegments != 0.0f) {
6608 if( showfixmes) {
6609 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6610 showfixmes = FALSE;
6613 return WINED3D_OK;
6616 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6618 static BOOL showfixmes = TRUE;
6619 if( showfixmes) {
6620 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6621 showfixmes = FALSE;
6623 return 0.0f;
6626 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6628 /** TODO: remove casts to IWineD3DSurfaceImpl
6629 * NOTE: move code to surface to accomplish this
6630 ****************************************/
6631 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6632 int srcWidth, srcHeight;
6633 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6634 WINED3DFORMAT destFormat, srcFormat;
6635 UINT destSize;
6636 int destLeft, destTop;
6637 WINED3DPOOL srcPool, destPool;
6638 int offset = 0;
6639 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6640 glDescriptor *glDescription = NULL;
6641 GLenum textureDimensions = GL_TEXTURE_2D;
6642 IWineD3DBaseTexture *baseTexture;
6644 WINED3DSURFACE_DESC winedesc;
6646 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6647 memset(&winedesc, 0, sizeof(winedesc));
6648 winedesc.Width = &srcSurfaceWidth;
6649 winedesc.Height = &srcSurfaceHeight;
6650 winedesc.Pool = &srcPool;
6651 winedesc.Format = &srcFormat;
6653 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6655 winedesc.Width = &destSurfaceWidth;
6656 winedesc.Height = &destSurfaceHeight;
6657 winedesc.Pool = &destPool;
6658 winedesc.Format = &destFormat;
6659 winedesc.Size = &destSize;
6661 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6663 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6664 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6665 return WINED3DERR_INVALIDCALL;
6668 if (destFormat == WINED3DFMT_UNKNOWN) {
6669 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6670 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6672 /* Get the update surface description */
6673 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6676 /* Make sure the surface is loaded and up to date */
6677 IWineD3DSurface_PreLoad(pDestinationSurface);
6679 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6681 ENTER_GL();
6683 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6684 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6685 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6686 destLeft = pDestPoint ? pDestPoint->x : 0;
6687 destTop = pDestPoint ? pDestPoint->y : 0;
6690 /* This function doesn't support compressed textures
6691 the pitch is just bytesPerPixel * width */
6692 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6693 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6694 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6695 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6697 /* TODO DXT formats */
6699 if(pSourceRect != NULL && pSourceRect->top != 0){
6700 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6702 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6703 ,This
6704 ,glDescription->level
6705 ,destLeft
6706 ,destTop
6707 ,srcWidth
6708 ,srcHeight
6709 ,glDescription->glFormat
6710 ,glDescription->glType
6711 ,IWineD3DSurface_GetData(pSourceSurface)
6714 /* Sanity check */
6715 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6717 /* need to lock the surface to get the data */
6718 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6721 /* TODO: Cube and volume support */
6722 if(rowoffset != 0){
6723 /* not a whole row so we have to do it a line at a time */
6724 int j;
6726 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6727 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6729 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6731 glTexSubImage2D(glDescription->target
6732 ,glDescription->level
6733 ,destLeft
6735 ,srcWidth
6737 ,glDescription->glFormat
6738 ,glDescription->glType
6739 ,data /* could be quicker using */
6741 data += rowoffset;
6744 } else { /* Full width, so just write out the whole texture */
6746 if (WINED3DFMT_DXT1 == destFormat ||
6747 WINED3DFMT_DXT2 == destFormat ||
6748 WINED3DFMT_DXT3 == destFormat ||
6749 WINED3DFMT_DXT4 == destFormat ||
6750 WINED3DFMT_DXT5 == destFormat) {
6751 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6752 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6753 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6754 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6755 } if (destFormat != srcFormat) {
6756 FIXME("Updating mixed format compressed texture is not curretly support\n");
6757 } else {
6758 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6759 glDescription->level,
6760 glDescription->glFormatInternal,
6761 srcWidth,
6762 srcHeight,
6764 destSize,
6765 IWineD3DSurface_GetData(pSourceSurface));
6767 } else {
6768 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6772 } else {
6773 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6775 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6776 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6777 data returned by GetData non-power2 width/height with hardware non-power2
6778 pow2Width/height are set to surface width height, repacking isn't needed so it
6779 doesn't matter which function gets called. */
6780 glTexSubImage2D(glDescription->target
6781 ,glDescription->level
6782 ,destLeft
6783 ,destTop
6784 ,srcWidth
6785 ,srcHeight
6786 ,glDescription->glFormat
6787 ,glDescription->glType
6788 ,IWineD3DSurface_GetData(pSourceSurface)
6790 } else {
6792 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6793 glTexSubImage2D(glDescription->target
6794 ,glDescription->level
6795 ,destLeft
6796 ,destTop
6797 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6798 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6799 ,glDescription->glFormat
6800 ,glDescription->glType
6801 ,IWineD3DSurface_GetData(pSourceSurface)
6807 checkGLcall("glTexSubImage2D");
6808 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6810 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6811 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6812 * surface bigger than it needs to be hmm.. */
6813 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6814 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6815 IWineD3DBaseTexture_Release(baseTexture);
6818 glDisable(textureDimensions); /* This needs to be managed better.... */
6819 LEAVE_GL();
6821 return WINED3D_OK;
6824 /* Implementation details at http://developer.nvidia.com/attach/6494
6826 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6827 hmm.. no longer supported use
6828 OpenGL evaluators or tessellate surfaces within your application.
6831 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6832 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6834 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6835 FIXME("(%p) : Stub\n", This);
6836 return WINED3D_OK;
6840 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6841 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6843 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6844 FIXME("(%p) : Stub\n", This);
6845 return WINED3D_OK;
6848 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6850 TRACE("(%p) Handle(%d)\n", This, Handle);
6851 FIXME("(%p) : Stub\n", This);
6852 return WINED3D_OK;
6855 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6857 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6858 DDBLTFX BltFx;
6859 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
6861 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6862 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6863 return WINED3DERR_INVALIDCALL;
6866 /* Just forward this to the DirectDraw blitting engine */
6867 memset(&BltFx, 0, sizeof(BltFx));
6868 BltFx.dwSize = sizeof(BltFx);
6869 BltFx.u5.dwFillColor = color;
6870 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6873 /* rendertarget and deptth stencil functions */
6874 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6877 /* FIXME: Implelent RenderTargetIndex >0 */
6878 if(RenderTargetIndex > 0)
6879 FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
6881 *ppRenderTarget = This->renderTarget;
6882 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6884 return WINED3D_OK;
6887 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6889 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6890 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6891 IWineD3DSwapChainImpl *Swapchain;
6892 HRESULT hr;
6894 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6896 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6897 if(hr != WINED3D_OK) {
6898 ERR("Can't get the swapchain\n");
6899 return hr;
6902 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6903 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6904 return WINED3DERR_INVALIDCALL;
6906 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6907 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6908 return WINED3DERR_INVALIDCALL;
6911 if(Swapchain->frontBuffer != Front) {
6912 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6914 if(Swapchain->frontBuffer)
6915 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6916 Swapchain->frontBuffer = Front;
6918 if(Swapchain->frontBuffer) {
6919 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6923 if(Back && !Swapchain->backBuffer) {
6924 /* We need memory for the back buffer array - only one back buffer this way */
6925 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6926 if(!Swapchain->backBuffer) {
6927 ERR("Out of memory\n");
6928 return E_OUTOFMEMORY;
6932 if(Swapchain->backBuffer[0] != Back) {
6933 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6934 ENTER_GL();
6935 if(!Swapchain->backBuffer[0]) {
6936 /* GL was told to draw to the front buffer at creation,
6937 * undo that
6939 glDrawBuffer(GL_BACK);
6940 checkGLcall("glDrawBuffer(GL_BACK)");
6941 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6942 Swapchain->presentParms.BackBufferCount = 1;
6943 } else if (!Back) {
6944 /* That makes problems - disable for now */
6945 /* glDrawBuffer(GL_FRONT); */
6946 checkGLcall("glDrawBuffer(GL_FRONT)");
6947 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6948 Swapchain->presentParms.BackBufferCount = 0;
6950 LEAVE_GL();
6952 if(Swapchain->backBuffer[0])
6953 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6954 Swapchain->backBuffer[0] = Back;
6956 if(Swapchain->backBuffer[0]) {
6957 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6958 } else {
6959 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6964 return WINED3D_OK;
6967 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6969 *ppZStencilSurface = This->depthStencilBuffer;
6970 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6972 return WINED3D_OK;
6975 static void bind_fbo(IWineD3DDevice *iface) {
6976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6978 if (!This->fbo) {
6979 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
6980 checkGLcall("glGenFramebuffersEXT()");
6982 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
6983 checkGLcall("glBindFramebuffer()");
6986 /* TODO: Handle stencil attachments */
6987 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6989 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6991 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6993 bind_fbo(iface);
6995 if (depth_stencil_impl) {
6996 GLenum texttarget, target;
6998 IWineD3DSurface_PreLoad(depth_stencil);
6999 texttarget = depth_stencil_impl->glDescription.target;
7000 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7002 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
7003 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
7004 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
7005 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
7006 glBindTexture(target, 0);
7008 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
7009 checkGLcall("glFramebufferTexture2DEXT()");
7010 } else {
7011 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
7012 checkGLcall("glFramebufferTexture2DEXT()");
7015 if (!This->render_offscreen) {
7016 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7017 checkGLcall("glBindFramebuffer()");
7021 static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
7022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7023 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
7025 if (This->render_offscreen) {
7026 GLenum texttarget, target;
7028 bind_fbo(iface);
7030 IWineD3DSurface_PreLoad(render_target);
7031 texttarget = rtimpl->glDescription.target;
7032 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7034 glBindTexture(target, rtimpl->glDescription.textureName);
7035 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
7036 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
7037 glBindTexture(target, 0);
7039 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texttarget, rtimpl->glDescription.textureName, 0));
7040 checkGLcall("glFramebufferTexture2DEXT()");
7041 } else {
7042 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7043 checkGLcall("glBindFramebuffer()");
7047 /* internal static helper functions */
7048 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7049 IWineD3DSurface *RenderSurface);
7051 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7053 HRESULT hr = WINED3D_OK;
7054 WINED3DVIEWPORT viewport;
7056 TRACE("(%p) Swapping rendertarget\n",This);
7057 if (RenderTargetIndex > 0) {
7058 FIXME("(%p) Render targets other than the first are not supported\n",This);
7059 RenderTargetIndex = 0;
7062 /* MSDN says that null disables the render target
7063 but a device must always be associated with a render target
7064 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7066 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7067 for more details
7069 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7070 FIXME("Trying to set render target 0 to NULL\n");
7071 return WINED3DERR_INVALIDCALL;
7073 /* TODO: replace Impl* usage with interface usage */
7074 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7075 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);
7076 return WINED3DERR_INVALIDCALL;
7078 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7079 * builds, but I think wine counts as a 'debug' build for now.
7080 ******************************/
7081 /* If we are trying to set what we already have, don't bother */
7082 if (pRenderTarget == This->renderTarget) {
7083 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7084 } else {
7085 /* Otherwise, set the render target up */
7087 if (!This->sceneEnded) {
7088 IWineD3DDevice_EndScene(iface);
7090 TRACE("clearing renderer\n");
7091 /* IWineD3DDeviceImpl_CleanRender(iface); */
7092 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7093 depending on the renter target implementation being used.
7094 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7095 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7096 stencil buffer and incure an extra memory overhead */
7097 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7098 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7099 set_render_target_fbo(iface, pRenderTarget);
7103 if (SUCCEEDED(hr)) {
7104 /* Finally, reset the viewport as the MSDN states. */
7105 /* TODO: Replace impl usage */
7106 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7107 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7108 viewport.X = 0;
7109 viewport.Y = 0;
7110 viewport.MaxZ = 1.0f;
7111 viewport.MinZ = 0.0f;
7112 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7113 } else {
7114 FIXME("Unknown error setting the render target\n");
7116 This->sceneEnded = FALSE;
7117 return hr;
7120 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7122 HRESULT hr = WINED3D_OK;
7123 IWineD3DSurface *tmp;
7125 TRACE("(%p) Swapping z-buffer\n",This);
7127 if (pNewZStencil == This->stencilBufferTarget) {
7128 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7129 } else {
7130 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7131 * depending on the renter target implementation being used.
7132 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7133 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7134 * stencil buffer and incure an extra memory overhead
7135 ******************************************************/
7138 tmp = This->stencilBufferTarget;
7139 This->stencilBufferTarget = pNewZStencil;
7140 /* should we be calling the parent or the wined3d surface? */
7141 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7142 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7143 hr = WINED3D_OK;
7144 /** TODO: glEnable/glDisable on depth/stencil depending on
7145 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7146 **********************************************************/
7147 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7148 set_depth_stencil_fbo(iface, pNewZStencil);
7152 return hr;
7156 #ifdef GL_VERSION_1_3
7157 /* Internal functions not in DirectX */
7158 /** TODO: move this off to the opengl context manager
7159 *(the swapchain doesn't need to know anything about offscreen rendering!)
7160 ****************************************************/
7162 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7166 TRACE("(%p), %p\n", This, swapchain);
7168 if (swapchain->win != swapchain->drawable) {
7169 /* Set everything back the way it ws */
7170 swapchain->render_ctx = swapchain->glCtx;
7171 swapchain->drawable = swapchain->win;
7173 return WINED3D_OK;
7176 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7177 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7179 int i;
7180 unsigned int width;
7181 unsigned int height;
7182 WINED3DFORMAT format;
7183 WINED3DSURFACE_DESC surfaceDesc;
7184 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7185 surfaceDesc.Width = &width;
7186 surfaceDesc.Height = &height;
7187 surfaceDesc.Format = &format;
7188 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7189 *context = NULL;
7190 /* I need a get width/height function (and should do something with the format) */
7191 for (i = 0; i < CONTEXT_CACHE; ++i) {
7192 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7193 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7194 the pSurface can be set to 0 allowing it to be reused from cache **/
7195 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7196 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7197 *context = &This->contextCache[i];
7198 break;
7200 if (This->contextCache[i].Width == 0) {
7201 This->contextCache[i].pSurface = pSurface;
7202 This->contextCache[i].Width = width;
7203 This->contextCache[i].Height = height;
7204 *context = &This->contextCache[i];
7205 break;
7208 if (i == CONTEXT_CACHE) {
7209 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7210 glContext *dropContext = 0;
7211 for (i = 0; i < CONTEXT_CACHE; i++) {
7212 if (This->contextCache[i].usedcount < minUsage) {
7213 dropContext = &This->contextCache[i];
7214 minUsage = This->contextCache[i].usedcount;
7217 /* clean up the context (this doesn't work for ATI at the moment */
7218 #if 0
7219 glXDestroyContext(swapchain->display, dropContext->context);
7220 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7221 #endif
7222 FIXME("Leak\n");
7223 dropContext->Width = 0;
7224 dropContext->pSurface = pSurface;
7225 *context = dropContext;
7226 } else {
7227 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7228 for (i = 0; i < CONTEXT_CACHE; i++) {
7229 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7233 if (*context != NULL)
7234 return WINED3D_OK;
7235 else
7236 return E_OUTOFMEMORY;
7238 #endif
7240 /* Reapply the device stateblock */
7241 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7243 BOOL oldRecording;
7244 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7246 /* Disable recording */
7247 oldUpdateStateBlock = This->updateStateBlock;
7248 oldRecording= This->isRecordingState;
7249 This->isRecordingState = FALSE;
7250 This->updateStateBlock = This->stateBlock;
7252 /* Reapply the state block */
7253 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7255 /* Restore recording */
7256 This->isRecordingState = oldRecording;
7257 This->updateStateBlock = oldUpdateStateBlock;
7260 /* Set offscreen rendering. When rendering offscreen the surface will be
7261 * rendered upside down to compensate for the fact that D3D texture coordinates
7262 * are flipped compared to GL texture coordinates. The cullmode is affected by
7263 * this, so it must be updated. To update the cullmode stateblock recording has
7264 * to be temporarily disabled. The new state management code will hopefully
7265 * make this unnecessary */
7266 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7268 DWORD cullMode;
7269 BOOL oldRecording;
7270 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7272 /* Nothing to update, return. */
7273 if (This->render_offscreen == isTexture) return;
7275 /* Disable recording */
7276 oldUpdateStateBlock = This->updateStateBlock;
7277 oldRecording= This->isRecordingState;
7278 This->isRecordingState = FALSE;
7279 This->updateStateBlock = This->stateBlock;
7281 This->render_offscreen = isTexture;
7282 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
7283 This->depth_copy_state = WINED3D_DCS_COPY;
7285 This->last_was_rhw = FALSE;
7286 This->proj_valid = FALSE;
7287 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7288 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7290 /* Restore recording */
7291 This->isRecordingState = oldRecording;
7292 This->updateStateBlock = oldUpdateStateBlock;
7295 /* Returns an array of compatible FBconfig(s).
7296 * The array must be freed with XFree. Requires ENTER_GL() */
7298 static GLXFBConfig* device_find_fbconfigs(
7299 IWineD3DDeviceImpl* This,
7300 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7301 IWineD3DSurface* RenderSurface) {
7303 GLXFBConfig* cfgs = NULL;
7304 int nCfgs = 0;
7305 int attribs[256];
7306 int nAttribs = 0;
7308 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7309 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7310 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7312 /**TODO:
7313 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7314 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7317 #define PUSH1(att) attribs[nAttribs++] = (att);
7318 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7320 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7322 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7323 PUSH2(GLX_X_RENDERABLE, TRUE);
7324 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7325 TRACE("calling makeglcfg\n");
7326 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7327 PUSH1(None);
7328 TRACE("calling chooseFGConfig\n");
7329 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7330 DefaultScreen(implicitSwapchainImpl->display),
7331 attribs, &nCfgs);
7332 if (cfgs == NULL) {
7333 /* OK we didn't find the exact config, so use any reasonable match */
7334 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
7335 why we failed. */
7336 static BOOL show_message = TRUE;
7337 if (show_message) {
7338 ERR("Failed to find exact match, finding alternative but you may "
7339 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7340 show_message = FALSE;
7342 nAttribs = 0;
7343 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7344 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7345 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7346 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7347 TRACE("calling makeglcfg\n");
7348 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7349 PUSH1(None);
7350 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7351 DefaultScreen(implicitSwapchainImpl->display),
7352 attribs, &nCfgs);
7355 if (cfgs == NULL) {
7356 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7357 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7358 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7359 } else {
7360 #ifdef EXTRA_TRACES
7361 int i;
7362 for (i = 0; i < nCfgs; ++i) {
7363 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7364 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7365 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7367 if (NULL != This->renderTarget) {
7368 glFlush();
7369 vcheckGLcall("glFlush");
7370 /** This is only useful if the old render target was a swapchain,
7371 * we need to supercede this with a function that displays
7372 * the current buffer on the screen. This is easy to do in glx1.3 but
7373 * we need to do copy-write pixels in glx 1.2.
7374 ************************************************/
7375 glXSwapBuffers(implicitSwapChainImpl->display,
7376 implicitSwapChainImpl->drawable);
7377 printf("Hit Enter to get next frame ...\n");
7378 getchar();
7380 #endif
7382 #undef PUSH1
7383 #undef PUSH2
7385 return cfgs;
7388 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7389 * the functionality needs splitting up so that we don't do more than we should do.
7390 * this only seems to impact performance a little.
7391 ******************************/
7392 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7393 IWineD3DSurface *RenderSurface) {
7396 * Currently only active for GLX >= 1.3
7397 * for others versions we'll have to use GLXPixmaps
7399 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7400 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7401 * so only check OpenGL version
7402 * ..........................
7403 * I don't believe that it is a problem with NVidia headers,
7404 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7405 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7406 * ATI Note:
7407 * Your application will report GLX version 1.2 on glXQueryVersion.
7408 * However, it is safe to call the GLX 1.3 functions as described below.
7410 #if defined(GL_VERSION_1_3)
7412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7413 GLXFBConfig* cfgs = NULL;
7414 IWineD3DSwapChain *currentSwapchain;
7415 IWineD3DSwapChainImpl *currentSwapchainImpl;
7416 IWineD3DSwapChain *implicitSwapchain;
7417 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7418 IWineD3DSwapChain *renderSurfaceSwapchain;
7419 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7421 /* Obtain a reference to the device implicit swapchain,
7422 * the swapchain of the current render target,
7423 * and the swapchain of the new render target.
7424 * Fallback to device implicit swapchain if the current render target doesn't have one */
7425 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7426 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7427 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7428 if (currentSwapchain == NULL) {
7429 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7430 /* GetContainer currently AddRefs, but GetSwapChain doesn't.
7431 * Like this the release code for both is the same. */
7432 IWineD3DDevice_AddRef(currentSwapchain);
7435 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7436 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7437 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7439 ENTER_GL();
7442 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7443 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7444 **********************************************************************/
7445 if (renderSurfaceSwapchain != NULL) {
7447 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7448 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
7449 TRACE("making swapchain active\n");
7450 if (RenderSurface != This->renderTarget) {
7451 BOOL backbuf = FALSE;
7452 int i;
7454 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7455 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7456 backbuf = TRUE;
7457 break;
7461 if (backbuf) {
7462 } else {
7463 /* This could be flagged so that some operations work directly with the front buffer */
7464 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7466 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7467 renderSurfaceSwapchainImpl->win,
7468 renderSurfaceSwapchainImpl->glCtx) == False) {
7470 TRACE("Error in setting current context: context %p drawable %ld !\n",
7471 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7473 checkGLcall("glXMakeContextCurrent");
7475 /* Clean up the old context */
7476 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7478 /* Reapply the stateblock, and set the device not to render to texture */
7479 device_reapply_stateblock(This);
7480 device_render_to_texture(This, FALSE);
7483 /* Offscreen rendering: PBuffers (currently disabled).
7484 * Also note that this path is never reached if FBOs are supported */
7485 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
7486 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7488 /** ********************************************************************
7489 * This is a quickly hacked out implementation of offscreen textures.
7490 * It will work in most cases but there may be problems if the client
7491 * modifies the texture directly, or expects the contents of the rendertarget
7492 * to be persistent.
7494 * There are some real speed vs compatibility issues here:
7495 * we should really use a new context for every texture, but that eats ram.
7496 * we should also be restoring the texture to the pbuffer but that eats CPU
7497 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7498 * but if this means reusing the display backbuffer then we need to make sure that
7499 * states are correctly preserved.
7500 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7501 * and gain a good performance increase at the cost of compatibility.
7502 * I would suggest that, when this is the case, a user configurable flag be made
7503 * available, allowing the user to choose the best emulated experience for them.
7504 *********************************************************************/
7506 XVisualInfo *visinfo;
7507 glContext *newContext;
7509 /* Here were using a shared context model */
7510 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7511 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7514 /* If the context doesn't exist then create a new one */
7515 /* TODO: This should really be part of findGlContext */
7516 if (NULL == newContext->context) {
7518 int attribs[256];
7519 int nAttribs = 0;
7521 TRACE("making new buffer\n");
7522 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7523 attribs[nAttribs++] = newContext->Width;
7524 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7525 attribs[nAttribs++] = newContext->Height;
7526 attribs[nAttribs++] = None;
7528 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7530 /** ****************************************
7531 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7532 *they note:
7533 * In future releases, we may provide the calls glXCreateNewContext,
7534 * glXQueryDrawable and glXMakeContextCurrent.
7535 * so until then we have to use glXGetVisualFromFBConfig &co..
7536 ********************************************/
7538 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7539 if (!visinfo) {
7540 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7541 } else {
7542 newContext->context = glXCreateContext(
7543 implicitSwapchainImpl->display, visinfo,
7544 implicitSwapchainImpl->glCtx, GL_TRUE);
7546 XFree(visinfo);
7549 if (NULL == newContext || NULL == newContext->context) {
7550 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7551 } else {
7552 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7553 if (glXMakeCurrent(implicitSwapchainImpl->display,
7554 newContext->drawable, newContext->context) == False) {
7556 TRACE("Error in setting current context: context %p drawable %ld\n",
7557 newContext->context, newContext->drawable);
7559 checkGLcall("glXMakeContextCurrent");
7561 /* Clean up the old context */
7562 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7564 /* Reapply stateblock, and set device to render to a texture */
7565 device_reapply_stateblock(This);
7566 device_render_to_texture(This, TRUE);
7568 /* Set the current context of the swapchain to the new context */
7569 implicitSwapchainImpl->drawable = newContext->drawable;
7570 implicitSwapchainImpl->render_ctx = newContext->context;
7572 } else {
7573 /* Same context, but update render_offscreen and cull mode */
7574 device_render_to_texture(This, TRUE);
7577 /* Replace the render target */
7578 if (This->renderTarget != RenderSurface) {
7579 IWineD3DSurface_Release(This->renderTarget);
7580 This->renderTarget = RenderSurface;
7581 IWineD3DSurface_AddRef(RenderSurface);
7584 if (cfgs != NULL) XFree(cfgs);
7585 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7586 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7587 LEAVE_GL();
7588 #endif
7589 return WINED3D_OK;
7592 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7593 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7595 /* TODO: the use of Impl is deprecated. */
7596 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7598 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7600 /* some basic validation checks */
7601 if(This->cursorTexture) {
7602 ENTER_GL();
7603 glDeleteTextures(1, &This->cursorTexture);
7604 LEAVE_GL();
7605 This->cursorTexture = 0;
7608 if(pCursorBitmap) {
7609 /* MSDN: Cursor must be A8R8G8B8 */
7610 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7611 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7612 return WINED3DERR_INVALIDCALL;
7615 /* MSDN: Cursor must be smaller than the display mode */
7616 if(pSur->currentDesc.Width > This->ddraw_width ||
7617 pSur->currentDesc.Height > This->ddraw_height) {
7618 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);
7619 return WINED3DERR_INVALIDCALL;
7622 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7623 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7624 * Texture and Blitting code to draw the cursor
7626 pSur->Flags |= SFLAG_FORCELOAD;
7627 IWineD3DSurface_PreLoad(pCursorBitmap);
7628 pSur->Flags &= ~SFLAG_FORCELOAD;
7629 /* Do not store the surface's pointer because the application may release
7630 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7631 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7633 This->cursorTexture = pSur->glDescription.textureName;
7634 This->cursorWidth = pSur->currentDesc.Width;
7635 This->cursorHeight = pSur->currentDesc.Height;
7636 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7639 This->xHotSpot = XHotSpot;
7640 This->yHotSpot = YHotSpot;
7641 return WINED3D_OK;
7644 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7646 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7648 This->xScreenSpace = XScreenSpace;
7649 This->yScreenSpace = YScreenSpace;
7651 return;
7655 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7657 BOOL oldVisible = This->bCursorVisible;
7658 TRACE("(%p) : visible(%d)\n", This, bShow);
7660 if(This->cursorTexture)
7661 This->bCursorVisible = bShow;
7663 return oldVisible;
7666 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7668 TRACE("(%p) : state (%u)\n", This, This->state);
7669 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7670 switch (This->state) {
7671 case WINED3D_OK:
7672 return WINED3D_OK;
7673 case WINED3DERR_DEVICELOST:
7675 ResourceList *resourceList = This->resources;
7676 while (NULL != resourceList) {
7677 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7678 return WINED3DERR_DEVICENOTRESET;
7679 resourceList = resourceList->next;
7681 return WINED3DERR_DEVICELOST;
7683 case WINED3DERR_DRIVERINTERNALERROR:
7684 return WINED3DERR_DRIVERINTERNALERROR;
7687 /* Unknown state */
7688 return WINED3DERR_DRIVERINTERNALERROR;
7692 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7694 /** FIXME: Resource tracking needs to be done,
7695 * The closes we can do to this is set the priorities of all managed textures low
7696 * and then reset them.
7697 ***********************************************************/
7698 FIXME("(%p) : stub\n", This);
7699 return WINED3D_OK;
7702 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7704 /** FIXME: Resource trascking needs to be done.
7705 * in effect this pulls all non only default
7706 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7707 * and should clear down the context and set it up according to pPresentationParameters
7708 ***********************************************************/
7709 FIXME("(%p) : stub\n", This);
7710 return WINED3D_OK;
7713 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7715 /** FIXME: always true at the moment **/
7716 if(!bEnableDialogs) {
7717 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7719 return WINED3D_OK;
7723 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7725 TRACE("(%p) : pParameters %p\n", This, pParameters);
7727 *pParameters = This->createParms;
7728 return WINED3D_OK;
7731 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7732 IWineD3DSwapChain *swapchain;
7733 HRESULT hrc = WINED3D_OK;
7735 TRACE("Relaying to swapchain\n");
7737 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7738 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7740 return;
7743 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7744 IWineD3DSwapChain *swapchain;
7745 HRESULT hrc = WINED3D_OK;
7747 TRACE("Relaying to swapchain\n");
7749 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7750 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7752 return;
7756 /** ********************************************************
7757 * Notification functions
7758 ** ********************************************************/
7759 /** This function must be called in the release of a resource when ref == 0,
7760 * the contents of resource must still be correct,
7761 * any handels to other resource held by the caller must be closed
7762 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7763 *****************************************************/
7764 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7766 ResourceList* resourceList;
7768 TRACE("(%p) : resource %p\n", This, resource);
7769 #if 0
7770 EnterCriticalSection(&resourceStoreCriticalSection);
7771 #endif
7772 /* add a new texture to the frot of the linked list */
7773 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7774 resourceList->resource = resource;
7776 /* Get the old head */
7777 resourceList->next = This->resources;
7779 This->resources = resourceList;
7780 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7782 #if 0
7783 LeaveCriticalSection(&resourceStoreCriticalSection);
7784 #endif
7785 return;
7788 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7790 ResourceList* resourceList = NULL;
7791 ResourceList* previousResourceList = NULL;
7793 TRACE("(%p) : resource %p\n", This, resource);
7795 #if 0
7796 EnterCriticalSection(&resourceStoreCriticalSection);
7797 #endif
7798 resourceList = This->resources;
7800 while (resourceList != NULL) {
7801 if(resourceList->resource == resource) break;
7802 previousResourceList = resourceList;
7803 resourceList = resourceList->next;
7806 if (resourceList == NULL) {
7807 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7808 #if 0
7809 LeaveCriticalSection(&resourceStoreCriticalSection);
7810 #endif
7811 return;
7812 } else {
7813 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7815 /* make sure we don't leave a hole in the list */
7816 if (previousResourceList != NULL) {
7817 previousResourceList->next = resourceList->next;
7818 } else {
7819 This->resources = resourceList->next;
7822 #if 0
7823 LeaveCriticalSection(&resourceStoreCriticalSection);
7824 #endif
7825 return;
7829 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7831 int counter;
7833 TRACE("(%p) : resource %p\n", This, resource);
7834 switch(IWineD3DResource_GetType(resource)){
7835 case WINED3DRTYPE_SURFACE:
7836 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7837 break;
7838 case WINED3DRTYPE_TEXTURE:
7839 case WINED3DRTYPE_CUBETEXTURE:
7840 case WINED3DRTYPE_VOLUMETEXTURE:
7841 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7842 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7843 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7844 This->stateBlock->textures[counter] = NULL;
7846 if (This->updateStateBlock != This->stateBlock ){
7847 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7848 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7849 This->updateStateBlock->textures[counter] = NULL;
7853 break;
7854 case WINED3DRTYPE_VOLUME:
7855 /* TODO: nothing really? */
7856 break;
7857 case WINED3DRTYPE_VERTEXBUFFER:
7858 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7860 int streamNumber;
7861 TRACE("Cleaning up stream pointers\n");
7863 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7864 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7865 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7867 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7868 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7869 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7870 This->updateStateBlock->streamSource[streamNumber] = 0;
7871 /* Set changed flag? */
7874 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) */
7875 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7876 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7877 This->stateBlock->streamSource[streamNumber] = 0;
7880 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7881 else { /* This shouldn't happen */
7882 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7884 #endif
7888 break;
7889 case WINED3DRTYPE_INDEXBUFFER:
7890 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7891 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7892 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7893 This->updateStateBlock->pIndexData = NULL;
7896 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7897 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7898 This->stateBlock->pIndexData = NULL;
7902 break;
7903 default:
7904 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7905 break;
7909 /* Remove the resoruce from the resourceStore */
7910 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7912 TRACE("Resource released\n");
7916 /**********************************************************
7917 * IWineD3DDevice VTbl follows
7918 **********************************************************/
7920 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7922 /*** IUnknown methods ***/
7923 IWineD3DDeviceImpl_QueryInterface,
7924 IWineD3DDeviceImpl_AddRef,
7925 IWineD3DDeviceImpl_Release,
7926 /*** IWineD3DDevice methods ***/
7927 IWineD3DDeviceImpl_GetParent,
7928 /*** Creation methods**/
7929 IWineD3DDeviceImpl_CreateVertexBuffer,
7930 IWineD3DDeviceImpl_CreateIndexBuffer,
7931 IWineD3DDeviceImpl_CreateStateBlock,
7932 IWineD3DDeviceImpl_CreateSurface,
7933 IWineD3DDeviceImpl_CreateTexture,
7934 IWineD3DDeviceImpl_CreateVolumeTexture,
7935 IWineD3DDeviceImpl_CreateVolume,
7936 IWineD3DDeviceImpl_CreateCubeTexture,
7937 IWineD3DDeviceImpl_CreateQuery,
7938 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7939 IWineD3DDeviceImpl_CreateVertexDeclaration,
7940 IWineD3DDeviceImpl_CreateVertexShader,
7941 IWineD3DDeviceImpl_CreatePixelShader,
7942 IWineD3DDeviceImpl_CreatePalette,
7943 /*** Odd functions **/
7944 IWineD3DDeviceImpl_Init3D,
7945 IWineD3DDeviceImpl_Uninit3D,
7946 IWineD3DDeviceImpl_SetFullscreen,
7947 IWineD3DDeviceImpl_EnumDisplayModes,
7948 IWineD3DDeviceImpl_EvictManagedResources,
7949 IWineD3DDeviceImpl_GetAvailableTextureMem,
7950 IWineD3DDeviceImpl_GetBackBuffer,
7951 IWineD3DDeviceImpl_GetCreationParameters,
7952 IWineD3DDeviceImpl_GetDeviceCaps,
7953 IWineD3DDeviceImpl_GetDirect3D,
7954 IWineD3DDeviceImpl_GetDisplayMode,
7955 IWineD3DDeviceImpl_SetDisplayMode,
7956 IWineD3DDeviceImpl_GetHWND,
7957 IWineD3DDeviceImpl_SetHWND,
7958 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7959 IWineD3DDeviceImpl_GetRasterStatus,
7960 IWineD3DDeviceImpl_GetSwapChain,
7961 IWineD3DDeviceImpl_Reset,
7962 IWineD3DDeviceImpl_SetDialogBoxMode,
7963 IWineD3DDeviceImpl_SetCursorProperties,
7964 IWineD3DDeviceImpl_SetCursorPosition,
7965 IWineD3DDeviceImpl_ShowCursor,
7966 IWineD3DDeviceImpl_TestCooperativeLevel,
7967 /*** Getters and setters **/
7968 IWineD3DDeviceImpl_SetClipPlane,
7969 IWineD3DDeviceImpl_GetClipPlane,
7970 IWineD3DDeviceImpl_SetClipStatus,
7971 IWineD3DDeviceImpl_GetClipStatus,
7972 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7973 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7974 IWineD3DDeviceImpl_SetDepthStencilSurface,
7975 IWineD3DDeviceImpl_GetDepthStencilSurface,
7976 IWineD3DDeviceImpl_SetFVF,
7977 IWineD3DDeviceImpl_GetFVF,
7978 IWineD3DDeviceImpl_SetGammaRamp,
7979 IWineD3DDeviceImpl_GetGammaRamp,
7980 IWineD3DDeviceImpl_SetIndices,
7981 IWineD3DDeviceImpl_GetIndices,
7982 IWineD3DDeviceImpl_SetLight,
7983 IWineD3DDeviceImpl_GetLight,
7984 IWineD3DDeviceImpl_SetLightEnable,
7985 IWineD3DDeviceImpl_GetLightEnable,
7986 IWineD3DDeviceImpl_SetMaterial,
7987 IWineD3DDeviceImpl_GetMaterial,
7988 IWineD3DDeviceImpl_SetNPatchMode,
7989 IWineD3DDeviceImpl_GetNPatchMode,
7990 IWineD3DDeviceImpl_SetPaletteEntries,
7991 IWineD3DDeviceImpl_GetPaletteEntries,
7992 IWineD3DDeviceImpl_SetPixelShader,
7993 IWineD3DDeviceImpl_GetPixelShader,
7994 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7995 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7996 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7997 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7998 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7999 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8000 IWineD3DDeviceImpl_SetRenderState,
8001 IWineD3DDeviceImpl_GetRenderState,
8002 IWineD3DDeviceImpl_SetRenderTarget,
8003 IWineD3DDeviceImpl_GetRenderTarget,
8004 IWineD3DDeviceImpl_SetFrontBackBuffers,
8005 IWineD3DDeviceImpl_SetSamplerState,
8006 IWineD3DDeviceImpl_GetSamplerState,
8007 IWineD3DDeviceImpl_SetScissorRect,
8008 IWineD3DDeviceImpl_GetScissorRect,
8009 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8010 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8011 IWineD3DDeviceImpl_SetStreamSource,
8012 IWineD3DDeviceImpl_GetStreamSource,
8013 IWineD3DDeviceImpl_SetStreamSourceFreq,
8014 IWineD3DDeviceImpl_GetStreamSourceFreq,
8015 IWineD3DDeviceImpl_SetTexture,
8016 IWineD3DDeviceImpl_GetTexture,
8017 IWineD3DDeviceImpl_SetTextureStageState,
8018 IWineD3DDeviceImpl_GetTextureStageState,
8019 IWineD3DDeviceImpl_SetTransform,
8020 IWineD3DDeviceImpl_GetTransform,
8021 IWineD3DDeviceImpl_SetVertexDeclaration,
8022 IWineD3DDeviceImpl_GetVertexDeclaration,
8023 IWineD3DDeviceImpl_SetVertexShader,
8024 IWineD3DDeviceImpl_GetVertexShader,
8025 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8026 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8027 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8028 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8029 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8030 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8031 IWineD3DDeviceImpl_SetViewport,
8032 IWineD3DDeviceImpl_GetViewport,
8033 IWineD3DDeviceImpl_MultiplyTransform,
8034 IWineD3DDeviceImpl_ValidateDevice,
8035 IWineD3DDeviceImpl_ProcessVertices,
8036 /*** State block ***/
8037 IWineD3DDeviceImpl_BeginStateBlock,
8038 IWineD3DDeviceImpl_EndStateBlock,
8039 /*** Scene management ***/
8040 IWineD3DDeviceImpl_BeginScene,
8041 IWineD3DDeviceImpl_EndScene,
8042 IWineD3DDeviceImpl_Present,
8043 IWineD3DDeviceImpl_Clear,
8044 /*** Drawing ***/
8045 IWineD3DDeviceImpl_DrawPrimitive,
8046 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8047 IWineD3DDeviceImpl_DrawPrimitiveUP,
8048 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8049 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8050 IWineD3DDeviceImpl_DrawRectPatch,
8051 IWineD3DDeviceImpl_DrawTriPatch,
8052 IWineD3DDeviceImpl_DeletePatch,
8053 IWineD3DDeviceImpl_ColorFill,
8054 IWineD3DDeviceImpl_UpdateTexture,
8055 IWineD3DDeviceImpl_UpdateSurface,
8056 IWineD3DDeviceImpl_StretchRect,
8057 IWineD3DDeviceImpl_GetRenderTargetData,
8058 IWineD3DDeviceImpl_GetFrontBufferData,
8059 /*** Internal use IWineD3DDevice methods ***/
8060 IWineD3DDeviceImpl_SetupTextureStates,
8061 /*** object tracking ***/
8062 IWineD3DDeviceImpl_ResourceReleased
8066 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8067 WINED3DRS_ALPHABLENDENABLE ,
8068 WINED3DRS_ALPHAFUNC ,
8069 WINED3DRS_ALPHAREF ,
8070 WINED3DRS_ALPHATESTENABLE ,
8071 WINED3DRS_BLENDOP ,
8072 WINED3DRS_COLORWRITEENABLE ,
8073 WINED3DRS_DESTBLEND ,
8074 WINED3DRS_DITHERENABLE ,
8075 WINED3DRS_FILLMODE ,
8076 WINED3DRS_FOGDENSITY ,
8077 WINED3DRS_FOGEND ,
8078 WINED3DRS_FOGSTART ,
8079 WINED3DRS_LASTPIXEL ,
8080 WINED3DRS_SHADEMODE ,
8081 WINED3DRS_SRCBLEND ,
8082 WINED3DRS_STENCILENABLE ,
8083 WINED3DRS_STENCILFAIL ,
8084 WINED3DRS_STENCILFUNC ,
8085 WINED3DRS_STENCILMASK ,
8086 WINED3DRS_STENCILPASS ,
8087 WINED3DRS_STENCILREF ,
8088 WINED3DRS_STENCILWRITEMASK ,
8089 WINED3DRS_STENCILZFAIL ,
8090 WINED3DRS_TEXTUREFACTOR ,
8091 WINED3DRS_WRAP0 ,
8092 WINED3DRS_WRAP1 ,
8093 WINED3DRS_WRAP2 ,
8094 WINED3DRS_WRAP3 ,
8095 WINED3DRS_WRAP4 ,
8096 WINED3DRS_WRAP5 ,
8097 WINED3DRS_WRAP6 ,
8098 WINED3DRS_WRAP7 ,
8099 WINED3DRS_ZENABLE ,
8100 WINED3DRS_ZFUNC ,
8101 WINED3DRS_ZWRITEENABLE
8104 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8105 WINED3DTSS_ADDRESSW ,
8106 WINED3DTSS_ALPHAARG0 ,
8107 WINED3DTSS_ALPHAARG1 ,
8108 WINED3DTSS_ALPHAARG2 ,
8109 WINED3DTSS_ALPHAOP ,
8110 WINED3DTSS_BUMPENVLOFFSET ,
8111 WINED3DTSS_BUMPENVLSCALE ,
8112 WINED3DTSS_BUMPENVMAT00 ,
8113 WINED3DTSS_BUMPENVMAT01 ,
8114 WINED3DTSS_BUMPENVMAT10 ,
8115 WINED3DTSS_BUMPENVMAT11 ,
8116 WINED3DTSS_COLORARG0 ,
8117 WINED3DTSS_COLORARG1 ,
8118 WINED3DTSS_COLORARG2 ,
8119 WINED3DTSS_COLOROP ,
8120 WINED3DTSS_RESULTARG ,
8121 WINED3DTSS_TEXCOORDINDEX ,
8122 WINED3DTSS_TEXTURETRANSFORMFLAGS
8125 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8126 WINED3DSAMP_ADDRESSU ,
8127 WINED3DSAMP_ADDRESSV ,
8128 WINED3DSAMP_ADDRESSW ,
8129 WINED3DSAMP_BORDERCOLOR ,
8130 WINED3DSAMP_MAGFILTER ,
8131 WINED3DSAMP_MINFILTER ,
8132 WINED3DSAMP_MIPFILTER ,
8133 WINED3DSAMP_MIPMAPLODBIAS ,
8134 WINED3DSAMP_MAXMIPLEVEL ,
8135 WINED3DSAMP_MAXANISOTROPY ,
8136 WINED3DSAMP_SRGBTEXTURE ,
8137 WINED3DSAMP_ELEMENTINDEX
8140 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8141 WINED3DRS_AMBIENT ,
8142 WINED3DRS_AMBIENTMATERIALSOURCE ,
8143 WINED3DRS_CLIPPING ,
8144 WINED3DRS_CLIPPLANEENABLE ,
8145 WINED3DRS_COLORVERTEX ,
8146 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8147 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8148 WINED3DRS_FOGDENSITY ,
8149 WINED3DRS_FOGEND ,
8150 WINED3DRS_FOGSTART ,
8151 WINED3DRS_FOGTABLEMODE ,
8152 WINED3DRS_FOGVERTEXMODE ,
8153 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8154 WINED3DRS_LIGHTING ,
8155 WINED3DRS_LOCALVIEWER ,
8156 WINED3DRS_MULTISAMPLEANTIALIAS ,
8157 WINED3DRS_MULTISAMPLEMASK ,
8158 WINED3DRS_NORMALIZENORMALS ,
8159 WINED3DRS_PATCHEDGESTYLE ,
8160 WINED3DRS_POINTSCALE_A ,
8161 WINED3DRS_POINTSCALE_B ,
8162 WINED3DRS_POINTSCALE_C ,
8163 WINED3DRS_POINTSCALEENABLE ,
8164 WINED3DRS_POINTSIZE ,
8165 WINED3DRS_POINTSIZE_MAX ,
8166 WINED3DRS_POINTSIZE_MIN ,
8167 WINED3DRS_POINTSPRITEENABLE ,
8168 WINED3DRS_RANGEFOGENABLE ,
8169 WINED3DRS_SPECULARMATERIALSOURCE ,
8170 WINED3DRS_TWEENFACTOR ,
8171 WINED3DRS_VERTEXBLEND
8174 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8175 WINED3DTSS_TEXCOORDINDEX ,
8176 WINED3DTSS_TEXTURETRANSFORMFLAGS
8179 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8180 WINED3DSAMP_DMAPOFFSET