wined3d: Print real unhandled D3DCMPFUNC value.
[wine/multimedia.git] / dlls / wined3d / device.c
blobf0e7f26e8ccfee92f67e8954535abdefcfcc7859
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 D3DLIGHT_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 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
75 /* enable pbuffer support for offscreen textures */
76 BOOL pbuffer_support = FALSE;
77 /* allocate one pbuffer per surface */
78 BOOL pbuffer_per_surface = FALSE;
80 /* static function declarations */
81 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
83 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
85 /* helper macros */
86 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
88 #define D3DCREATEOBJECTINSTANCE(object, type) { \
89 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
90 D3DMEMCHECK(object, pp##type); \
91 object->lpVtbl = &IWineD3D##type##_Vtbl; \
92 object->wineD3DDevice = This; \
93 object->parent = parent; \
94 object->ref = 1; \
95 *pp##type = (IWineD3D##type *) object; \
98 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
99 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
100 D3DMEMCHECK(object, pp##type); \
101 object->lpVtbl = &IWineD3D##type##_Vtbl; \
102 object->resource.wineD3DDevice = This; \
103 object->resource.parent = parent; \
104 object->resource.resourceType = d3dtype; \
105 object->resource.ref = 1; \
106 object->resource.pool = Pool; \
107 object->resource.format = Format; \
108 object->resource.usage = Usage; \
109 object->resource.size = _size; \
110 /* Check that we have enough video ram left */ \
111 if (Pool == WINED3DPOOL_DEFAULT) { \
112 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
113 WARN("Out of 'bogus' video memory\n"); \
114 HeapFree(GetProcessHeap(), 0, object); \
115 *pp##type = NULL; \
116 return WINED3DERR_OUTOFVIDEOMEMORY; \
118 globalChangeGlRam(_size); \
120 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
121 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
122 FIXME("Out of memory!\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 *pp##type = (IWineD3D##type *) object; \
128 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
129 TRACE("(%p) : Created resource %p\n", This, object); \
132 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
133 _basetexture.levels = Levels; \
134 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
135 _basetexture.LOD = 0; \
136 _basetexture.dirty = TRUE; \
139 /**********************************************************
140 * Global variable / Constants follow
141 **********************************************************/
142 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
144 /**********************************************************
145 * Utility functions follow
146 **********************************************************/
147 /* Convert the D3DLIGHT properties into equivalent gl lights */
148 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
150 float quad_att;
151 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
155 glMatrixMode(GL_MODELVIEW);
156 glPushMatrix();
157 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
159 /* Diffuse: */
160 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
161 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
162 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
163 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
164 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
165 checkGLcall("glLightfv");
167 /* Specular */
168 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
169 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
170 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
171 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
172 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
173 checkGLcall("glLightfv");
175 /* Ambient */
176 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
177 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
178 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
179 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
180 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
181 checkGLcall("glLightfv");
183 /* Attenuation - Are these right? guessing... */
184 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
185 checkGLcall("glLightf");
186 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
187 checkGLcall("glLightf");
189 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
190 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
191 } else {
192 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
195 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
196 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
197 checkGLcall("glLightf");
199 switch (lightInfo->OriginalParms.Type) {
200 case D3DLIGHT_POINT:
201 /* Position */
202 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
203 checkGLcall("glLightfv");
204 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
205 checkGLcall("glLightf");
206 /* FIXME: Range */
207 break;
209 case D3DLIGHT_SPOT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 /* Direction */
214 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
215 checkGLcall("glLightfv");
216 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
217 checkGLcall("glLightf");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
219 checkGLcall("glLightf");
220 /* FIXME: Range */
221 break;
223 case D3DLIGHT_DIRECTIONAL:
224 /* Direction */
225 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
226 checkGLcall("glLightfv");
227 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
230 checkGLcall("glLightf");
231 break;
233 default:
234 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
237 /* Restore the modelview matrix */
238 glPopMatrix();
241 /**********************************************************
242 * GLSL helper functions follow
243 **********************************************************/
245 /** Attach a GLSL pixel or vertex shader object to the shader program */
246 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
249 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
250 if (This->stateBlock->glsl_program && shaderObj != 0) {
251 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
252 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
253 checkGLcall("glAttachObjectARB");
257 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
258 * It sets the programId on the current StateBlock (because it should be called
259 * inside of the DrawPrimitive() part of the render loop).
261 * If a program for the given combination does not exist, create one, and store
262 * the program in the list. If it creates a program, it will link the given
263 * objects, too.
265 * We keep the shader programs around on a list because linking
266 * shader objects together is an expensive operation. It's much
267 * faster to loop through a list of pre-compiled & linked programs
268 * each time that the application sets a new pixel or vertex shader
269 * than it is to re-link them together at that time.
271 * The list will be deleted in IWineD3DDevice::Release().
273 void set_glsl_shader_program(IWineD3DDevice *iface) {
275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
276 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
277 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
278 struct glsl_shader_prog_link *curLink = NULL;
279 struct glsl_shader_prog_link *newLink = NULL;
280 struct list *ptr = NULL;
281 GLhandleARB programId = 0;
282 int i;
283 char glsl_name[8];
285 ptr = list_head( &This->glsl_shader_progs );
286 while (ptr) {
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
292 curLink->programId);
293 This->stateBlock->glsl_program = curLink;
294 return;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
304 /* Allocate a new link for the list of programs */
305 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
306 newLink->programId = programId;
307 This->stateBlock->glsl_program = newLink;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
311 int i;
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
313 char tmp_name[10];
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
322 * GLSL shaders.
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
348 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
349 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
350 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
351 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
353 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
354 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
355 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
356 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
359 return;
362 /** Detach the GLSL pixel or vertex shader object from the shader program */
363 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
367 if (shaderObj != 0 && programId != 0) {
368 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
369 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
370 checkGLcall("glDetachObjectARB");
374 /** Delete a GLSL shader program */
375 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379 if (obj != 0) {
380 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
381 GL_EXTCALL(glDeleteObjectARB(obj));
382 checkGLcall("glDeleteObjectARB");
386 /** Delete the list of linked programs this shader is associated with.
387 * Also at this point, check to see if there are any objects left attached
388 * to each GLSL program. If not, delete the GLSL program object.
389 * This will be run when a device is released. */
390 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
392 struct list *ptr = NULL;
393 struct glsl_shader_prog_link *curLink = NULL;
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 int numAttached = 0;
397 int i;
398 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
399 (one pixel shader and one vertex shader at most) */
401 ptr = list_head( &This->glsl_shader_progs );
402 while (ptr) {
403 /* First, get the current item,
404 * save the link to the next pointer,
405 * detach and delete shader objects,
406 * then de-allocate the list item's memory */
407 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
408 ptr = list_next( &This->glsl_shader_progs, ptr );
410 /* See if this object is still attached to the program - it may have been detached already */
411 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
412 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
413 for (i = 0; i < numAttached; i++) {
414 detach_glsl_shader(iface, objList[i], curLink->programId);
417 delete_glsl_shader_program(iface, curLink->programId);
419 /* Free the uniform locations */
420 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
421 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
423 /* Free the memory for this list item */
424 HeapFree(GetProcessHeap(), 0, curLink);
429 /* Apply the current values to the specified texture stage */
430 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 float col[4];
434 union {
435 float f;
436 DWORD d;
437 } tmpvalue;
439 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
440 clamping, MIPLOD, etc. This will work for up to 16 samplers.
443 if (Sampler >= GL_LIMITS(sampler_stages)) {
444 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
445 return;
447 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
448 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
449 ENTER_GL();
450 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
451 checkGLcall("glActiveTextureARB");
452 LEAVE_GL();
453 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
454 } else if (Sampler > 0) {
455 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
456 return;
459 /* TODO: change this to a lookup table
460 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
461 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
462 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
463 especially when there are a number of groups of states. */
465 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
467 /* 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 */
468 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
469 /* these are the only two supported states that need to be applied */
470 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
471 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
472 #if 0 /* not supported at the moment */
473 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
474 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
475 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
476 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
477 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
478 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
479 APPLY_STATE(WINED3DTSS_RESULTARG);
480 APPLY_STATE(WINED3DTSS_CONSTANT);
481 #endif
482 /* a quick sanity check in case someone forgot to update this function */
483 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
484 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
486 #undef APPLY_STATE
488 /* apply any sampler states that always need applying */
489 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
490 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
491 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
492 GL_TEXTURE_LOD_BIAS_EXT,
493 tmpvalue.f);
494 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
497 /* Note the D3DRS value applies to all textures, but GL has one
498 * per texture, so apply it now ready to be used!
500 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
501 /* Set the default alpha blend color */
502 if (GL_SUPPORT(ARB_IMAGING)) {
503 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
504 checkGLcall("glBlendColor");
505 } else {
506 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
509 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
510 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
511 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
513 /* TODO: NV_POINT_SPRITE */
514 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
515 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
516 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
517 glDisable(GL_POINT_SMOOTH);
519 /* Centre the texture on the vertex */
520 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
521 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
523 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
524 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
525 checkGLcall("glTexEnvf(...)");
526 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
527 glEnable( GL_POINT_SPRITE_ARB );
528 checkGLcall("glEnable(...)");
529 } else {
530 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
531 glDisable( GL_POINT_SPRITE_ARB );
532 checkGLcall("glEnable(...)");
536 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
539 /**********************************************************
540 * IUnknown parts follows
541 **********************************************************/
543 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
547 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
548 if (IsEqualGUID(riid, &IID_IUnknown)
549 || IsEqualGUID(riid, &IID_IWineD3DBase)
550 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
551 IUnknown_AddRef(iface);
552 *ppobj = This;
553 return S_OK;
555 *ppobj = NULL;
556 return E_NOINTERFACE;
559 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
561 ULONG refCount = InterlockedIncrement(&This->ref);
563 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
564 return refCount;
567 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
569 ULONG refCount = InterlockedDecrement(&This->ref);
571 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
573 if (!refCount) {
574 /* TODO: Clean up all the surfaces and textures! */
575 /* NOTE: You must release the parent if the object was created via a callback
576 ** ***************************/
578 /* Delete any GLSL shader programs that may exist */
579 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
580 wined3d_settings.ps_selected_mode == SHADER_GLSL)
581 delete_glsl_shader_list(iface);
583 /* Release the update stateblock */
584 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
585 if(This->updateStateBlock != This->stateBlock)
586 FIXME("(%p) Something's still holding the Update stateblock\n",This);
588 This->updateStateBlock = NULL;
589 { /* because were not doing proper internal refcounts releasing the primary state block
590 causes recursion with the extra checks in ResourceReleased, to avoid this we have
591 to set this->stateBlock = NULL; first */
592 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
593 This->stateBlock = NULL;
595 /* Release the stateblock */
596 if(IWineD3DStateBlock_Release(stateBlock) > 0){
597 FIXME("(%p) Something's still holding the Update stateblock\n",This);
601 if (This->resources != NULL ) {
602 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
603 dumpResources(This->resources);
607 IWineD3D_Release(This->wineD3D);
608 This->wineD3D = NULL;
609 HeapFree(GetProcessHeap(), 0, This);
610 TRACE("Freed device %p\n", This);
611 This = NULL;
613 return refCount;
616 /**********************************************************
617 * IWineD3DDevice implementation follows
618 **********************************************************/
619 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
621 *pParent = This->parent;
622 IUnknown_AddRef(This->parent);
623 return WINED3D_OK;
626 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
627 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
628 GLenum error, glUsage;
629 DWORD vboUsage = object->resource.usage;
630 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
631 WARN("Creating a vbo failed once, not trying again\n");
632 return;
635 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
637 ENTER_GL();
638 /* Make sure that the gl error is cleared. Do not use checkGLcall
639 * here because checkGLcall just prints a fixme and continues. However,
640 * if an error during VBO creation occurs we can fall back to non-vbo operation
641 * with full functionality(but performance loss)
643 while(glGetError() != GL_NO_ERROR);
645 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
646 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
647 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
648 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
649 * to check if the rhw and color values are in the correct format.
652 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
653 error = glGetError();
654 if(object->vbo == 0 || error != GL_NO_ERROR) {
655 WARN("Failed to create a VBO with error %d\n", error);
656 goto error;
659 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
660 error = glGetError();
661 if(error != GL_NO_ERROR) {
662 WARN("Failed to bind the VBO, error %d\n", error);
663 goto error;
666 /* Transformed vertices are horribly inflexible. If the app specifies an
667 * vertex buffer with transformed vertices in default pool without DYNAMIC
668 * usage assume DYNAMIC usage and print a warning. The app will have to update
669 * the vertices regularily for them to be useful
671 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
672 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
673 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
674 vboUsage |= WINED3DUSAGE_DYNAMIC;
677 /* Don't use static, because dx apps tend to update the buffer
678 * quite often even if they specify 0 usage
680 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
681 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
682 TRACE("Gl usage = GL_STREAM_DRAW\n");
683 glUsage = GL_STREAM_DRAW_ARB;
684 break;
685 case D3DUSAGE_WRITEONLY:
686 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
687 glUsage = GL_DYNAMIC_DRAW_ARB;
688 break;
689 case D3DUSAGE_DYNAMIC:
690 TRACE("Gl usage = GL_STREAM_COPY\n");
691 glUsage = GL_STREAM_COPY_ARB;
692 break;
693 default:
694 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
695 glUsage = GL_DYNAMIC_COPY_ARB;
696 break;
699 /* Reserve memory for the buffer. The amount of data won't change
700 * so we are safe with calling glBufferData once with a NULL ptr and
701 * calling glBufferSubData on updates
703 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
704 error = glGetError();
705 if(error != GL_NO_ERROR) {
706 WARN("glBufferDataARB failed with error %d\n", error);
707 goto error;
710 LEAVE_GL();
712 return;
713 error:
714 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
715 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
716 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
717 object->vbo = 0;
718 object->Flags |= VBFLAG_VBOCREATEFAIL;
719 LEAVE_GL();
720 return;
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
724 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
725 IUnknown *parent) {
726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
727 IWineD3DVertexBufferImpl *object;
728 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
729 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
730 BOOL conv;
731 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
733 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
734 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
736 if(Size == 0) return WINED3DERR_INVALIDCALL;
738 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
739 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
741 object->fvf = FVF;
743 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
744 * drawStridedFast (half-life 2).
746 * Basically converting the vertices in the buffer is quite expensive, and observations
747 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
748 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
750 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
751 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
752 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
753 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
754 * dx7 apps.
755 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
756 * more. In this call we can convert dx7 buffers too.
758 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
759 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
760 (dxVersion > 7 || !conv) ) {
761 CreateVBO(object);
763 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
764 if(dxVersion == 7 && object->vbo) {
765 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
766 object->resource.allocatedMemory = NULL;
770 return WINED3D_OK;
773 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
774 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
775 HANDLE *sharedHandle, IUnknown *parent) {
776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
777 IWineD3DIndexBufferImpl *object;
778 TRACE("(%p) Creating index buffer\n", This);
780 /* Allocate the storage for the device */
781 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
783 /*TODO: use VBO's */
784 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
785 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
788 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
789 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
790 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
792 return WINED3D_OK;
795 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
798 IWineD3DStateBlockImpl *object;
799 int i, j;
800 HRESULT temp_result;
802 D3DCREATEOBJECTINSTANCE(object, StateBlock)
803 object->blockType = Type;
805 /* Special case - Used during initialization to produce a placeholder stateblock
806 so other functions called can update a state block */
807 if (Type == WINED3DSBT_INIT) {
808 /* Don't bother increasing the reference count otherwise a device will never
809 be freed due to circular dependencies */
810 return WINED3D_OK;
813 temp_result = allocate_shader_constants(object);
814 if (WINED3D_OK != temp_result)
815 return temp_result;
817 /* Otherwise, might as well set the whole state block to the appropriate values */
818 if (This->stateBlock != NULL)
819 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
820 else
821 memset(object->streamFreq, 1, sizeof(object->streamFreq));
823 /* Reset the ref and type after kludging it */
824 object->wineD3DDevice = This;
825 object->ref = 1;
826 object->blockType = Type;
828 TRACE("Updating changed flags appropriate for type %d\n", Type);
830 if (Type == WINED3DSBT_ALL) {
832 TRACE("ALL => Pretend everything has changed\n");
833 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
835 } else if (Type == WINED3DSBT_PIXELSTATE) {
837 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
838 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
840 object->changed.pixelShader = TRUE;
842 /* Pixel Shader Constants */
843 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
844 object->changed.pixelShaderConstantsF[i] = TRUE;
845 for (i = 0; i < MAX_CONST_B; ++i)
846 object->changed.pixelShaderConstantsB[i] = TRUE;
847 for (i = 0; i < MAX_CONST_I; ++i)
848 object->changed.pixelShaderConstantsI[i] = TRUE;
850 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
851 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
853 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
854 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
855 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
858 for (j = 0 ; j < 16; j++) {
859 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
861 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
865 } else if (Type == WINED3DSBT_VERTEXSTATE) {
867 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
868 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
870 object->changed.vertexShader = TRUE;
872 /* Vertex Shader Constants */
873 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
874 object->changed.vertexShaderConstantsF[i] = TRUE;
875 for (i = 0; i < MAX_CONST_B; ++i)
876 object->changed.vertexShaderConstantsB[i] = TRUE;
877 for (i = 0; i < MAX_CONST_I; ++i)
878 object->changed.vertexShaderConstantsI[i] = TRUE;
880 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
881 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
883 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
884 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
885 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
888 for (j = 0 ; j < 16; j++){
889 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
890 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
894 /* Duplicate light chain */
896 PLIGHTINFOEL *src = NULL;
897 PLIGHTINFOEL *dst = NULL;
898 PLIGHTINFOEL *newEl = NULL;
899 src = This->stateBlock->lights;
900 object->lights = NULL;
903 while (src) {
904 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
905 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
906 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
907 newEl->prev = dst;
908 newEl->changed = TRUE;
909 newEl->enabledChanged = TRUE;
910 if (dst == NULL) {
911 object->lights = newEl;
912 } else {
913 dst->next = newEl;
915 dst = newEl;
916 src = src->next;
921 } else {
922 FIXME("Unrecognized state block type %d\n", Type);
925 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
926 return WINED3D_OK;
930 /* ************************************
931 MSDN:
932 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
934 Discard
935 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
937 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.
939 ******************************** */
941 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) {
942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
943 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
944 unsigned int pow2Width, pow2Height;
945 unsigned int Size = 1;
946 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
947 TRACE("(%p) Create surface\n",This);
949 /** FIXME: Check ranges on the inputs are valid
950 * MSDN
951 * MultisampleQuality
952 * [in] Quality level. The valid range is between zero and one less than the level
953 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
954 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
955 * values of paired render targets, depth stencil surfaces, and the MultiSample type
956 * must all match.
957 *******************************/
961 * TODO: Discard MSDN
962 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
964 * If this flag is set, the contents of the depth stencil buffer will be
965 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
966 * with a different depth surface.
968 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
969 ***************************/
971 if(MultisampleQuality < 0) {
972 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
973 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
976 if(MultisampleQuality > 0) {
977 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
978 MultisampleQuality=0;
981 /** FIXME: Check that the format is supported
982 * by the device.
983 *******************************/
985 /* Non-power2 support */
987 /* Find the nearest pow2 match */
988 pow2Width = pow2Height = 1;
989 while (pow2Width < Width) pow2Width <<= 1;
990 while (pow2Height < Height) pow2Height <<= 1;
992 if (pow2Width > Width || pow2Height > Height) {
993 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
994 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
995 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
996 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
997 This, Width, Height);
998 return WINED3DERR_NOTAVAILABLE;
1002 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1003 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1004 * space!
1005 *********************************/
1006 if (WINED3DFMT_UNKNOWN == Format) {
1007 Size = 0;
1008 } else if (Format == WINED3DFMT_DXT1) {
1009 /* DXT1 is half byte per pixel */
1010 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1012 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1013 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1014 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1015 } else {
1016 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1019 /** Create and initialise the surface resource **/
1020 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1021 /* "Standalone" surface */
1022 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1024 object->currentDesc.Width = Width;
1025 object->currentDesc.Height = Height;
1026 object->currentDesc.MultiSampleType = MultiSample;
1027 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1029 /* Setup some glformat defaults */
1030 object->glDescription.glFormat = tableEntry->glFormat;
1031 object->glDescription.glFormatInternal = tableEntry->glInternal;
1032 object->glDescription.glType = tableEntry->glType;
1034 object->glDescription.textureName = 0;
1035 object->glDescription.level = Level;
1036 object->glDescription.target = GL_TEXTURE_2D;
1038 /* Internal data */
1039 object->pow2Width = pow2Width;
1040 object->pow2Height = pow2Height;
1042 /* Flags */
1043 object->Flags = 0; /* We start without flags set */
1044 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1045 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1046 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1047 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1050 if (WINED3DFMT_UNKNOWN != Format) {
1051 object->bytesPerPixel = tableEntry->bpp;
1052 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1053 } else {
1054 object->bytesPerPixel = 0;
1055 object->pow2Size = 0;
1058 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1060 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1062 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1063 * this function is too deap to need to care about things like this.
1064 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1065 * ****************************************/
1066 switch(Pool) {
1067 case WINED3DPOOL_SCRATCH:
1068 if(Lockable == FALSE)
1069 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1070 which are mutually exclusive, setting lockable to true\n");
1071 Lockable = TRUE;
1072 break;
1073 case WINED3DPOOL_SYSTEMMEM:
1074 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1075 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1076 case WINED3DPOOL_MANAGED:
1077 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1078 Usage of DYNAMIC which are mutually exclusive, not doing \
1079 anything just telling you.\n");
1080 break;
1081 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1082 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1083 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1084 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1085 break;
1086 default:
1087 FIXME("(%p) Unknown pool %d\n", This, Pool);
1088 break;
1091 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1092 FIXME("Trying to create a render target that isn't in the default pool\n");
1095 /* mark the texture as dirty so that it get's loaded first time around*/
1096 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1097 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1098 This, Width, Height, Format, debug_d3dformat(Format),
1099 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1101 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1102 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1103 This->ddraw_primary = (IWineD3DSurface *) object;
1105 /* Look at the implementation and set the correct Vtable */
1106 switch(Impl) {
1107 case SURFACE_OPENGL:
1108 /* Nothing to do, it's set already */
1109 break;
1111 case SURFACE_GDI:
1112 object->lpVtbl = &IWineGDISurface_Vtbl;
1113 break;
1115 default:
1116 /* To be sure to catch this */
1117 ERR("Unknown requested surface implementation %d!\n", Impl);
1118 IWineD3DSurface_Release((IWineD3DSurface *) object);
1119 return WINED3DERR_INVALIDCALL;
1122 /* Call the private setup routine */
1123 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1127 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1128 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1129 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1130 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1133 IWineD3DTextureImpl *object;
1134 unsigned int i;
1135 UINT tmpW;
1136 UINT tmpH;
1137 HRESULT hr;
1138 unsigned int pow2Width = Width;
1139 unsigned int pow2Height = Height;
1142 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#lx\n", This, Width, Height, Levels, Usage);
1143 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1144 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1146 /* TODO: It should only be possible to create textures for formats
1147 that are reported as supported */
1148 if (WINED3DFMT_UNKNOWN >= Format) {
1149 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1150 return WINED3DERR_INVALIDCALL;
1153 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1154 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1155 object->width = Width;
1156 object->height = Height;
1158 /** Non-power2 support **/
1159 /* Find the nearest pow2 match */
1160 pow2Width = pow2Height = 1;
1161 while (pow2Width < Width) pow2Width <<= 1;
1162 while (pow2Height < Height) pow2Height <<= 1;
1164 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1165 /* Precalculated scaling for 'faked' non power of two texture coords */
1166 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1167 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1168 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1170 /* Calculate levels for mip mapping */
1171 if (Levels == 0) {
1172 TRACE("calculating levels %d\n", object->baseTexture.levels);
1173 object->baseTexture.levels++;
1174 tmpW = Width;
1175 tmpH = Height;
1176 while (tmpW > 1 || tmpH > 1) {
1177 tmpW = max(1, tmpW >> 1);
1178 tmpH = max(1, tmpH >> 1);
1179 object->baseTexture.levels++;
1181 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1184 /* Generate all the surfaces */
1185 tmpW = Width;
1186 tmpH = Height;
1187 for (i = 0; i < object->baseTexture.levels; i++)
1189 /* use the callback to create the texture surface */
1190 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1191 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1192 FIXME("Failed to create surface %p\n", object);
1193 /* clean up */
1194 object->surfaces[i] = NULL;
1195 IWineD3DTexture_Release((IWineD3DTexture *)object);
1197 *ppTexture = NULL;
1198 return hr;
1201 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1202 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1203 /* calculate the next mipmap level */
1204 tmpW = max(1, tmpW >> 1);
1205 tmpH = max(1, tmpH >> 1);
1208 TRACE("(%p) : Created texture %p\n", This, object);
1209 return WINED3D_OK;
1212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1213 UINT Width, UINT Height, UINT Depth,
1214 UINT Levels, DWORD Usage,
1215 WINED3DFORMAT Format, WINED3DPOOL Pool,
1216 IWineD3DVolumeTexture **ppVolumeTexture,
1217 HANDLE *pSharedHandle, IUnknown *parent,
1218 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1221 IWineD3DVolumeTextureImpl *object;
1222 unsigned int i;
1223 UINT tmpW;
1224 UINT tmpH;
1225 UINT tmpD;
1227 /* TODO: It should only be possible to create textures for formats
1228 that are reported as supported */
1229 if (WINED3DFMT_UNKNOWN >= Format) {
1230 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1231 return WINED3DERR_INVALIDCALL;
1234 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1235 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1237 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1238 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1240 object->width = Width;
1241 object->height = Height;
1242 object->depth = Depth;
1244 /* Calculate levels for mip mapping */
1245 if (Levels == 0) {
1246 object->baseTexture.levels++;
1247 tmpW = Width;
1248 tmpH = Height;
1249 tmpD = Depth;
1250 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1251 tmpW = max(1, tmpW >> 1);
1252 tmpH = max(1, tmpH >> 1);
1253 tmpD = max(1, tmpD >> 1);
1254 object->baseTexture.levels++;
1256 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1259 /* Generate all the surfaces */
1260 tmpW = Width;
1261 tmpH = Height;
1262 tmpD = Depth;
1264 for (i = 0; i < object->baseTexture.levels; i++)
1266 /* Create the volume */
1267 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1268 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1270 /* Set it's container to this object */
1271 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1273 /* calcualte the next mipmap level */
1274 tmpW = max(1, tmpW >> 1);
1275 tmpH = max(1, tmpH >> 1);
1276 tmpD = max(1, tmpD >> 1);
1279 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1280 TRACE("(%p) : Created volume texture %p\n", This, object);
1281 return WINED3D_OK;
1284 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1285 UINT Width, UINT Height, UINT Depth,
1286 DWORD Usage,
1287 WINED3DFORMAT Format, WINED3DPOOL Pool,
1288 IWineD3DVolume** ppVolume,
1289 HANDLE* pSharedHandle, IUnknown *parent) {
1291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1292 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1293 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1295 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1297 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1298 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1300 object->currentDesc.Width = Width;
1301 object->currentDesc.Height = Height;
1302 object->currentDesc.Depth = Depth;
1303 object->bytesPerPixel = formatDesc->bpp;
1305 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1306 object->lockable = TRUE;
1307 object->locked = FALSE;
1308 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1309 object->dirty = TRUE;
1311 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1314 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1315 UINT Levels, DWORD Usage,
1316 WINED3DFORMAT Format, WINED3DPOOL Pool,
1317 IWineD3DCubeTexture **ppCubeTexture,
1318 HANDLE *pSharedHandle, IUnknown *parent,
1319 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1322 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1323 unsigned int i, j;
1324 UINT tmpW;
1325 HRESULT hr;
1326 unsigned int pow2EdgeLength = EdgeLength;
1328 /* TODO: It should only be possible to create textures for formats
1329 that are reported as supported */
1330 if (WINED3DFMT_UNKNOWN >= Format) {
1331 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1332 return WINED3DERR_INVALIDCALL;
1335 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1336 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1338 TRACE("(%p) Create Cube Texture\n", This);
1340 /** Non-power2 support **/
1342 /* Find the nearest pow2 match */
1343 pow2EdgeLength = 1;
1344 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1346 object->edgeLength = EdgeLength;
1347 /* TODO: support for native non-power 2 */
1348 /* Precalculated scaling for 'faked' non power of two texture coords */
1349 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1351 /* Calculate levels for mip mapping */
1352 if (Levels == 0) {
1353 object->baseTexture.levels++;
1354 tmpW = EdgeLength;
1355 while (tmpW > 1) {
1356 tmpW = max(1, tmpW >> 1);
1357 object->baseTexture.levels++;
1359 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1362 /* Generate all the surfaces */
1363 tmpW = EdgeLength;
1364 for (i = 0; i < object->baseTexture.levels; i++) {
1366 /* Create the 6 faces */
1367 for (j = 0; j < 6; j++) {
1369 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1370 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1372 if(hr!= WINED3D_OK) {
1373 /* clean up */
1374 int k;
1375 int l;
1376 for (l = 0; l < j; l++) {
1377 IWineD3DSurface_Release(object->surfaces[j][i]);
1379 for (k = 0; k < i; k++) {
1380 for (l = 0; l < 6; l++) {
1381 IWineD3DSurface_Release(object->surfaces[l][j]);
1385 FIXME("(%p) Failed to create surface\n",object);
1386 HeapFree(GetProcessHeap(),0,object);
1387 *ppCubeTexture = NULL;
1388 return hr;
1390 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1391 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1393 tmpW = max(1, tmpW >> 1);
1396 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1397 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1398 return WINED3D_OK;
1401 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1403 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1405 if (NULL == ppQuery) {
1406 /* Just a check to see if we support this type of query */
1407 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1408 switch(Type) {
1409 case WINED3DQUERYTYPE_OCCLUSION:
1410 TRACE("(%p) occlusion query\n", This);
1411 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1412 hr = WINED3D_OK;
1413 else
1414 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1415 break;
1416 case WINED3DQUERYTYPE_VCACHE:
1417 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1418 case WINED3DQUERYTYPE_VERTEXSTATS:
1419 case WINED3DQUERYTYPE_EVENT:
1420 case WINED3DQUERYTYPE_TIMESTAMP:
1421 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1422 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1423 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1424 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1425 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1426 case WINED3DQUERYTYPE_PIXELTIMINGS:
1427 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1428 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1429 default:
1430 FIXME("(%p) Unhandled query type %d\n", This, Type);
1432 return hr;
1435 D3DCREATEOBJECTINSTANCE(object, Query)
1436 object->type = Type;
1437 /* allocated the 'extended' data based on the type of query requested */
1438 switch(Type){
1439 case D3DQUERYTYPE_OCCLUSION:
1440 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1441 TRACE("(%p) Allocating data for an occlusion query\n", This);
1442 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1443 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1444 break;
1446 case D3DQUERYTYPE_VCACHE:
1447 case D3DQUERYTYPE_RESOURCEMANAGER:
1448 case D3DQUERYTYPE_VERTEXSTATS:
1449 case D3DQUERYTYPE_EVENT:
1450 case D3DQUERYTYPE_TIMESTAMP:
1451 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1452 case D3DQUERYTYPE_TIMESTAMPFREQ:
1453 case D3DQUERYTYPE_PIPELINETIMINGS:
1454 case D3DQUERYTYPE_INTERFACETIMINGS:
1455 case D3DQUERYTYPE_VERTEXTIMINGS:
1456 case D3DQUERYTYPE_PIXELTIMINGS:
1457 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1458 case D3DQUERYTYPE_CACHEUTILIZATION:
1459 default:
1460 object->extendedData = 0;
1461 FIXME("(%p) Unhandled query type %d\n",This , Type);
1463 TRACE("(%p) : Created Query %p\n", This, object);
1464 return WINED3D_OK;
1467 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1468 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1469 IUnknown* parent,
1470 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1471 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1474 HDC hDc;
1475 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1476 int num;
1477 XVisualInfo template;
1478 GLXContext oldContext;
1479 Drawable oldDrawable;
1480 HRESULT hr = WINED3D_OK;
1482 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1484 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1485 * does a device hold a reference to a swap chain giving them a lifetime of the device
1486 * or does the swap chain notify the device of its destruction.
1487 *******************************/
1489 /* Check the params */
1490 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1491 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1492 return WINED3DERR_INVALIDCALL;
1493 } else if (*pPresentationParameters->BackBufferCount > 1) {
1494 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");
1497 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1499 /*********************
1500 * Lookup the window Handle and the relating X window handle
1501 ********************/
1503 /* Setup hwnd we are using, plus which display this equates to */
1504 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1505 if (!object->win_handle) {
1506 object->win_handle = This->createParms.hFocusWindow;
1509 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1510 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1511 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1512 return WINED3DERR_NOTAVAILABLE;
1514 hDc = GetDC(object->win_handle);
1515 object->display = get_display(hDc);
1516 ReleaseDC(object->win_handle, hDc);
1517 TRACE("Using a display of %p %p\n", object->display, hDc);
1519 if (NULL == object->display || NULL == hDc) {
1520 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1521 return WINED3DERR_NOTAVAILABLE;
1524 if (object->win == 0) {
1525 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1526 return WINED3DERR_NOTAVAILABLE;
1529 * Create an opengl context for the display visual
1530 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1531 * use different properties after that point in time. FIXME: How to handle when requested format
1532 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1533 * it chooses is identical to the one already being used!
1534 **********************************/
1536 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1537 ENTER_GL();
1539 /* Create a new context for this swapchain */
1540 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1541 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1542 (or the best possible if none is requested) */
1543 TRACE("Found x visual ID : %ld\n", template.visualid);
1545 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1546 if (NULL == object->visInfo) {
1547 ERR("cannot really get XVisual\n");
1548 LEAVE_GL();
1549 return WINED3DERR_NOTAVAILABLE;
1550 } else {
1551 int n, value;
1552 /* Write out some debug info about the visual/s */
1553 TRACE("Using x visual ID : %ld\n", template.visualid);
1554 TRACE(" visual info: %p\n", object->visInfo);
1555 TRACE(" num items : %d\n", num);
1556 for (n = 0;n < num; n++) {
1557 TRACE("=====item=====: %d\n", n + 1);
1558 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1559 TRACE(" screen : %d\n", object->visInfo[n].screen);
1560 TRACE(" depth : %u\n", object->visInfo[n].depth);
1561 TRACE(" class : %d\n", object->visInfo[n].class);
1562 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1563 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1564 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1565 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1566 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1567 /* log some extra glx info */
1568 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1569 TRACE(" gl_aux_buffers : %d\n", value);
1570 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1571 TRACE(" gl_buffer_size : %d\n", value);
1572 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1573 TRACE(" gl_red_size : %d\n", value);
1574 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1575 TRACE(" gl_green_size : %d\n", value);
1576 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1577 TRACE(" gl_blue_size : %d\n", value);
1578 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1579 TRACE(" gl_alpha_size : %d\n", value);
1580 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1581 TRACE(" gl_depth_size : %d\n", value);
1582 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1583 TRACE(" gl_stencil_size : %d\n", value);
1585 /* Now choose a simila visual ID*/
1587 #ifdef USE_CONTEXT_MANAGER
1589 /** TODO: use a context mamager **/
1590 #endif
1593 IWineD3DSwapChain *implSwapChain;
1594 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1595 /* The first time around we create the context that is shared with all other swapchains and render targets */
1596 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1597 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1598 } else {
1600 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1601 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1602 /* and create a new context with the implicit swapchains context as the shared context */
1603 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1604 IWineD3DSwapChain_Release(implSwapChain);
1608 /* Cleanup */
1609 XFree(object->visInfo);
1610 object->visInfo = NULL;
1612 LEAVE_GL();
1614 if (!object->glCtx) {
1615 ERR("Failed to create GLX context\n");
1616 return WINED3DERR_NOTAVAILABLE;
1617 } else {
1618 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1619 object->win_handle, object->glCtx, object->win, object->visInfo);
1622 /*********************
1623 * Windowed / Fullscreen
1624 *******************/
1627 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1628 * so we should really check to see if there is a fullscreen swapchain already
1629 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1630 **************************************/
1632 if (!*(pPresentationParameters->Windowed)) {
1634 DEVMODEW devmode;
1635 HDC hdc;
1636 int bpp = 0;
1638 /* Get info on the current display setup */
1639 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1640 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1641 DeleteDC(hdc);
1643 /* Change the display settings */
1644 memset(&devmode, 0, sizeof(DEVMODEW));
1645 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1646 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1647 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1648 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1649 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1650 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1652 /* Make popup window */
1653 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1654 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1655 *(pPresentationParameters->BackBufferWidth),
1656 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1658 /* For GetDisplayMode */
1659 This->ddraw_width = devmode.dmPelsWidth;
1660 This->ddraw_height = devmode.dmPelsHeight;
1661 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1665 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1666 * then the corresponding dimension of the client area of the hDeviceWindow
1667 * (or the focus window, if hDeviceWindow is NULL) is taken.
1668 **********************/
1670 if (*(pPresentationParameters->Windowed) &&
1671 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1672 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1674 RECT Rect;
1675 GetClientRect(object->win_handle, &Rect);
1677 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1678 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1679 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1681 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1682 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1683 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1687 /*********************
1688 * finish off parameter initialization
1689 *******************/
1691 /* Put the correct figures in the presentation parameters */
1692 TRACE("Coppying accross presentaion paraneters\n");
1693 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1694 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1695 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1696 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1697 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1698 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1699 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1700 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1701 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1702 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1703 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1704 object->presentParms.Flags = *(pPresentationParameters->Flags);
1705 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1706 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1709 /*********************
1710 * Create the back, front and stencil buffers
1711 *******************/
1713 TRACE("calling rendertarget CB\n");
1714 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1715 object->presentParms.BackBufferWidth,
1716 object->presentParms.BackBufferHeight,
1717 object->presentParms.BackBufferFormat,
1718 object->presentParms.MultiSampleType,
1719 object->presentParms.MultiSampleQuality,
1720 TRUE /* Lockable */,
1721 &object->frontBuffer,
1722 NULL /* pShared (always null)*/);
1723 if (object->frontBuffer != NULL)
1724 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1726 if(object->presentParms.BackBufferCount > 0) {
1727 int i;
1729 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1730 if(!object->backBuffer) {
1731 ERR("Out of memory\n");
1733 if (object->frontBuffer) {
1734 IUnknown *bufferParent;
1735 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1736 IUnknown_Release(bufferParent); /* once for the get parent */
1737 if (IUnknown_Release(bufferParent) > 0) {
1738 FIXME("(%p) Something's still holding the front buffer\n",This);
1741 HeapFree(GetProcessHeap(), 0, object);
1742 return E_OUTOFMEMORY;
1745 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1746 TRACE("calling rendertarget CB\n");
1747 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1748 object->presentParms.BackBufferWidth,
1749 object->presentParms.BackBufferHeight,
1750 object->presentParms.BackBufferFormat,
1751 object->presentParms.MultiSampleType,
1752 object->presentParms.MultiSampleQuality,
1753 TRUE /* Lockable */,
1754 &object->backBuffer[i],
1755 NULL /* pShared (always null)*/);
1756 if(hr == WINED3D_OK && object->backBuffer[i]) {
1757 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1758 } else {
1759 break;
1762 } else {
1763 object->backBuffer = NULL;
1766 if (object->backBuffer != NULL) {
1767 ENTER_GL();
1768 glDrawBuffer(GL_BACK);
1769 checkGLcall("glDrawBuffer(GL_BACK)");
1770 LEAVE_GL();
1771 } else {
1772 /* Single buffering - draw to front buffer */
1773 ENTER_GL();
1774 glDrawBuffer(GL_FRONT);
1775 checkGLcall("glDrawBuffer(GL_FRONT)");
1776 LEAVE_GL();
1779 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1780 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1781 TRACE("Creating depth stencil buffer\n");
1782 if (This->depthStencilBuffer == NULL ) {
1783 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1784 object->presentParms.BackBufferWidth,
1785 object->presentParms.BackBufferHeight,
1786 object->presentParms.AutoDepthStencilFormat,
1787 object->presentParms.MultiSampleType,
1788 object->presentParms.MultiSampleQuality,
1789 FALSE /* FIXME: Discard */,
1790 &This->depthStencilBuffer,
1791 NULL /* pShared (always null)*/ );
1792 if (This->depthStencilBuffer != NULL)
1793 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1796 /** TODO: A check on width, height and multisample types
1797 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1798 ****************************/
1799 object->wantsDepthStencilBuffer = TRUE;
1800 } else {
1801 object->wantsDepthStencilBuffer = FALSE;
1804 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1807 /*********************
1808 * init the default renderTarget management
1809 *******************/
1810 object->drawable = object->win;
1811 object->render_ctx = object->glCtx;
1813 if (hr == WINED3D_OK) {
1814 /*********************
1815 * Setup some defaults and clear down the buffers
1816 *******************/
1817 ENTER_GL();
1818 /** save current context and drawable **/
1819 oldContext = glXGetCurrentContext();
1820 oldDrawable = glXGetCurrentDrawable();
1822 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1823 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1824 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1826 checkGLcall("glXMakeCurrent");
1828 TRACE("Setting up the screen\n");
1829 /* Clear the screen */
1830 glClearColor(1.0, 0.0, 0.0, 0.0);
1831 checkGLcall("glClearColor");
1832 glClearIndex(0);
1833 glClearDepth(1);
1834 glClearStencil(0xffff);
1836 checkGLcall("glClear");
1838 glColor3f(1.0, 1.0, 1.0);
1839 checkGLcall("glColor3f");
1841 glEnable(GL_LIGHTING);
1842 checkGLcall("glEnable");
1844 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1845 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1847 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1848 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1850 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1851 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1853 /* switch back to the original context (if there was one)*/
1854 if (This->swapchains) {
1855 /** TODO: restore the context and drawable **/
1856 glXMakeCurrent(object->display, oldDrawable, oldContext);
1859 LEAVE_GL();
1861 TRACE("Set swapchain to %p\n", object);
1862 } else { /* something went wrong so clean up */
1863 IUnknown* bufferParent;
1864 if (object->frontBuffer) {
1866 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1867 IUnknown_Release(bufferParent); /* once for the get parent */
1868 if (IUnknown_Release(bufferParent) > 0) {
1869 FIXME("(%p) Something's still holding the front buffer\n",This);
1872 if (object->backBuffer) {
1873 int i;
1874 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1875 if(object->backBuffer[i]) {
1876 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1877 IUnknown_Release(bufferParent); /* once for the get parent */
1878 if (IUnknown_Release(bufferParent) > 0) {
1879 FIXME("(%p) Something's still holding the back buffer\n",This);
1883 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1884 object->backBuffer = NULL;
1886 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1887 /* Clean up the context */
1888 /* check that we are the current context first (we shouldn't be though!) */
1889 if (object->glCtx != 0) {
1890 if(glXGetCurrentContext() == object->glCtx) {
1891 glXMakeCurrent(object->display, None, NULL);
1893 glXDestroyContext(object->display, object->glCtx);
1895 HeapFree(GetProcessHeap(), 0, object);
1899 return hr;
1902 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1903 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1905 TRACE("(%p)\n", This);
1907 return This->NumberOfSwapChains;
1910 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1914 if(iSwapChain < This->NumberOfSwapChains) {
1915 *pSwapChain = This->swapchains[iSwapChain];
1916 IWineD3DSwapChain_AddRef(*pSwapChain);
1917 TRACE("(%p) returning %p\n", This, *pSwapChain);
1918 return WINED3D_OK;
1919 } else {
1920 TRACE("Swapchain out of range\n");
1921 *pSwapChain = NULL;
1922 return WINED3DERR_INVALIDCALL;
1926 /*****
1927 * Vertex Declaration
1928 *****/
1929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1931 IWineD3DVertexDeclarationImpl *object = NULL;
1932 HRESULT hr = WINED3D_OK;
1933 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1934 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1935 object->allFVF = 0;
1937 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1939 return hr;
1942 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1943 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1945 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1946 HRESULT hr = WINED3D_OK;
1947 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1948 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1950 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1952 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1953 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1954 if (pDeclaration != NULL) {
1955 IWineD3DVertexDeclaration *vertexDeclaration;
1956 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1957 if (WINED3D_OK == hr) {
1958 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1959 object->vertexDeclaration = vertexDeclaration;
1960 } else {
1961 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1962 IWineD3DVertexShader_Release(*ppVertexShader);
1963 return WINED3DERR_INVALIDCALL;
1967 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1969 if (WINED3D_OK != hr) {
1970 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1971 IWineD3DVertexShader_Release(*ppVertexShader);
1972 return WINED3DERR_INVALIDCALL;
1975 #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. */
1976 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1977 /* Foo */
1978 } else {
1979 /* Bar */
1982 #endif
1984 return WINED3D_OK;
1987 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1989 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1990 HRESULT hr = WINED3D_OK;
1992 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1993 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1994 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1995 if (WINED3D_OK == hr) {
1996 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1997 } else {
1998 WARN("(%p) : Failed to create pixel shader\n", This);
2001 return hr;
2004 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 IWineD3DPaletteImpl *object;
2007 HRESULT hr;
2008 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2010 /* Create the new object */
2011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2012 if(!object) {
2013 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2014 return E_OUTOFMEMORY;
2017 object->lpVtbl = &IWineD3DPalette_Vtbl;
2018 object->ref = 1;
2019 object->Flags = Flags;
2020 object->parent = Parent;
2021 object->wineD3DDevice = This;
2022 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2024 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2026 if(!object->hpal) {
2027 HeapFree( GetProcessHeap(), 0, object);
2028 return E_OUTOFMEMORY;
2031 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2032 if(FAILED(hr)) {
2033 IWineD3DPalette_Release((IWineD3DPalette *) object);
2034 return hr;
2037 *Palette = (IWineD3DPalette *) object;
2039 return WINED3D_OK;
2042 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2044 IWineD3DSwapChainImpl *swapchain;
2046 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2047 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2049 /* TODO: Test if OpenGL is compiled in and loaded */
2051 /* Setup the implicit swapchain */
2052 TRACE("Creating implicit swapchain\n");
2053 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2054 WARN("Failed to create implicit swapchain\n");
2055 return WINED3DERR_INVALIDCALL;
2058 This->NumberOfSwapChains = 1;
2059 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2060 if(!This->swapchains) {
2061 ERR("Out of memory!\n");
2062 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2063 return E_OUTOFMEMORY;
2065 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2067 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2068 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2069 This->renderTarget = swapchain->backBuffer[0];
2071 else {
2072 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2073 This->renderTarget = swapchain->frontBuffer;
2075 IWineD3DSurface_AddRef(This->renderTarget);
2076 /* Depth Stencil support */
2077 This->stencilBufferTarget = This->depthStencilBuffer;
2078 if (NULL != This->stencilBufferTarget) {
2079 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2082 /* Set up some starting GL setup */
2083 ENTER_GL();
2085 * Initialize openGL extension related variables
2086 * with Default values
2089 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2090 /* Setup all the devices defaults */
2091 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2092 #if 0
2093 IWineD3DImpl_CheckGraphicsMemory();
2094 #endif
2095 LEAVE_GL();
2097 /* Initialize our list of GLSL programs */
2098 list_init(&This->glsl_shader_progs);
2100 { /* Set a default viewport */
2101 D3DVIEWPORT9 vp;
2102 vp.X = 0;
2103 vp.Y = 0;
2104 vp.Width = *(pPresentationParameters->BackBufferWidth);
2105 vp.Height = *(pPresentationParameters->BackBufferHeight);
2106 vp.MinZ = 0.0f;
2107 vp.MaxZ = 1.0f;
2108 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2111 /* Initialize the current view state */
2112 This->modelview_valid = 1;
2113 This->proj_valid = 0;
2114 This->view_ident = 1;
2115 This->last_was_rhw = 0;
2116 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2117 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2119 /* Clear the screen */
2120 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2122 This->d3d_initialized = TRUE;
2123 return WINED3D_OK;
2126 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2128 int sampler;
2129 IUnknown* stencilBufferParent;
2130 IUnknown* swapChainParent;
2131 uint i;
2132 TRACE("(%p)\n", This);
2134 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2136 /* Delete the mouse cursor texture */
2137 if(This->cursorTexture) {
2138 ENTER_GL();
2139 glDeleteTextures(1, &This->cursorTexture);
2140 LEAVE_GL();
2141 This->cursorTexture = 0;
2144 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2145 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2148 /* Release the buffers (with sanity checks)*/
2149 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2150 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2151 if(This->depthStencilBuffer != This->stencilBufferTarget)
2152 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2154 This->stencilBufferTarget = NULL;
2156 TRACE("Releasing the render target at %p\n", This->renderTarget);
2157 if(IWineD3DSurface_Release(This->renderTarget) >0){
2158 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2160 TRACE("Setting rendertarget to NULL\n");
2161 This->renderTarget = NULL;
2163 if (This->depthStencilBuffer) {
2164 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2165 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2166 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2167 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2169 This->depthStencilBuffer = NULL;
2172 for(i=0; i < This->NumberOfSwapChains; i++) {
2173 TRACE("Releasing the implicit swapchain %d\n", i);
2174 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2175 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2176 IUnknown_Release(swapChainParent); /* once for the get parent */
2177 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2178 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2182 HeapFree(GetProcessHeap(), 0, This->swapchains);
2183 This->swapchains = NULL;
2184 This->NumberOfSwapChains = 0;
2186 This->d3d_initialized = FALSE;
2187 return WINED3D_OK;
2190 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2193 DEVMODEW DevModeW;
2194 int i;
2195 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2197 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2199 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2200 /* Ignore some modes if a description was passed */
2201 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2202 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2203 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2205 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2207 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2208 return D3D_OK;
2211 return D3D_OK;
2214 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2215 DEVMODEW devmode;
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2217 LONG ret;
2218 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2220 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2222 /* Resize the screen even without a window:
2223 * The app could have unset it with SetCooperativeLevel, but not called
2224 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2225 * but we don't have any hwnd
2228 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2229 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2230 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2231 devmode.dmPelsWidth = pMode->Width;
2232 devmode.dmPelsHeight = pMode->Height;
2234 devmode.dmDisplayFrequency = pMode->RefreshRate;
2235 if (pMode->RefreshRate != 0) {
2236 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2239 /* Only change the mode if necessary */
2240 if( (This->ddraw_width == pMode->Width) &&
2241 (This->ddraw_height == pMode->Height) &&
2242 (This->ddraw_format == pMode->Format) &&
2243 (pMode->RefreshRate == 0) ) {
2244 return D3D_OK;
2247 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2248 if (ret != DISP_CHANGE_SUCCESSFUL) {
2249 if(devmode.dmDisplayFrequency != 0) {
2250 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2251 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2252 devmode.dmDisplayFrequency = 0;
2253 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2255 if(ret != DISP_CHANGE_SUCCESSFUL) {
2256 return DDERR_INVALIDMODE;
2260 /* Store the new values */
2261 This->ddraw_width = pMode->Width;
2262 This->ddraw_height = pMode->Height;
2263 This->ddraw_format = pMode->Format;
2265 /* Only do this with a window of course */
2266 if(This->ddraw_window)
2267 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2269 return WINED3D_OK;
2272 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 *ppD3D= This->wineD3D;
2275 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2276 IWineD3D_AddRef(*ppD3D);
2277 return WINED3D_OK;
2280 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2281 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2282 * Into the video ram as possible and seeing how many fit
2283 * you can also get the correct initial value from nvidia and ATI's driver via X
2284 * texture memory is video memory + AGP memory
2285 *******************/
2286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2287 static BOOL showfixmes = TRUE;
2288 if (showfixmes) {
2289 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2290 (wined3d_settings.emulated_textureram/(1024*1024)),
2291 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2292 showfixmes = FALSE;
2294 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2295 (wined3d_settings.emulated_textureram/(1024*1024)),
2296 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2297 /* return simulated texture memory left */
2298 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2303 /*****
2304 * Get / Set FVF
2305 *****/
2306 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 HRESULT hr = WINED3D_OK;
2310 /* Update the current state block */
2311 This->updateStateBlock->fvf = fvf;
2312 This->updateStateBlock->changed.fvf = TRUE;
2313 This->updateStateBlock->set.fvf = TRUE;
2315 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2316 return hr;
2320 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2322 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2323 *pfvf = This->stateBlock->fvf;
2324 return WINED3D_OK;
2327 /*****
2328 * Get / Set Stream Source
2329 *****/
2330 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2332 IWineD3DVertexBuffer *oldSrc;
2334 /**TODO: instance and index data, see
2335 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2337 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2338 **************/
2340 /* D3d9 only, but shouldn't hurt d3d8 */
2341 UINT streamFlags;
2343 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2344 if (streamFlags) {
2345 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2346 FIXME("stream index data not supported\n");
2348 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2349 FIXME("stream instance data not supported\n");
2353 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2355 if (StreamNumber >= MAX_STREAMS) {
2356 WARN("Stream out of range %d\n", StreamNumber);
2357 return WINED3DERR_INVALIDCALL;
2360 oldSrc = This->stateBlock->streamSource[StreamNumber];
2361 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2363 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2364 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2365 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2366 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2367 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2368 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2370 /* Handle recording of state blocks */
2371 if (This->isRecordingState) {
2372 TRACE("Recording... not performing anything\n");
2373 return WINED3D_OK;
2376 /* Same stream object: no action */
2377 if (oldSrc == pStreamData)
2378 return WINED3D_OK;
2380 /* Need to do a getParent and pass the reffs up */
2381 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2382 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2383 so for now, just count internally */
2384 if (pStreamData != NULL) {
2385 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2386 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2387 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2389 vbImpl->stream = StreamNumber;
2390 vbImpl->Flags |= VBFLAG_STREAM;
2391 IWineD3DVertexBuffer_AddRef(pStreamData);
2393 if (oldSrc != NULL) {
2394 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2395 IWineD3DVertexBuffer_Release(oldSrc);
2398 return WINED3D_OK;
2401 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 UINT streamFlags;
2405 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2406 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2409 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2410 if (streamFlags) {
2411 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2412 FIXME("stream index data not supported\n");
2414 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2415 FIXME("stream instance data not supported\n");
2419 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2421 if (StreamNumber >= MAX_STREAMS) {
2422 WARN("Stream out of range %d\n", StreamNumber);
2423 return WINED3DERR_INVALIDCALL;
2425 *pStream = This->stateBlock->streamSource[StreamNumber];
2426 *pStride = This->stateBlock->streamStride[StreamNumber];
2427 if (pOffset) {
2428 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2431 if (*pStream == NULL) {
2432 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2433 return WINED3DERR_INVALIDCALL;
2436 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2437 return WINED3D_OK;
2440 /*Should be quite easy, just an extension of vertexdata
2441 ref...
2442 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2444 The divider is a bit odd though
2446 VertexOffset = StartVertex / Divider * StreamStride +
2447 VertexIndex / Divider * StreamStride + StreamOffset
2450 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2454 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2456 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2457 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2458 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2460 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2461 FIXME("Stream indexing not fully supported\n");
2464 return WINED3D_OK;
2467 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2471 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2473 TRACE("(%p) : returning %d\n", This, *Divider);
2475 return WINED3D_OK;
2478 /*****
2479 * Get / Set & Multiply Transform
2480 *****/
2481 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484 /* Most of this routine, comments included copied from ddraw tree initially: */
2485 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2487 /* Handle recording of state blocks */
2488 if (This->isRecordingState) {
2489 TRACE("Recording... not performing anything\n");
2490 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2491 This->updateStateBlock->set.transform[d3dts] = TRUE;
2492 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2493 return WINED3D_OK;
2497 * If the new matrix is the same as the current one,
2498 * we cut off any further processing. this seems to be a reasonable
2499 * optimization because as was noticed, some apps (warcraft3 for example)
2500 * tend towards setting the same matrix repeatedly for some reason.
2502 * From here on we assume that the new matrix is different, wherever it matters.
2504 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2505 TRACE("The app is setting the same matrix over again\n");
2506 return WINED3D_OK;
2507 } else {
2508 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2512 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2513 where ViewMat = Camera space, WorldMat = world space.
2515 In OpenGL, camera and world space is combined into GL_MODELVIEW
2516 matrix. The Projection matrix stay projection matrix.
2519 /* Capture the times we can just ignore the change for now */
2520 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2521 This->modelview_valid = FALSE;
2522 return WINED3D_OK;
2524 } else if (d3dts == WINED3DTS_PROJECTION) {
2525 This->proj_valid = FALSE;
2526 return WINED3D_OK;
2528 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2529 /* Indexed Vertex Blending Matrices 256 -> 511 */
2530 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2531 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2532 return WINED3D_OK;
2535 /* Now we really are going to have to change a matrix */
2536 ENTER_GL();
2538 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2539 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2540 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2541 unsigned int k;
2543 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2544 * NOTE: We have to reset the positions even if the light/plane is not currently
2545 * enabled, since the call to enable it will not reset the position.
2546 * NOTE2: Apparently texture transforms do NOT need reapplying
2549 PLIGHTINFOEL *lightChain = NULL;
2550 This->modelview_valid = FALSE;
2551 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2553 glMatrixMode(GL_MODELVIEW);
2554 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2555 glPushMatrix();
2556 glLoadMatrixf((float *)lpmatrix);
2557 checkGLcall("glLoadMatrixf(...)");
2559 /* Reset lights */
2560 lightChain = This->stateBlock->lights;
2561 while (lightChain && lightChain->glIndex != -1) {
2562 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2563 checkGLcall("glLightfv posn");
2564 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2565 checkGLcall("glLightfv dirn");
2566 lightChain = lightChain->next;
2569 /* Reset Clipping Planes if clipping is enabled */
2570 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2571 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2572 checkGLcall("glClipPlane");
2574 glPopMatrix();
2576 } else { /* What was requested!?? */
2577 WARN("invalid matrix specified: %i\n", d3dts);
2580 /* Release lock, all done */
2581 LEAVE_GL();
2582 return WINED3D_OK;
2585 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2588 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2589 return WINED3D_OK;
2592 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2593 D3DMATRIX *mat = NULL;
2594 D3DMATRIX temp;
2596 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2597 * below means it will be recorded in a state block change, but it
2598 * works regardless where it is recorded.
2599 * If this is found to be wrong, change to StateBlock.
2601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2604 if (State < HIGHEST_TRANSFORMSTATE)
2606 mat = &This->updateStateBlock->transforms[State];
2607 } else {
2608 FIXME("Unhandled transform state!!\n");
2611 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2613 /* Apply change via set transform - will reapply to eg. lights this way */
2614 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2617 /*****
2618 * Get / Set Light
2619 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2620 *****/
2621 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2622 you can reference any indexes you want as long as that number max are enabled at any
2623 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2624 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2625 but when recording, just build a chain pretty much of commands to be replayed. */
2627 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2628 float rho;
2629 PLIGHTINFOEL *object, *temp;
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2634 /* If recording state block, just add to end of lights chain */
2635 if (This->isRecordingState) {
2636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2637 if (NULL == object) {
2638 return WINED3DERR_OUTOFVIDEOMEMORY;
2640 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2641 object->OriginalIndex = Index;
2642 object->glIndex = -1;
2643 object->changed = TRUE;
2645 /* Add to the END of the chain of lights changes to be replayed */
2646 if (This->updateStateBlock->lights == NULL) {
2647 This->updateStateBlock->lights = object;
2648 } else {
2649 temp = This->updateStateBlock->lights;
2650 while (temp->next != NULL) temp=temp->next;
2651 temp->next = object;
2653 TRACE("Recording... not performing anything more\n");
2654 return WINED3D_OK;
2657 /* Ok, not recording any longer so do real work */
2658 object = This->stateBlock->lights;
2659 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2661 /* If we didn't find it in the list of lights, time to add it */
2662 if (object == NULL) {
2663 PLIGHTINFOEL *insertAt,*prevPos;
2665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2666 if (NULL == object) {
2667 return WINED3DERR_OUTOFVIDEOMEMORY;
2669 object->OriginalIndex = Index;
2670 object->glIndex = -1;
2672 /* Add it to the front of list with the idea that lights will be changed as needed
2673 BUT after any lights currently assigned GL indexes */
2674 insertAt = This->stateBlock->lights;
2675 prevPos = NULL;
2676 while (insertAt != NULL && insertAt->glIndex != -1) {
2677 prevPos = insertAt;
2678 insertAt = insertAt->next;
2681 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2682 This->stateBlock->lights = object;
2683 } else if (insertAt == NULL) { /* End of list */
2684 prevPos->next = object;
2685 object->prev = prevPos;
2686 } else { /* Middle of chain */
2687 if (prevPos == NULL) {
2688 This->stateBlock->lights = object;
2689 } else {
2690 prevPos->next = object;
2692 object->prev = prevPos;
2693 object->next = insertAt;
2694 insertAt->prev = object;
2698 /* Initialize the object */
2699 TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2700 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2701 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2702 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2703 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2704 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2705 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2707 /* Save away the information */
2708 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2710 switch (pLight->Type) {
2711 case D3DLIGHT_POINT:
2712 /* Position */
2713 object->lightPosn[0] = pLight->Position.x;
2714 object->lightPosn[1] = pLight->Position.y;
2715 object->lightPosn[2] = pLight->Position.z;
2716 object->lightPosn[3] = 1.0f;
2717 object->cutoff = 180.0f;
2718 /* FIXME: Range */
2719 break;
2721 case D3DLIGHT_DIRECTIONAL:
2722 /* Direction */
2723 object->lightPosn[0] = -pLight->Direction.x;
2724 object->lightPosn[1] = -pLight->Direction.y;
2725 object->lightPosn[2] = -pLight->Direction.z;
2726 object->lightPosn[3] = 0.0;
2727 object->exponent = 0.0f;
2728 object->cutoff = 180.0f;
2729 break;
2731 case D3DLIGHT_SPOT:
2732 /* Position */
2733 object->lightPosn[0] = pLight->Position.x;
2734 object->lightPosn[1] = pLight->Position.y;
2735 object->lightPosn[2] = pLight->Position.z;
2736 object->lightPosn[3] = 1.0;
2738 /* Direction */
2739 object->lightDirn[0] = pLight->Direction.x;
2740 object->lightDirn[1] = pLight->Direction.y;
2741 object->lightDirn[2] = pLight->Direction.z;
2742 object->lightDirn[3] = 1.0;
2745 * opengl-ish and d3d-ish spot lights use too different models for the
2746 * light "intensity" as a function of the angle towards the main light direction,
2747 * so we only can approximate very roughly.
2748 * however spot lights are rather rarely used in games (if ever used at all).
2749 * furthermore if still used, probably nobody pays attention to such details.
2751 if (pLight->Falloff == 0) {
2752 rho = 6.28f;
2753 } else {
2754 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2756 if (rho < 0.0001) rho = 0.0001f;
2757 object->exponent = -0.3/log(cos(rho/2));
2758 object->cutoff = pLight->Phi*90/M_PI;
2760 /* FIXME: Range */
2761 break;
2763 default:
2764 FIXME("Unrecognized light type %d\n", pLight->Type);
2767 /* Update the live definitions if the light is currently assigned a glIndex */
2768 if (object->glIndex != -1) {
2769 setup_light(iface, object->glIndex, object);
2771 return WINED3D_OK;
2774 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2775 PLIGHTINFOEL *lightInfo = NULL;
2776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2777 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2779 /* Locate the light in the live lights */
2780 lightInfo = This->stateBlock->lights;
2781 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2783 if (lightInfo == NULL) {
2784 TRACE("Light information requested but light not defined\n");
2785 return WINED3DERR_INVALIDCALL;
2788 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2789 return WINED3D_OK;
2792 /*****
2793 * Get / Set Light Enable
2794 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2795 *****/
2796 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2797 PLIGHTINFOEL *lightInfo = NULL;
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2801 /* Tests show true = 128...not clear why */
2803 Enable = Enable? 128: 0;
2805 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2806 if (This->isRecordingState) {
2807 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2808 if (NULL == lightInfo) {
2809 return WINED3DERR_OUTOFVIDEOMEMORY;
2811 lightInfo->OriginalIndex = Index;
2812 lightInfo->glIndex = -1;
2813 lightInfo->enabledChanged = TRUE;
2814 lightInfo->lightEnabled = Enable;
2816 /* Add to the END of the chain of lights changes to be replayed */
2817 if (This->updateStateBlock->lights == NULL) {
2818 This->updateStateBlock->lights = lightInfo;
2819 } else {
2820 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2821 while (temp->next != NULL) temp=temp->next;
2822 temp->next = lightInfo;
2824 TRACE("Recording... not performing anything more\n");
2825 return WINED3D_OK;
2828 /* Not recording... So, locate the light in the live lights */
2829 lightInfo = This->stateBlock->lights;
2830 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2832 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2833 if (lightInfo == NULL) {
2835 TRACE("Light enabled requested but light not defined, so defining one!\n");
2836 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2838 /* Search for it again! Should be fairly quick as near head of list */
2839 lightInfo = This->stateBlock->lights;
2840 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2841 if (lightInfo == NULL) {
2842 FIXME("Adding default lights has failed dismally\n");
2843 return WINED3DERR_INVALIDCALL;
2847 /* OK, we now have a light... */
2848 if (Enable == FALSE) {
2850 /* If we are disabling it, check it was enabled, and
2851 still only do something if it has assigned a glIndex (which it should have!) */
2852 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2853 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2854 ENTER_GL();
2855 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2856 checkGLcall("glDisable GL_LIGHT0+Index");
2857 LEAVE_GL();
2858 } else {
2859 TRACE("Nothing to do as light was not enabled\n");
2861 lightInfo->lightEnabled = Enable;
2862 } else {
2864 /* We are enabling it. If it is enabled, it's really simple */
2865 if (lightInfo->lightEnabled) {
2866 /* nop */
2867 TRACE("Nothing to do as light was enabled\n");
2869 /* If it already has a glIndex, it's still simple */
2870 } else if (lightInfo->glIndex != -1) {
2871 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2872 lightInfo->lightEnabled = Enable;
2873 ENTER_GL();
2874 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2875 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2876 LEAVE_GL();
2878 /* Otherwise got to find space - lights are ordered gl indexes first */
2879 } else {
2880 PLIGHTINFOEL *bsf = NULL;
2881 PLIGHTINFOEL *pos = This->stateBlock->lights;
2882 PLIGHTINFOEL *prev = NULL;
2883 int Index= 0;
2884 int glIndex = -1;
2886 /* Try to minimize changes as much as possible */
2887 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2889 /* Try to remember which index can be replaced if necessary */
2890 if (bsf==NULL && pos->lightEnabled == FALSE) {
2891 /* Found a light we can replace, save as best replacement */
2892 bsf = pos;
2895 /* Step to next space */
2896 prev = pos;
2897 pos = pos->next;
2898 Index ++;
2901 /* If we have too many active lights, fail the call */
2902 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2903 FIXME("Program requests too many concurrent lights\n");
2904 return WINED3DERR_INVALIDCALL;
2906 /* If we have allocated all lights, but not all are enabled,
2907 reuse one which is not enabled */
2908 } else if (Index == This->maxConcurrentLights) {
2909 /* use bsf - Simply swap the new light and the BSF one */
2910 PLIGHTINFOEL *bsfNext = bsf->next;
2911 PLIGHTINFOEL *bsfPrev = bsf->prev;
2913 /* Sort out ends */
2914 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2915 if (bsf->prev != NULL) {
2916 bsf->prev->next = lightInfo;
2917 } else {
2918 This->stateBlock->lights = lightInfo;
2921 /* If not side by side, lots of chains to update */
2922 if (bsf->next != lightInfo) {
2923 lightInfo->prev->next = bsf;
2924 bsf->next->prev = lightInfo;
2925 bsf->next = lightInfo->next;
2926 bsf->prev = lightInfo->prev;
2927 lightInfo->next = bsfNext;
2928 lightInfo->prev = bsfPrev;
2930 } else {
2931 /* Simple swaps */
2932 bsf->prev = lightInfo;
2933 bsf->next = lightInfo->next;
2934 lightInfo->next = bsf;
2935 lightInfo->prev = bsfPrev;
2939 /* Update states */
2940 glIndex = bsf->glIndex;
2941 bsf->glIndex = -1;
2942 lightInfo->glIndex = glIndex;
2943 lightInfo->lightEnabled = Enable;
2945 /* Finally set up the light in gl itself */
2946 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2947 ENTER_GL();
2948 setup_light(iface, glIndex, lightInfo);
2949 glEnable(GL_LIGHT0 + glIndex);
2950 checkGLcall("glEnable GL_LIGHT0 new setup");
2951 LEAVE_GL();
2953 /* If we reached the end of the allocated lights, with space in the
2954 gl lights, setup a new light */
2955 } else if (pos->glIndex == -1) {
2957 /* We reached the end of the allocated gl lights, so already
2958 know the index of the next one! */
2959 glIndex = Index;
2960 lightInfo->glIndex = glIndex;
2961 lightInfo->lightEnabled = Enable;
2963 /* In an ideal world, it's already in the right place */
2964 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2965 /* No need to move it */
2966 } else {
2967 /* Remove this light from the list */
2968 lightInfo->prev->next = lightInfo->next;
2969 if (lightInfo->next != NULL) {
2970 lightInfo->next->prev = lightInfo->prev;
2973 /* Add in at appropriate place (inbetween prev and pos) */
2974 lightInfo->prev = prev;
2975 lightInfo->next = pos;
2976 if (prev == NULL) {
2977 This->stateBlock->lights = lightInfo;
2978 } else {
2979 prev->next = lightInfo;
2981 if (pos != NULL) {
2982 pos->prev = lightInfo;
2986 /* Finally set up the light in gl itself */
2987 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2988 ENTER_GL();
2989 setup_light(iface, glIndex, lightInfo);
2990 glEnable(GL_LIGHT0 + glIndex);
2991 checkGLcall("glEnable GL_LIGHT0 new setup");
2992 LEAVE_GL();
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3002 PLIGHTINFOEL *lightInfo = NULL;
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : for idx(%ld)\n", This, Index);
3006 /* Locate the light in the live lights */
3007 lightInfo = This->stateBlock->lights;
3008 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3010 if (lightInfo == NULL) {
3011 TRACE("Light enabled state requested but light not defined\n");
3012 return WINED3DERR_INVALIDCALL;
3014 *pEnable = lightInfo->lightEnabled;
3015 return WINED3D_OK;
3018 /*****
3019 * Get / Set Clip Planes
3020 *****/
3021 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3023 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3025 /* Validate Index */
3026 if (Index >= GL_LIMITS(clipplanes)) {
3027 TRACE("Application has requested clipplane this device doesn't support\n");
3028 return WINED3DERR_INVALIDCALL;
3031 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3032 This->updateStateBlock->set.clipplane[Index] = TRUE;
3033 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3034 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3035 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3036 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3038 /* Handle recording of state blocks */
3039 if (This->isRecordingState) {
3040 TRACE("Recording... not performing anything\n");
3041 return WINED3D_OK;
3044 /* Apply it */
3046 ENTER_GL();
3048 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3049 glMatrixMode(GL_MODELVIEW);
3050 glPushMatrix();
3051 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3053 TRACE("Clipplane [%f,%f,%f,%f]\n",
3054 This->updateStateBlock->clipplane[Index][0],
3055 This->updateStateBlock->clipplane[Index][1],
3056 This->updateStateBlock->clipplane[Index][2],
3057 This->updateStateBlock->clipplane[Index][3]);
3058 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3059 checkGLcall("glClipPlane");
3061 glPopMatrix();
3062 LEAVE_GL();
3064 return WINED3D_OK;
3067 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 TRACE("(%p) : for idx %ld\n", This, Index);
3071 /* Validate Index */
3072 if (Index >= GL_LIMITS(clipplanes)) {
3073 TRACE("Application has requested clipplane this device doesn't support\n");
3074 return WINED3DERR_INVALIDCALL;
3077 pPlane[0] = This->stateBlock->clipplane[Index][0];
3078 pPlane[1] = This->stateBlock->clipplane[Index][1];
3079 pPlane[2] = This->stateBlock->clipplane[Index][2];
3080 pPlane[3] = This->stateBlock->clipplane[Index][3];
3081 return WINED3D_OK;
3084 /*****
3085 * Get / Set Clip Plane Status
3086 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3087 *****/
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3090 FIXME("(%p) : stub\n", This);
3091 if (NULL == pClipStatus) {
3092 return WINED3DERR_INVALIDCALL;
3094 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3095 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 FIXME("(%p) : stub\n", This);
3102 if (NULL == pClipStatus) {
3103 return WINED3DERR_INVALIDCALL;
3105 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3106 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3107 return WINED3D_OK;
3110 /*****
3111 * Get / Set Material
3112 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3113 *****/
3114 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 This->updateStateBlock->changed.material = TRUE;
3118 This->updateStateBlock->set.material = TRUE;
3119 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3121 /* Handle recording of state blocks */
3122 if (This->isRecordingState) {
3123 TRACE("Recording... not performing anything\n");
3124 return WINED3D_OK;
3127 ENTER_GL();
3128 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3129 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3130 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3131 pMaterial->Ambient.b, pMaterial->Ambient.a);
3132 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3133 pMaterial->Specular.b, pMaterial->Specular.a);
3134 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3135 pMaterial->Emissive.b, pMaterial->Emissive.a);
3136 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3138 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3139 checkGLcall("glMaterialfv(GL_AMBIENT)");
3140 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3141 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3143 /* Only change material color if specular is enabled, otherwise it is set to black */
3144 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3145 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3146 checkGLcall("glMaterialfv(GL_SPECULAR");
3147 } else {
3148 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3149 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3150 checkGLcall("glMaterialfv(GL_SPECULAR");
3152 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3153 checkGLcall("glMaterialfv(GL_EMISSION)");
3154 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3155 checkGLcall("glMaterialf(GL_SHININESS");
3157 LEAVE_GL();
3158 return WINED3D_OK;
3161 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3164 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3165 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3166 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3167 pMaterial->Ambient.b, pMaterial->Ambient.a);
3168 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3169 pMaterial->Specular.b, pMaterial->Specular.a);
3170 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3171 pMaterial->Emissive.b, pMaterial->Emissive.a);
3172 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3174 return WINED3D_OK;
3177 /*****
3178 * Get / Set Indices
3179 *****/
3180 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3181 UINT BaseVertexIndex) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 IWineD3DIndexBuffer *oldIdxs;
3185 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3186 oldIdxs = This->updateStateBlock->pIndexData;
3188 This->updateStateBlock->changed.indices = TRUE;
3189 This->updateStateBlock->set.indices = TRUE;
3190 This->updateStateBlock->pIndexData = pIndexData;
3191 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3193 /* Handle recording of state blocks */
3194 if (This->isRecordingState) {
3195 TRACE("Recording... not performing anything\n");
3196 return WINED3D_OK;
3199 if (NULL != pIndexData) {
3200 IWineD3DIndexBuffer_AddRef(pIndexData);
3202 if (NULL != oldIdxs) {
3203 IWineD3DIndexBuffer_Release(oldIdxs);
3205 return WINED3D_OK;
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 *ppIndexData = This->stateBlock->pIndexData;
3213 /* up ref count on ppindexdata */
3214 if (*ppIndexData) {
3215 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3216 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3217 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3218 }else{
3219 TRACE("(%p) No index data set\n", This);
3221 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3223 return WINED3D_OK;
3226 /*****
3227 * Get / Set Viewports
3228 *****/
3229 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 TRACE("(%p)\n", This);
3233 This->updateStateBlock->changed.viewport = TRUE;
3234 This->updateStateBlock->set.viewport = TRUE;
3235 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3237 /* Handle recording of state blocks */
3238 if (This->isRecordingState) {
3239 TRACE("Recording... not performing anything\n");
3240 return WINED3D_OK;
3242 This->viewport_changed = TRUE;
3244 ENTER_GL();
3246 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3247 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3249 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3250 checkGLcall("glDepthRange");
3251 /* Note: GL requires lower left, DirectX supplies upper left */
3252 /* TODO: replace usage of renderTarget with context management */
3253 glViewport(pViewport->X,
3254 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3255 pViewport->Width, pViewport->Height);
3257 checkGLcall("glViewport");
3259 LEAVE_GL();
3261 return WINED3D_OK;
3265 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 TRACE("(%p)\n", This);
3268 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3269 return WINED3D_OK;
3272 static void renderstate_stencil_twosided(
3273 IWineD3DDeviceImpl *This,
3274 GLint face,
3275 GLint func,
3276 GLint ref,
3277 GLuint mask,
3278 GLint stencilFail,
3279 GLint depthFail,
3280 GLint stencilPass ) {
3281 #if 0 /* Don't use OpenGL 2.0 calls for now */
3282 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3283 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3284 checkGLcall("glStencilFuncSeparate(...)");
3285 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3286 checkGLcall("glStencilOpSeparate(...)");
3288 else
3289 #endif
3290 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3291 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3292 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3293 GL_EXTCALL(glActiveStencilFaceEXT(face));
3294 checkGLcall("glActiveStencilFaceEXT(...)");
3295 glStencilFunc(func, ref, mask);
3296 checkGLcall("glStencilFunc(...)");
3297 glStencilOp(stencilFail, depthFail, stencilPass);
3298 checkGLcall("glStencilOp(...)");
3299 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3300 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3301 checkGLcall("glStencilFuncSeparateATI(...)");
3302 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3303 checkGLcall("glStencilOpSeparateATI(...)");
3304 } else {
3305 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3309 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3310 DWORD onesided_enable = FALSE;
3311 DWORD twosided_enable = FALSE;
3312 GLint func = GL_ALWAYS;
3313 GLint func_ccw = GL_ALWAYS;
3314 GLint ref = 0;
3315 GLuint mask = 0;
3316 GLint stencilFail = GL_KEEP;
3317 GLint depthFail = GL_KEEP;
3318 GLint stencilPass = GL_KEEP;
3319 GLint stencilFail_ccw = GL_KEEP;
3320 GLint depthFail_ccw = GL_KEEP;
3321 GLint stencilPass_ccw = GL_KEEP;
3323 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3324 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3325 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3326 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3327 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3328 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3329 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3330 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3331 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3332 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3333 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3334 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3335 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3336 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3337 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3338 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3339 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3340 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3341 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3342 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3343 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3344 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3345 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3346 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3348 switch(State) {
3349 case WINED3DRS_STENCILENABLE :
3350 onesided_enable = Value;
3351 break;
3352 case WINED3DRS_TWOSIDEDSTENCILMODE :
3353 twosided_enable = Value;
3354 break;
3355 case WINED3DRS_STENCILFUNC :
3356 func = StencilFunc(Value);
3357 break;
3358 case WINED3DRS_CCW_STENCILFUNC :
3359 func_ccw = StencilFunc(Value);
3360 break;
3361 case WINED3DRS_STENCILREF :
3362 ref = Value;
3363 break;
3364 case WINED3DRS_STENCILMASK :
3365 mask = Value;
3366 break;
3367 case WINED3DRS_STENCILFAIL :
3368 stencilFail = StencilOp(Value);
3369 break;
3370 case WINED3DRS_STENCILZFAIL :
3371 depthFail = StencilOp(Value);
3372 break;
3373 case WINED3DRS_STENCILPASS :
3374 stencilPass = StencilOp(Value);
3375 break;
3376 case WINED3DRS_CCW_STENCILFAIL :
3377 stencilFail_ccw = StencilOp(Value);
3378 break;
3379 case WINED3DRS_CCW_STENCILZFAIL :
3380 depthFail_ccw = StencilOp(Value);
3381 break;
3382 case WINED3DRS_CCW_STENCILPASS :
3383 stencilPass_ccw = StencilOp(Value);
3384 break;
3385 default :
3386 ERR("This should not happen!");
3389 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3390 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3391 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3392 onesided_enable, twosided_enable, ref, mask,
3393 func, stencilFail, depthFail, stencilPass,
3394 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3396 if (twosided_enable) {
3397 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3398 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3399 } else {
3400 if (onesided_enable) {
3401 glEnable(GL_STENCIL_TEST);
3402 checkGLcall("glEnable GL_STENCIL_TEST");
3403 glStencilFunc(func, ref, mask);
3404 checkGLcall("glStencilFunc(...)");
3405 glStencilOp(stencilFail, depthFail, stencilPass);
3406 checkGLcall("glStencilOp(...)");
3407 } else {
3408 glDisable(GL_STENCIL_TEST);
3409 checkGLcall("glDisable GL_STENCIL_TEST");
3414 /*****
3415 * Get / Set Render States
3416 * TODO: Verify against dx9 definitions
3417 *****/
3418 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3421 DWORD OldValue = This->stateBlock->renderState[State];
3423 /* Simple way of referring to either a DWORD or a 4 byte float */
3424 union {
3425 DWORD d;
3426 float f;
3427 } tmpvalue;
3429 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3430 This->updateStateBlock->changed.renderState[State] = TRUE;
3431 This->updateStateBlock->set.renderState[State] = TRUE;
3432 This->updateStateBlock->renderState[State] = Value;
3434 /* Handle recording of state blocks */
3435 if (This->isRecordingState) {
3436 TRACE("Recording... not performing anything\n");
3437 return WINED3D_OK;
3440 ENTER_GL();
3442 switch (State) {
3443 case WINED3DRS_FILLMODE :
3444 switch ((D3DFILLMODE) Value) {
3445 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3446 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3447 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3448 default:
3449 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3451 checkGLcall("glPolygonMode (fillmode)");
3452 break;
3454 case WINED3DRS_LIGHTING :
3455 if (Value) {
3456 glEnable(GL_LIGHTING);
3457 checkGLcall("glEnable GL_LIGHTING");
3458 } else {
3459 glDisable(GL_LIGHTING);
3460 checkGLcall("glDisable GL_LIGHTING");
3462 break;
3464 case WINED3DRS_ZENABLE :
3465 switch ((D3DZBUFFERTYPE) Value) {
3466 case D3DZB_FALSE:
3467 glDisable(GL_DEPTH_TEST);
3468 checkGLcall("glDisable GL_DEPTH_TEST");
3469 break;
3470 case D3DZB_TRUE:
3471 glEnable(GL_DEPTH_TEST);
3472 checkGLcall("glEnable GL_DEPTH_TEST");
3473 break;
3474 case D3DZB_USEW:
3475 glEnable(GL_DEPTH_TEST);
3476 checkGLcall("glEnable GL_DEPTH_TEST");
3477 FIXME("W buffer is not well handled\n");
3478 break;
3479 default:
3480 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3482 break;
3484 case WINED3DRS_CULLMODE :
3486 /* If we are culling "back faces with clockwise vertices" then
3487 set front faces to be counter clockwise and enable culling
3488 of back faces */
3489 switch ((D3DCULL) Value) {
3490 case D3DCULL_NONE:
3491 glDisable(GL_CULL_FACE);
3492 checkGLcall("glDisable GL_CULL_FACE");
3493 break;
3494 case D3DCULL_CW:
3495 glEnable(GL_CULL_FACE);
3496 checkGLcall("glEnable GL_CULL_FACE");
3497 if (This->renderUpsideDown) {
3498 glFrontFace(GL_CW);
3499 checkGLcall("glFrontFace GL_CW");
3500 } else {
3501 glFrontFace(GL_CCW);
3502 checkGLcall("glFrontFace GL_CCW");
3504 glCullFace(GL_BACK);
3505 break;
3506 case D3DCULL_CCW:
3507 glEnable(GL_CULL_FACE);
3508 checkGLcall("glEnable GL_CULL_FACE");
3509 if (This->renderUpsideDown) {
3510 glFrontFace(GL_CCW);
3511 checkGLcall("glFrontFace GL_CCW");
3512 } else {
3513 glFrontFace(GL_CW);
3514 checkGLcall("glFrontFace GL_CW");
3516 glCullFace(GL_BACK);
3517 break;
3518 default:
3519 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3521 break;
3523 case WINED3DRS_SHADEMODE :
3524 switch ((D3DSHADEMODE) Value) {
3525 case D3DSHADE_FLAT:
3526 glShadeModel(GL_FLAT);
3527 checkGLcall("glShadeModel");
3528 break;
3529 case D3DSHADE_GOURAUD:
3530 glShadeModel(GL_SMOOTH);
3531 checkGLcall("glShadeModel");
3532 break;
3533 case D3DSHADE_PHONG:
3534 FIXME("D3DSHADE_PHONG isn't supported\n");
3535 break;
3536 default:
3537 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3539 break;
3541 case WINED3DRS_DITHERENABLE :
3542 if (Value) {
3543 glEnable(GL_DITHER);
3544 checkGLcall("glEnable GL_DITHER");
3545 } else {
3546 glDisable(GL_DITHER);
3547 checkGLcall("glDisable GL_DITHER");
3549 break;
3551 case WINED3DRS_ZWRITEENABLE :
3552 if (Value) {
3553 glDepthMask(1);
3554 checkGLcall("glDepthMask");
3555 } else {
3556 glDepthMask(0);
3557 checkGLcall("glDepthMask");
3559 break;
3561 case WINED3DRS_ZFUNC :
3563 int glParm = GL_LESS;
3565 switch ((D3DCMPFUNC) Value) {
3566 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3567 case D3DCMP_LESS: glParm=GL_LESS; break;
3568 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3569 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3570 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3571 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3572 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3573 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3574 default:
3575 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3577 glDepthFunc(glParm);
3578 checkGLcall("glDepthFunc");
3580 break;
3582 case WINED3DRS_AMBIENT :
3584 float col[4];
3585 D3DCOLORTOGLFLOAT4(Value, col);
3586 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3587 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3588 checkGLcall("glLightModel for MODEL_AMBIENT");
3591 break;
3593 case WINED3DRS_ALPHABLENDENABLE :
3594 if (Value) {
3595 glEnable(GL_BLEND);
3596 checkGLcall("glEnable GL_BLEND");
3597 } else {
3598 glDisable(GL_BLEND);
3599 checkGLcall("glDisable GL_BLEND");
3601 break;
3603 case WINED3DRS_SRCBLEND :
3604 case WINED3DRS_DESTBLEND :
3606 int newVal = GL_ZERO;
3607 switch (Value) {
3608 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3609 case D3DBLEND_ONE : newVal = GL_ONE; break;
3610 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3611 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3612 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3613 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3614 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3615 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3616 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3617 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3618 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3620 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3621 This->srcBlend = newVal;
3622 This->dstBlend = newVal;
3623 break;
3625 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3626 This->srcBlend = newVal;
3627 This->dstBlend = newVal;
3628 break;
3629 default:
3630 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3633 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3634 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3635 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3636 glBlendFunc(This->srcBlend, This->dstBlend);
3638 checkGLcall("glBlendFunc");
3640 break;
3642 case WINED3DRS_ALPHATESTENABLE :
3643 case WINED3DRS_ALPHAFUNC :
3644 case WINED3DRS_ALPHAREF :
3645 case WINED3DRS_COLORKEYENABLE :
3647 int glParm = 0.0;
3648 float ref = GL_LESS;
3649 BOOL enable_ckey = FALSE;
3651 IWineD3DSurfaceImpl *surf;
3653 /* Find out if the texture on the first stage has a ckey set */
3654 if(This->stateBlock->textures[0]) {
3655 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3656 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3659 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3660 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3661 glEnable(GL_ALPHA_TEST);
3662 checkGLcall("glEnable GL_ALPHA_TEST");
3663 } else {
3664 glDisable(GL_ALPHA_TEST);
3665 checkGLcall("glDisable GL_ALPHA_TEST");
3666 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3667 * enable call
3669 break;
3672 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3673 glParm = GL_NOTEQUAL;
3674 ref = 0.0;
3675 } else {
3676 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3678 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3679 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3680 case D3DCMP_LESS: glParm = GL_LESS; break;
3681 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3682 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3683 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3684 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3685 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3686 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3687 default:
3688 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3691 This->alphafunc = glParm;
3692 glAlphaFunc(glParm, ref);
3693 checkGLcall("glAlphaFunc");
3695 break;
3697 case WINED3DRS_CLIPPLANEENABLE :
3698 case WINED3DRS_CLIPPING :
3700 /* Ensure we only do the changed clip planes */
3701 DWORD enable = 0xFFFFFFFF;
3702 DWORD disable = 0x00000000;
3704 /* If enabling / disabling all */
3705 if (State == WINED3DRS_CLIPPING) {
3706 if (Value) {
3707 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3708 disable = 0x00;
3709 } else {
3710 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3711 enable = 0x00;
3713 } else {
3714 enable = Value & ~OldValue;
3715 disable = ~Value & OldValue;
3718 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3719 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3720 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3721 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3722 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3723 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3725 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3726 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3727 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3728 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3729 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3730 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3732 /** update clipping status */
3733 if (enable) {
3734 This->stateBlock->clip_status.ClipUnion = 0;
3735 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3736 } else {
3737 This->stateBlock->clip_status.ClipUnion = 0;
3738 This->stateBlock->clip_status.ClipIntersection = 0;
3741 break;
3743 case WINED3DRS_BLENDOP :
3745 int glParm = GL_FUNC_ADD;
3747 switch ((D3DBLENDOP) Value) {
3748 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3749 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3750 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3751 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3752 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3753 default:
3754 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3757 if(GL_SUPPORT(ARB_IMAGING)) {
3758 TRACE("glBlendEquation(%x)\n", glParm);
3759 GL_EXTCALL(glBlendEquation(glParm));
3760 checkGLcall("glBlendEquation");
3761 } else {
3762 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3765 break;
3767 case WINED3DRS_TEXTUREFACTOR :
3769 unsigned int i;
3771 /* Note the texture color applies to all textures whereas
3772 GL_TEXTURE_ENV_COLOR applies to active only */
3773 float col[4];
3774 D3DCOLORTOGLFLOAT4(Value, col);
3775 /* Set the default alpha blend color */
3776 if (GL_SUPPORT(ARB_IMAGING)) {
3777 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3778 checkGLcall("glBlendColor");
3779 } else {
3780 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3783 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3784 /* And now the default texture color as well */
3785 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3786 /* Note the D3DRS value applies to all textures, but GL has one
3787 per texture, so apply it now ready to be used! */
3788 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3789 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3790 checkGLcall("glActiveTextureARB");
3791 } else if (i>0) {
3792 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3795 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3796 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3800 break;
3802 case WINED3DRS_SPECULARENABLE :
3804 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3805 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3806 specular color. This is wrong:
3807 Separate specular color means the specular colour is maintained separately, whereas
3808 single color means it is merged in. However in both cases they are being used to
3809 some extent.
3810 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3811 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3812 running 1.4 yet!
3815 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3816 * Instead, we need to setup the FinalCombiner properly.
3818 * The default setup for the FinalCombiner is:
3820 * <variable> <input> <mapping> <usage>
3821 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3822 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3823 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3824 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3825 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3826 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3827 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3829 * That's pretty much fine as it is, except for variable B, which needs to take
3830 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3831 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3834 if (Value) {
3835 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3836 checkGLcall("glMaterialfv");
3837 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3838 glEnable(GL_COLOR_SUM_EXT);
3839 } else {
3840 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3842 checkGLcall("glEnable(GL_COLOR_SUM)");
3844 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3845 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3846 checkGLcall("glFinalCombinerInputNV()");
3848 } else {
3849 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3851 /* for the case of enabled lighting: */
3852 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3853 checkGLcall("glMaterialfv");
3855 /* for the case of disabled lighting: */
3856 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3857 glDisable(GL_COLOR_SUM_EXT);
3858 } else {
3859 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3861 checkGLcall("glDisable(GL_COLOR_SUM)");
3863 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3864 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3865 checkGLcall("glFinalCombinerInputNV()");
3869 break;
3871 case WINED3DRS_STENCILENABLE :
3872 case WINED3DRS_TWOSIDEDSTENCILMODE :
3873 case WINED3DRS_STENCILFUNC :
3874 case WINED3DRS_CCW_STENCILFUNC :
3875 case WINED3DRS_STENCILREF :
3876 case WINED3DRS_STENCILMASK :
3877 case WINED3DRS_STENCILFAIL :
3878 case WINED3DRS_STENCILZFAIL :
3879 case WINED3DRS_STENCILPASS :
3880 case WINED3DRS_CCW_STENCILFAIL :
3881 case WINED3DRS_CCW_STENCILZFAIL :
3882 case WINED3DRS_CCW_STENCILPASS :
3883 renderstate_stencil(This, State, Value);
3884 break;
3885 case WINED3DRS_STENCILWRITEMASK :
3887 glStencilMask(Value);
3888 TRACE("glStencilMask(%lu)\n", Value);
3889 checkGLcall("glStencilMask");
3891 break;
3893 case WINED3DRS_FOGENABLE :
3895 if (Value) {
3896 glEnable(GL_FOG);
3897 checkGLcall("glEnable GL_FOG");
3898 } else {
3899 glDisable(GL_FOG);
3900 checkGLcall("glDisable GL_FOG");
3903 break;
3905 case WINED3DRS_RANGEFOGENABLE :
3907 if (Value) {
3908 TRACE("Enabled RANGEFOG\n");
3909 } else {
3910 TRACE("Disabled RANGEFOG\n");
3913 break;
3915 case WINED3DRS_FOGCOLOR :
3917 float col[4];
3918 D3DCOLORTOGLFLOAT4(Value, col);
3919 /* Set the default alpha blend color */
3920 glFogfv(GL_FOG_COLOR, &col[0]);
3921 checkGLcall("glFog GL_FOG_COLOR");
3923 break;
3925 case WINED3DRS_FOGTABLEMODE :
3926 case WINED3DRS_FOGVERTEXMODE :
3928 /* 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." */
3929 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3930 glHint(GL_FOG_HINT, GL_FASTEST);
3931 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3932 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3933 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3934 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3936 case D3DFOG_EXP: {
3937 if(!This->last_was_rhw) {
3938 glFogi(GL_FOG_MODE, GL_EXP);
3939 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3940 if(GL_SUPPORT(EXT_FOG_COORD)) {
3941 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3942 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3943 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3944 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3946 break;
3949 case D3DFOG_EXP2: {
3950 if(!This->last_was_rhw) {
3951 glFogi(GL_FOG_MODE, GL_EXP2);
3952 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3953 if(GL_SUPPORT(EXT_FOG_COORD)) {
3954 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3955 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3956 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3957 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3959 break;
3962 case D3DFOG_LINEAR: {
3963 if(!This->last_was_rhw) {
3964 glFogi(GL_FOG_MODE, GL_LINEAR);
3965 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3966 if(GL_SUPPORT(EXT_FOG_COORD)) {
3967 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3968 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3969 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3970 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3972 break;
3975 case D3DFOG_NONE: {
3976 /* Both are none? According to msdn the alpha channel of the specular
3977 * color contains a fog factor. Set it in drawStridedSlow.
3978 * Same happens with Vertexfog on transformed vertices
3980 if(GL_SUPPORT(EXT_FOG_COORD)) {
3981 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3982 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3983 glFogi(GL_FOG_MODE, GL_LINEAR);
3984 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3985 glFogf(GL_FOG_START, (float) 0xff);
3986 checkGLcall("glFogfv GL_FOG_START");
3987 glFogf(GL_FOG_END, 0.0);
3988 checkGLcall("glFogfv GL_FOG_END");
3989 } else {
3990 /* Disable GL fog, handle this in software in drawStridedSlow */
3991 glDisable(GL_FOG);
3992 checkGLcall("glDisable(GL_FOG)");
3994 break;
3996 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3998 } else {
3999 glHint(GL_FOG_HINT, GL_NICEST);
4000 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
4001 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
4002 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
4003 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
4004 if(GL_SUPPORT(EXT_FOG_COORD)) {
4005 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4006 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4007 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4008 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4010 break;
4011 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
4012 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
4013 if(GL_SUPPORT(EXT_FOG_COORD)) {
4014 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4015 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4016 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4017 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4019 break;
4020 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4021 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4022 if(GL_SUPPORT(EXT_FOG_COORD)) {
4023 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4024 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4025 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4026 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4028 break;
4029 case D3DFOG_NONE: /* Won't happen */
4030 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4033 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4034 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4037 break;
4039 case WINED3DRS_FOGSTART :
4041 tmpvalue.d = Value;
4042 glFogfv(GL_FOG_START, &tmpvalue.f);
4043 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4044 TRACE("Fog Start == %f\n", tmpvalue.f);
4046 break;
4048 case WINED3DRS_FOGEND :
4050 tmpvalue.d = Value;
4051 glFogfv(GL_FOG_END, &tmpvalue.f);
4052 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4053 TRACE("Fog End == %f\n", tmpvalue.f);
4055 break;
4057 case WINED3DRS_FOGDENSITY :
4059 tmpvalue.d = Value;
4060 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4061 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4063 break;
4065 case WINED3DRS_VERTEXBLEND :
4067 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4068 TRACE("Vertex Blending state to %ld\n", Value);
4070 break;
4072 case WINED3DRS_TWEENFACTOR :
4074 tmpvalue.d = Value;
4075 This->updateStateBlock->tween_factor = tmpvalue.f;
4076 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4078 break;
4080 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4082 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4084 break;
4086 case WINED3DRS_COLORVERTEX :
4087 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4088 case WINED3DRS_SPECULARMATERIALSOURCE :
4089 case WINED3DRS_AMBIENTMATERIALSOURCE :
4090 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4092 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4094 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4095 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4096 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4097 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4098 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4099 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4101 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4102 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4103 Parm = GL_AMBIENT_AND_DIFFUSE;
4104 } else {
4105 Parm = GL_DIFFUSE;
4107 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4108 Parm = GL_AMBIENT;
4109 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4110 Parm = GL_EMISSION;
4111 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4112 Parm = GL_SPECULAR;
4113 } else {
4114 Parm = -1;
4117 if (Parm == -1) {
4118 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4119 } else {
4120 This->tracking_color = NEEDS_TRACKING;
4121 This->tracking_parm = Parm;
4124 } else {
4125 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4128 break;
4130 case WINED3DRS_LINEPATTERN :
4132 union {
4133 DWORD d;
4134 D3DLINEPATTERN lp;
4135 } tmppattern;
4136 tmppattern.d = Value;
4138 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4140 if (tmppattern.lp.wRepeatFactor) {
4141 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4142 checkGLcall("glLineStipple(repeat, linepattern)");
4143 glEnable(GL_LINE_STIPPLE);
4144 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4145 } else {
4146 glDisable(GL_LINE_STIPPLE);
4147 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4150 break;
4152 case WINED3DRS_ZBIAS : /* D3D8 only */
4154 if (Value) {
4155 tmpvalue.d = Value;
4156 TRACE("ZBias value %f\n", tmpvalue.f);
4157 glPolygonOffset(0, -tmpvalue.f);
4158 checkGLcall("glPolygonOffset(0, -Value)");
4159 glEnable(GL_POLYGON_OFFSET_FILL);
4160 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4161 glEnable(GL_POLYGON_OFFSET_LINE);
4162 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4163 glEnable(GL_POLYGON_OFFSET_POINT);
4164 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4165 } else {
4166 glDisable(GL_POLYGON_OFFSET_FILL);
4167 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4168 glDisable(GL_POLYGON_OFFSET_LINE);
4169 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4170 glDisable(GL_POLYGON_OFFSET_POINT);
4171 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4174 break;
4176 case WINED3DRS_NORMALIZENORMALS :
4177 if (Value) {
4178 glEnable(GL_NORMALIZE);
4179 checkGLcall("glEnable(GL_NORMALIZE);");
4180 } else {
4181 glDisable(GL_NORMALIZE);
4182 checkGLcall("glDisable(GL_NORMALIZE);");
4184 break;
4186 case WINED3DRS_POINTSIZE :
4187 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4188 tmpvalue.d = Value;
4189 TRACE("Set point size to %f\n", tmpvalue.f);
4190 glPointSize(tmpvalue.f);
4191 checkGLcall("glPointSize(...);");
4192 break;
4194 case WINED3DRS_POINTSIZE_MIN :
4195 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4196 tmpvalue.d = Value;
4197 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4198 checkGLcall("glPointParameterfEXT(...);");
4199 } else {
4200 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4202 break;
4204 case WINED3DRS_POINTSIZE_MAX :
4205 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4206 tmpvalue.d = Value;
4207 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4208 checkGLcall("glPointParameterfEXT(...);");
4209 } else {
4210 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4212 break;
4214 case WINED3DRS_POINTSCALE_A :
4215 case WINED3DRS_POINTSCALE_B :
4216 case WINED3DRS_POINTSCALE_C :
4217 case WINED3DRS_POINTSCALEENABLE :
4220 * POINTSCALEENABLE controls how point size value is treated. If set to
4221 * true, the point size is scaled with respect to height of viewport.
4222 * When set to false point size is in pixels.
4224 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4227 /* Default values */
4228 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4231 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4232 * This means that OpenGL will clamp really small point sizes to 1.0f.
4233 * To correct for this we need to multiply by the scale factor when sizes
4234 * are less than 1.0f. scale_factor = 1.0f / point_size.
4236 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4237 if(pointSize > 0.0f) {
4238 GLfloat scaleFactor;
4240 if(pointSize < 1.0f) {
4241 scaleFactor = pointSize * pointSize;
4242 } else {
4243 scaleFactor = 1.0f;
4246 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4247 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4248 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4249 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4250 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4251 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4252 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4256 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4257 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4258 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4260 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4261 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4262 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4263 } else {
4264 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4266 break;
4268 case WINED3DRS_COLORWRITEENABLE :
4270 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4271 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4272 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4273 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4274 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4275 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4276 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4277 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4278 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4279 checkGLcall("glColorMask(...)");
4281 break;
4283 case WINED3DRS_LOCALVIEWER :
4285 GLint state = (Value) ? 1 : 0;
4286 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4287 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4289 break;
4291 case WINED3DRS_LASTPIXEL :
4293 if (Value) {
4294 TRACE("Last Pixel Drawing Enabled\n");
4295 } else {
4296 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4299 break;
4301 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4303 if (Value) {
4304 TRACE("Software Processing Enabled\n");
4305 } else {
4306 TRACE("Software Processing Disabled\n");
4309 break;
4311 /** not supported */
4312 case WINED3DRS_ZVISIBLE :
4314 LEAVE_GL();
4315 return WINED3DERR_INVALIDCALL;
4317 case WINED3DRS_POINTSPRITEENABLE :
4319 /* TODO: NV_POINT_SPRITE */
4320 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4321 TRACE("Point sprites not supported\n");
4322 break;
4326 * Point sprites are always enabled. Value controls texture coordinate
4327 * replacement mode. Must be set true for point sprites to use
4328 * textures.
4330 glEnable(GL_POINT_SPRITE_ARB);
4331 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4333 if (Value) {
4334 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4335 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4336 } else {
4337 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4338 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4340 break;
4342 case WINED3DRS_EDGEANTIALIAS :
4344 if(Value) {
4345 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4346 glEnable(GL_BLEND);
4347 checkGLcall("glEnable(GL_BLEND)");
4348 glEnable(GL_LINE_SMOOTH);
4349 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4350 } else {
4351 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4352 glDisable(GL_BLEND);
4353 checkGLcall("glDisable(GL_BLEND)");
4355 glDisable(GL_LINE_SMOOTH);
4356 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4358 break;
4360 case WINED3DRS_WRAP0 :
4361 case WINED3DRS_WRAP1 :
4362 case WINED3DRS_WRAP2 :
4363 case WINED3DRS_WRAP3 :
4364 case WINED3DRS_WRAP4 :
4365 case WINED3DRS_WRAP5 :
4366 case WINED3DRS_WRAP6 :
4367 case WINED3DRS_WRAP7 :
4368 case WINED3DRS_WRAP8 :
4369 case WINED3DRS_WRAP9 :
4370 case WINED3DRS_WRAP10 :
4371 case WINED3DRS_WRAP11 :
4372 case WINED3DRS_WRAP12 :
4373 case WINED3DRS_WRAP13 :
4374 case WINED3DRS_WRAP14 :
4375 case WINED3DRS_WRAP15 :
4377 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4378 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4379 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4380 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4381 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4383 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4386 if(Value) {
4387 ERR("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4389 break;
4392 case WINED3DRS_MULTISAMPLEANTIALIAS :
4394 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4395 if(Value) {
4396 glEnable(GL_MULTISAMPLE_ARB);
4397 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4398 } else {
4399 glDisable(GL_MULTISAMPLE_ARB);
4400 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4402 } else {
4403 if(Value) {
4404 ERR("Multisample antialiasing not supported by gl\n");
4407 break;
4410 case WINED3DRS_SCISSORTESTENABLE :
4412 if(Value) {
4413 glEnable(GL_SCISSOR_TEST);
4414 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4415 } else {
4416 glDisable(GL_SCISSOR_TEST);
4417 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4419 break;
4421 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4423 if(Value) {
4424 tmpvalue.d = Value;
4425 glEnable(GL_POLYGON_OFFSET_FILL);
4426 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4427 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4428 checkGLcall("glPolygonOffset(...)");
4429 } else {
4430 glDisable(GL_POLYGON_OFFSET_FILL);
4431 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4433 break;
4435 case WINED3DRS_ANTIALIASEDLINEENABLE :
4437 if(Value) {
4438 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4439 glEnable(GL_BLEND);
4440 checkGLcall("glEnable(GL_BLEND)");
4441 glEnable(GL_LINE_SMOOTH);
4442 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4443 } else {
4444 glDisable(GL_BLEND);
4445 checkGLcall("glDisable(GL_BLEND)");
4446 glDisable(GL_LINE_SMOOTH);
4447 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4449 break;
4451 case WINED3DRS_DEPTHBIAS :
4453 if(Value) {
4454 tmpvalue.d = Value;
4455 glEnable(GL_POLYGON_OFFSET_FILL);
4456 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4457 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4458 checkGLcall("glPolygonOffset(...)");
4459 } else {
4460 glDisable(GL_POLYGON_OFFSET_FILL);
4461 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4463 break;
4466 case WINED3DRS_TEXTUREPERSPECTIVE :
4468 if (Value)
4469 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4470 else
4471 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4472 break;
4475 case WINED3DRS_STIPPLEDALPHA :
4477 if (Value)
4478 ERR(" Stippled Alpha not supported yet.\n");
4479 break;
4481 case WINED3DRS_ANTIALIAS :
4483 if (Value)
4484 ERR(" Antialias not supported yet.\n");
4485 break;
4488 case WINED3DRS_MULTISAMPLEMASK :
4490 if(0xFFFFFFFF != Value)
4491 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4492 break;
4495 case WINED3DRS_PATCHEDGESTYLE :
4497 if(D3DPATCHEDGE_DISCRETE != Value)
4498 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4499 break;
4502 case WINED3DRS_PATCHSEGMENTS :
4504 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4505 tmpvalue.f = 1.0f;
4506 if(tmpvalue.d != Value)
4507 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4508 break;
4511 case WINED3DRS_DEBUGMONITORTOKEN :
4513 /* Only useful for "debug builds". */
4514 if(0xbaadcafe != Value) {
4515 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4516 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4517 * but our tests disagree.
4518 * We do not claim to implement a debugging lib, so do not write an ERR
4520 WARN("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4522 break;
4525 case WINED3DRS_POSITIONDEGREE :
4527 if(D3DDEGREE_CUBIC != Value)
4528 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4529 break;
4532 case WINED3DRS_NORMALDEGREE :
4534 if(D3DDEGREE_LINEAR != Value)
4535 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4536 break;
4539 case WINED3DRS_MINTESSELLATIONLEVEL :
4540 case WINED3DRS_MAXTESSELLATIONLEVEL :
4541 case WINED3DRS_ADAPTIVETESS_X :
4542 case WINED3DRS_ADAPTIVETESS_Y :
4543 case WINED3DRS_ADAPTIVETESS_Z :
4544 case WINED3DRS_ADAPTIVETESS_W :
4546 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4547 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4548 else
4549 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4550 break;
4553 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4555 if(Value)
4556 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4557 break;
4560 case WINED3DRS_COLORWRITEENABLE1 :
4561 case WINED3DRS_COLORWRITEENABLE2 :
4562 case WINED3DRS_COLORWRITEENABLE3 :
4564 /* depends on WINED3DRS_COLORWRITEENABLE. */
4565 if(0x0000000F != Value)
4566 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4567 break;
4570 case WINED3DRS_BLENDFACTOR :
4572 if(0xFFFFFFFF != Value)
4573 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPBLENDCAPS_BLENDFACTOR wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4574 break;
4577 case WINED3DRS_SRGBWRITEENABLE :
4579 if(Value)
4580 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4581 break;
4584 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4586 if(Value)
4587 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4588 break;
4591 case WINED3DRS_SRCBLENDALPHA :
4592 case WINED3DRS_DESTBLENDALPHA :
4593 case WINED3DRS_BLENDOPALPHA :
4595 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4596 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4597 else
4598 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4599 break;
4602 default:
4603 FIXME("(%p)->(%s,%ld) unknown state\n", This, debug_d3drenderstate(State), Value);
4606 LEAVE_GL();
4608 return WINED3D_OK;
4611 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4613 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4614 *pValue = This->stateBlock->renderState[State];
4615 return WINED3D_OK;
4618 /*****
4619 * Get / Set Sampler States
4620 * TODO: Verify against dx9 definitions
4621 *****/
4623 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 * SetSampler is designed to allow for more than the standard up to 8 textures
4627 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4628 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4630 * http://developer.nvidia.com/object/General_FAQ.html#t6
4632 * There are two new settings for GForce
4633 * the sampler one:
4634 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4635 * and the texture one:
4636 * GL_MAX_TEXTURE_COORDS_ARB.
4637 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4638 ******************/
4639 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4640 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4641 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4642 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4643 return WINED3DERR_INVALIDCALL;
4646 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4647 debug_d3dsamplerstate(Type), Type, Value);
4648 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4649 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4650 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4652 /* Handle recording of state blocks */
4653 if (This->isRecordingState) {
4654 TRACE("Recording... not performing anything\n");
4655 return WINED3D_OK;
4658 return WINED3D_OK;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 /** TODO: check that sampler is in range **/
4664 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4665 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4667 return WINED3D_OK;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 ENTER_GL();
4674 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4675 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4676 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4677 LEAVE_GL();
4679 return WINED3D_OK;
4682 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4684 GLint scissorBox[4];
4686 ENTER_GL();
4687 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4688 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4689 pRect->left = scissorBox[0];
4690 pRect->top = scissorBox[1];
4691 pRect->right = scissorBox[0] + scissorBox[2];
4692 pRect->bottom = scissorBox[1] + scissorBox[3];
4693 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4694 LEAVE_GL();
4695 return WINED3D_OK;
4698 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4700 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4702 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4704 This->updateStateBlock->vertexDecl = pDecl;
4705 This->updateStateBlock->changed.vertexDecl = TRUE;
4706 This->updateStateBlock->set.vertexDecl = TRUE;
4708 if (This->isRecordingState) {
4709 TRACE("Recording... not performing anything\n");
4712 if (NULL != pDecl) {
4713 IWineD3DVertexDeclaration_AddRef(pDecl);
4715 if (NULL != oldDecl) {
4716 IWineD3DVertexDeclaration_Release(oldDecl);
4718 return WINED3D_OK;
4721 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4724 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4726 *ppDecl = This->stateBlock->vertexDecl;
4727 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4728 return WINED3D_OK;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4733 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4735 This->updateStateBlock->vertexShader = pShader;
4736 This->updateStateBlock->changed.vertexShader = TRUE;
4737 This->updateStateBlock->set.vertexShader = TRUE;
4739 if (This->isRecordingState) {
4740 TRACE("Recording... not performing anything\n");
4743 if (NULL != pShader) {
4744 IWineD3DVertexShader_AddRef(pShader);
4746 if (NULL != oldShader) {
4747 IWineD3DVertexShader_Release(oldShader);
4750 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4752 * TODO: merge HAL shaders context switching from prototype
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 if (NULL == ppShader) {
4761 return WINED3DERR_INVALIDCALL;
4763 *ppShader = This->stateBlock->vertexShader;
4764 if( NULL != *ppShader)
4765 IWineD3DVertexShader_AddRef(*ppShader);
4767 TRACE("(%p) : returning %p\n", This, *ppShader);
4768 return WINED3D_OK;
4771 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4772 IWineD3DDevice *iface,
4773 UINT start,
4774 CONST BOOL *srcData,
4775 UINT count) {
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 int i, cnt = min(count, MAX_CONST_B - start);
4780 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4781 iface, srcData, start, count);
4783 if (srcData == NULL || cnt < 0)
4784 return WINED3DERR_INVALIDCALL;
4786 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4787 for (i = 0; i < cnt; i++)
4788 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4790 for (i = start; i < cnt + start; ++i) {
4791 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4792 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4795 return WINED3D_OK;
4798 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4799 IWineD3DDevice *iface,
4800 UINT start,
4801 BOOL *dstData,
4802 UINT count) {
4804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4805 int cnt = min(count, MAX_CONST_B - start);
4807 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4808 iface, dstData, start, count);
4810 if (dstData == NULL || cnt < 0)
4811 return WINED3DERR_INVALIDCALL;
4813 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4814 return WINED3D_OK;
4817 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4818 IWineD3DDevice *iface,
4819 UINT start,
4820 CONST int *srcData,
4821 UINT count) {
4823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4824 int i, cnt = min(count, MAX_CONST_I - start);
4826 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4827 iface, srcData, start, count);
4829 if (srcData == NULL || cnt < 0)
4830 return WINED3DERR_INVALIDCALL;
4832 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4833 for (i = 0; i < cnt; i++)
4834 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4835 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4837 for (i = start; i < cnt + start; ++i) {
4838 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4839 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4842 return WINED3D_OK;
4845 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4846 IWineD3DDevice *iface,
4847 UINT start,
4848 int *dstData,
4849 UINT count) {
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 int cnt = min(count, MAX_CONST_I - start);
4854 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4855 iface, dstData, start, count);
4857 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4858 return WINED3DERR_INVALIDCALL;
4860 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4861 return WINED3D_OK;
4864 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4865 IWineD3DDevice *iface,
4866 UINT start,
4867 CONST float *srcData,
4868 UINT count) {
4870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4871 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4873 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4874 iface, srcData, start, count);
4876 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4877 return WINED3DERR_INVALIDCALL;
4879 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4880 for (i = 0; i < cnt; i++)
4881 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4882 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4884 for (i = start; i < cnt + start; ++i) {
4885 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4886 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4887 ptr->idx = i;
4888 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4889 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4891 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4894 return WINED3D_OK;
4897 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4898 IWineD3DDevice *iface,
4899 UINT start,
4900 float *dstData,
4901 UINT count) {
4903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4904 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4906 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4907 iface, dstData, start, count);
4909 if (dstData == NULL || cnt < 0)
4910 return WINED3DERR_INVALIDCALL;
4912 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4913 return WINED3D_OK;
4916 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4918 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4919 This->updateStateBlock->pixelShader = pShader;
4920 This->updateStateBlock->changed.pixelShader = TRUE;
4921 This->updateStateBlock->set.pixelShader = TRUE;
4923 /* Handle recording of state blocks */
4924 if (This->isRecordingState) {
4925 TRACE("Recording... not performing anything\n");
4928 if (NULL != pShader) {
4929 IWineD3DPixelShader_AddRef(pShader);
4931 if (NULL != oldShader) {
4932 IWineD3DPixelShader_Release(oldShader);
4935 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4937 * TODO: merge HAL shaders context switching from prototype
4939 return WINED3D_OK;
4942 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4945 if (NULL == ppShader) {
4946 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4947 return WINED3DERR_INVALIDCALL;
4950 *ppShader = This->stateBlock->pixelShader;
4951 if (NULL != *ppShader) {
4952 IWineD3DPixelShader_AddRef(*ppShader);
4954 TRACE("(%p) : returning %p\n", This, *ppShader);
4955 return WINED3D_OK;
4958 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4959 IWineD3DDevice *iface,
4960 UINT start,
4961 CONST BOOL *srcData,
4962 UINT count) {
4964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4965 int i, cnt = min(count, MAX_CONST_B - start);
4967 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4968 iface, srcData, start, count);
4970 if (srcData == NULL || cnt < 0)
4971 return WINED3DERR_INVALIDCALL;
4973 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4974 for (i = 0; i < cnt; i++)
4975 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4977 for (i = start; i < cnt + start; ++i) {
4978 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4979 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4982 return WINED3D_OK;
4985 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4986 IWineD3DDevice *iface,
4987 UINT start,
4988 BOOL *dstData,
4989 UINT count) {
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4992 int cnt = min(count, MAX_CONST_B - start);
4994 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4995 iface, dstData, start, count);
4997 if (dstData == NULL || cnt < 0)
4998 return WINED3DERR_INVALIDCALL;
5000 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
5001 return WINED3D_OK;
5004 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
5005 IWineD3DDevice *iface,
5006 UINT start,
5007 CONST int *srcData,
5008 UINT count) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 int i, cnt = min(count, MAX_CONST_I - start);
5013 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5014 iface, srcData, start, count);
5016 if (srcData == NULL || cnt < 0)
5017 return WINED3DERR_INVALIDCALL;
5019 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
5020 for (i = 0; i < cnt; i++)
5021 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
5022 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5024 for (i = start; i < cnt + start; ++i) {
5025 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
5026 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
5029 return WINED3D_OK;
5032 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
5033 IWineD3DDevice *iface,
5034 UINT start,
5035 int *dstData,
5036 UINT count) {
5038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5039 int cnt = min(count, MAX_CONST_I - start);
5041 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5042 iface, dstData, start, count);
5044 if (dstData == NULL || cnt < 0)
5045 return WINED3DERR_INVALIDCALL;
5047 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5048 return WINED3D_OK;
5051 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5052 IWineD3DDevice *iface,
5053 UINT start,
5054 CONST float *srcData,
5055 UINT count) {
5057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5058 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5060 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5061 iface, srcData, start, count);
5063 if (srcData == NULL || cnt < 0)
5064 return WINED3DERR_INVALIDCALL;
5066 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5067 for (i = 0; i < cnt; i++)
5068 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5069 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5071 for (i = start; i < cnt + start; ++i) {
5072 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5073 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5074 ptr->idx = i;
5075 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5076 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5078 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5081 return WINED3D_OK;
5084 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5085 IWineD3DDevice *iface,
5086 UINT start,
5087 float *dstData,
5088 UINT count) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5093 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5094 iface, dstData, start, count);
5096 if (dstData == NULL || cnt < 0)
5097 return WINED3DERR_INVALIDCALL;
5099 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5100 return WINED3D_OK;
5103 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5104 static HRESULT
5105 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5106 char *dest_ptr, *dest_conv = NULL;
5107 unsigned int i;
5108 DWORD DestFVF = dest->fvf;
5109 D3DVIEWPORT9 vp;
5110 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5111 BOOL doClip;
5112 int numTextures;
5114 if (SrcFVF & D3DFVF_NORMAL) {
5115 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5118 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5119 ERR("Source has no position mask\n");
5120 return WINED3DERR_INVALIDCALL;
5123 /* We might access VBOs from this code, so hold the lock */
5124 ENTER_GL();
5126 if (dest->resource.allocatedMemory == NULL) {
5127 /* This may happen if we do direct locking into a vbo. Unlikely,
5128 * but theoretically possible(ddraw processvertices test)
5130 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5131 if(!dest->resource.allocatedMemory) {
5132 LEAVE_GL();
5133 ERR("Out of memory\n");
5134 return E_OUTOFMEMORY;
5136 if(dest->vbo) {
5137 void *src;
5138 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5139 checkGLcall("glBindBufferARB");
5140 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5141 if(src) {
5142 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5144 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5145 checkGLcall("glUnmapBufferARB");
5149 /* Get a pointer into the destination vbo(create one if none exists) and
5150 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5152 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5153 CreateVBO(dest);
5156 if(dest->vbo) {
5157 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5158 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5159 if(!dest_conv) {
5160 ERR("glMapBuffer failed\n");
5161 /* Continue without storing converted vertices */
5165 /* Should I clip?
5166 * a) D3DRS_CLIPPING is enabled
5167 * b) WINED3DVOP_CLIP is passed
5169 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5170 static BOOL warned = FALSE;
5172 * The clipping code is not quite correct. Some things need
5173 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5174 * so disable clipping for now.
5175 * (The graphics in Half-Life are broken, and my processvertices
5176 * test crashes with IDirect3DDevice3)
5177 doClip = TRUE;
5179 doClip = FALSE;
5180 if(!warned) {
5181 warned = TRUE;
5182 FIXME("Clipping is broken and disabled for now\n");
5184 } else doClip = FALSE;
5185 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5186 if(dest_conv) {
5187 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5190 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5191 WINED3DTS_VIEW,
5192 &view_mat);
5193 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5194 WINED3DTS_PROJECTION,
5195 &proj_mat);
5196 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5197 WINED3DTS_WORLDMATRIX(0),
5198 &world_mat);
5200 TRACE("View mat:\n");
5201 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); \
5202 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); \
5203 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); \
5204 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); \
5206 TRACE("Proj mat:\n");
5207 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); \
5208 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); \
5209 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); \
5210 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); \
5212 TRACE("World mat:\n");
5213 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); \
5214 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); \
5215 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); \
5216 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); \
5218 /* Get the viewport */
5219 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5220 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5221 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5223 multiply_matrix(&mat,&view_mat,&world_mat);
5224 multiply_matrix(&mat,&proj_mat,&mat);
5226 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5228 for (i = 0; i < dwCount; i+= 1) {
5229 unsigned int tex_index;
5231 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5232 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5233 /* The position first */
5234 float *p =
5235 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5236 float x, y, z, rhw;
5237 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5239 /* Multiplication with world, view and projection matrix */
5240 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);
5241 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);
5242 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);
5243 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);
5245 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5247 /* WARNING: The following things are taken from d3d7 and were not yet checked
5248 * against d3d8 or d3d9!
5251 /* Clipping conditions: From
5252 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5254 * A vertex is clipped if it does not match the following requirements
5255 * -rhw < x <= rhw
5256 * -rhw < y <= rhw
5257 * 0 < z <= rhw
5258 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5260 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5261 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5265 if( doClip == FALSE ||
5266 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5267 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5268 ( rhw > eps ) ) ) {
5270 /* "Normal" viewport transformation (not clipped)
5271 * 1) The values are divided by rhw
5272 * 2) The y axis is negative, so multiply it with -1
5273 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5274 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5275 * 4) Multiply x with Width/2 and add Width/2
5276 * 5) The same for the height
5277 * 6) Add the viewpoint X and Y to the 2D coordinates and
5278 * The minimum Z value to z
5279 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5281 * Well, basically it's simply a linear transformation into viewport
5282 * coordinates
5285 x /= rhw;
5286 y /= rhw;
5287 z /= rhw;
5289 y *= -1;
5291 x *= vp.Width / 2;
5292 y *= vp.Height / 2;
5293 z *= vp.MaxZ - vp.MinZ;
5295 x += vp.Width / 2 + vp.X;
5296 y += vp.Height / 2 + vp.Y;
5297 z += vp.MinZ;
5299 rhw = 1 / rhw;
5300 } else {
5301 /* That vertex got clipped
5302 * Contrary to OpenGL it is not dropped completely, it just
5303 * undergoes a different calculation.
5305 TRACE("Vertex got clipped\n");
5306 x += rhw;
5307 y += rhw;
5309 x /= 2;
5310 y /= 2;
5312 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5313 * outside of the main vertex buffer memory. That needs some more
5314 * investigation...
5318 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5321 ( (float *) dest_ptr)[0] = x;
5322 ( (float *) dest_ptr)[1] = y;
5323 ( (float *) dest_ptr)[2] = z;
5324 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5326 dest_ptr += 3 * sizeof(float);
5328 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5329 dest_ptr += sizeof(float);
5332 if(dest_conv) {
5333 float w = 1 / rhw;
5334 ( (float *) dest_conv)[0] = x * w;
5335 ( (float *) dest_conv)[1] = y * w;
5336 ( (float *) dest_conv)[2] = z * w;
5337 ( (float *) dest_conv)[3] = w;
5339 dest_conv += 3 * sizeof(float);
5341 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5342 dest_conv += sizeof(float);
5346 if (DestFVF & D3DFVF_PSIZE) {
5347 dest_ptr += sizeof(DWORD);
5348 if(dest_conv) dest_conv += sizeof(DWORD);
5350 if (DestFVF & D3DFVF_NORMAL) {
5351 float *normal =
5352 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5353 /* AFAIK this should go into the lighting information */
5354 FIXME("Didn't expect the destination to have a normal\n");
5355 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5356 if(dest_conv) {
5357 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5361 if (DestFVF & D3DFVF_DIFFUSE) {
5362 DWORD *color_d =
5363 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5364 if(!color_d) {
5365 static BOOL warned = FALSE;
5367 if(warned == FALSE) {
5368 ERR("No diffuse color in source, but destination has one\n");
5369 warned = TRUE;
5372 *( (DWORD *) dest_ptr) = 0xffffffff;
5373 dest_ptr += sizeof(DWORD);
5375 if(dest_conv) {
5376 *( (DWORD *) dest_conv) = 0xffffffff;
5377 dest_conv += sizeof(DWORD);
5380 else {
5381 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5382 if(dest_conv) {
5383 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5384 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5385 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5386 dest_conv += sizeof(DWORD);
5391 if (DestFVF & D3DFVF_SPECULAR) {
5392 /* What's the color value in the feedback buffer? */
5393 DWORD *color_s =
5394 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5395 if(!color_s) {
5396 static BOOL warned = FALSE;
5398 if(warned == FALSE) {
5399 ERR("No specular color in source, but destination has one\n");
5400 warned = TRUE;
5403 *( (DWORD *) dest_ptr) = 0xFF000000;
5404 dest_ptr += sizeof(DWORD);
5406 if(dest_conv) {
5407 *( (DWORD *) dest_conv) = 0xFF000000;
5408 dest_conv += sizeof(DWORD);
5411 else {
5412 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5413 if(dest_conv) {
5414 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5415 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5416 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5417 dest_conv += sizeof(DWORD);
5422 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5423 float *tex_coord =
5424 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5425 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5426 if(!tex_coord) {
5427 ERR("No source texture, but destination requests one\n");
5428 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5429 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5431 else {
5432 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5433 if(dest_conv) {
5434 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5440 if(dest_conv) {
5441 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5442 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5445 LEAVE_GL();
5447 return WINED3D_OK;
5449 #undef copy_and_next
5451 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5454 WineDirect3DVertexStridedData strided;
5455 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5457 /* We don't need the source vbo because this buffer is only used as
5458 * a source for ProcessVertices. Avoid wasting resources by converting the
5459 * buffer and loading the VBO
5461 if(SrcImpl->vbo) {
5462 TRACE("Releaseing the source vbo, it won't be needed\n");
5464 if(!SrcImpl->resource.allocatedMemory) {
5465 /* Rescue the data from the buffer */
5466 void *src;
5467 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5468 if(!SrcImpl->resource.allocatedMemory) {
5469 ERR("Out of memory\n");
5470 return E_OUTOFMEMORY;
5473 ENTER_GL();
5474 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5475 checkGLcall("glBindBufferARB");
5477 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5478 if(src) {
5479 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5482 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5483 checkGLcall("glUnmapBufferARB");
5484 } else {
5485 ENTER_GL();
5488 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5489 checkGLcall("glBindBufferARB");
5490 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5491 checkGLcall("glDeleteBuffersARB");
5492 LEAVE_GL();
5494 SrcImpl->vbo = 0;
5497 memset(&strided, 0, sizeof(strided));
5498 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5500 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5503 /*****
5504 * Apply / Get / Set Texture Stage States
5505 * TODO: Verify against dx9 definitions
5506 *****/
5508 /* 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 */
5509 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5511 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5512 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5514 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5516 /* Check that the stage is within limits */
5517 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5518 TRACE("Attempt to access invalid texture rejected\n");
5519 return;
5522 ENTER_GL();
5524 switch (Type) {
5525 case WINED3DTSS_ALPHAOP :
5526 case WINED3DTSS_COLOROP :
5527 /* nothing to do as moved to drawprim for now */
5528 break;
5529 case WINED3DTSS_ADDRESSW :
5530 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5531 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5532 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5534 } else {
5535 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5536 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5537 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5538 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5540 #endif
5541 case WINED3DTSS_TEXCOORDINDEX :
5543 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5545 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5546 one flag, you can still specify an index value, which the system uses to
5547 determine the texture wrapping mode.
5548 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5549 means use the vertex position (camera-space) as the input texture coordinates
5550 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5551 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5552 to the TEXCOORDINDEX value */
5555 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5557 switch (Value & 0xFFFF0000) {
5558 case D3DTSS_TCI_PASSTHRU:
5559 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5560 glDisable(GL_TEXTURE_GEN_S);
5561 glDisable(GL_TEXTURE_GEN_T);
5562 glDisable(GL_TEXTURE_GEN_R);
5563 glDisable(GL_TEXTURE_GEN_Q);
5564 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5565 break;
5567 case D3DTSS_TCI_CAMERASPACEPOSITION:
5568 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5569 as the input texture coordinates for this stage's texture transformation. This
5570 equates roughly to EYE_LINEAR */
5572 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5573 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5574 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5575 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5576 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5578 glMatrixMode(GL_MODELVIEW);
5579 glPushMatrix();
5580 glLoadIdentity();
5581 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5582 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5583 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5584 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5585 glPopMatrix();
5587 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5588 glEnable(GL_TEXTURE_GEN_S);
5589 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5590 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5591 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5592 glEnable(GL_TEXTURE_GEN_T);
5593 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5594 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5595 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5596 glEnable(GL_TEXTURE_GEN_R);
5597 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5598 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5599 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5601 break;
5603 case D3DTSS_TCI_CAMERASPACENORMAL:
5605 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5606 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5607 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5608 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5609 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5610 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5612 glMatrixMode(GL_MODELVIEW);
5613 glPushMatrix();
5614 glLoadIdentity();
5615 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5616 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5617 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5618 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5619 glPopMatrix();
5621 glEnable(GL_TEXTURE_GEN_S);
5622 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5623 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5624 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5625 glEnable(GL_TEXTURE_GEN_T);
5626 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5627 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5628 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5629 glEnable(GL_TEXTURE_GEN_R);
5630 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5631 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5632 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5635 break;
5637 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5639 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5640 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5641 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5642 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5643 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5644 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5646 glMatrixMode(GL_MODELVIEW);
5647 glPushMatrix();
5648 glLoadIdentity();
5649 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5650 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5651 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5652 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5653 glPopMatrix();
5655 glEnable(GL_TEXTURE_GEN_S);
5656 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5657 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5658 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5659 glEnable(GL_TEXTURE_GEN_T);
5660 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5661 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5662 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5663 glEnable(GL_TEXTURE_GEN_R);
5664 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5665 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5666 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5669 break;
5671 /* Unhandled types: */
5672 default:
5673 /* Todo: */
5674 /* ? disable GL_TEXTURE_GEN_n ? */
5675 glDisable(GL_TEXTURE_GEN_S);
5676 glDisable(GL_TEXTURE_GEN_T);
5677 glDisable(GL_TEXTURE_GEN_R);
5678 glDisable(GL_TEXTURE_GEN_Q);
5679 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5680 break;
5683 break;
5685 /* Unhandled */
5686 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5687 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5688 break;
5690 case WINED3DTSS_BUMPENVMAT00 :
5691 case WINED3DTSS_BUMPENVMAT01 :
5692 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5693 break;
5694 case WINED3DTSS_BUMPENVMAT10 :
5695 case WINED3DTSS_BUMPENVMAT11 :
5696 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5697 break;
5699 case WINED3DTSS_BUMPENVLSCALE :
5700 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5701 break;
5703 case WINED3DTSS_BUMPENVLOFFSET :
5704 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5705 break;
5707 case WINED3DTSS_RESULTARG :
5708 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5709 break;
5711 default:
5712 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5713 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5716 LEAVE_GL();
5718 return;
5721 /*****
5722 * Get / Set Texture Stage States
5723 * TODO: Verify against dx9 definitions
5724 *****/
5725 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5730 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5732 /* Reject invalid texture units */
5733 if (Stage >= GL_LIMITS(texture_stages)) {
5734 TRACE("Attempt to access invalid texture rejected\n");
5735 return WINED3DERR_INVALIDCALL;
5738 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5739 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5740 This->updateStateBlock->textureState[Stage][Type] = Value;
5742 return WINED3D_OK;
5745 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5747 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5748 *pValue = This->updateStateBlock->textureState[Stage][Type];
5749 return WINED3D_OK;
5752 /*****
5753 * Get / Set Texture
5754 *****/
5755 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 IWineD3DBaseTexture *oldTexture;
5760 oldTexture = This->updateStateBlock->textures[Stage];
5761 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5763 #if 0 /* TODO: check so vertex textures */
5764 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5765 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5766 return WINED3D_OK;
5768 #endif
5770 /* Reject invalid texture units */
5771 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5772 WARN("Attempt to access invalid texture rejected\n");
5773 return WINED3DERR_INVALIDCALL;
5776 if(pTexture != NULL) {
5777 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5779 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5780 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5781 return WINED3DERR_INVALIDCALL;
5785 oldTexture = This->updateStateBlock->textures[Stage];
5786 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5787 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5789 This->updateStateBlock->set.textures[Stage] = TRUE;
5790 This->updateStateBlock->changed.textures[Stage] = TRUE;
5791 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5792 This->updateStateBlock->textures[Stage] = pTexture;
5794 /* Handle recording of state blocks */
5795 if (This->isRecordingState) {
5796 TRACE("Recording... not performing anything\n");
5797 return WINED3D_OK;
5800 /** NOTE: MSDN says that setTexture increases the reference count,
5801 * and the the application nust set the texture back to null (or have a leaky application),
5802 * This means we should pass the refcount up to the parent
5803 *******************************/
5804 if (NULL != This->updateStateBlock->textures[Stage]) {
5805 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5808 if (NULL != oldTexture) {
5809 IWineD3DBaseTexture_Release(oldTexture);
5812 /* Reset color keying */
5813 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5814 BOOL enable_ckey = FALSE;
5816 if(pTexture) {
5817 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5818 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5821 if(enable_ckey) {
5822 glAlphaFunc(GL_NOTEQUAL, 0.0);
5823 checkGLcall("glAlphaFunc");
5827 return WINED3D_OK;
5830 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5834 /* Reject invalid texture units */
5835 if (Stage >= GL_LIMITS(sampler_stages)) {
5836 TRACE("Attempt to access invalid texture rejected\n");
5837 return WINED3DERR_INVALIDCALL;
5839 *ppTexture=This->updateStateBlock->textures[Stage];
5840 if (*ppTexture)
5841 IWineD3DBaseTexture_AddRef(*ppTexture);
5842 else
5843 return WINED3DERR_INVALIDCALL;
5844 return WINED3D_OK;
5847 /*****
5848 * Get Back Buffer
5849 *****/
5850 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5851 IWineD3DSurface **ppBackBuffer) {
5852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5853 IWineD3DSwapChain *swapChain;
5854 HRESULT hr;
5856 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5858 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5859 if (hr == WINED3D_OK) {
5860 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5861 IWineD3DSwapChain_Release(swapChain);
5862 } else {
5863 *ppBackBuffer = NULL;
5865 return hr;
5868 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5870 WARN("(%p) : stub, calling idirect3d for now\n", This);
5871 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5874 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5876 IWineD3DSwapChain *swapChain;
5877 HRESULT hr;
5879 if(iSwapChain > 0) {
5880 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5881 if (hr == WINED3D_OK) {
5882 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5883 IWineD3DSwapChain_Release(swapChain);
5884 } else {
5885 FIXME("(%p) Error getting display mode\n", This);
5887 } else {
5888 /* Don't read the real display mode,
5889 but return the stored mode instead. X11 can't change the color
5890 depth, and some apps are pretty angry if they SetDisplayMode from
5891 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5893 Also don't relay to the swapchain because with ddraw it's possible
5894 that there isn't a swapchain at all */
5895 pMode->Width = This->ddraw_width;
5896 pMode->Height = This->ddraw_height;
5897 pMode->Format = This->ddraw_format;
5898 pMode->RefreshRate = 0;
5899 hr = WINED3D_OK;
5902 return hr;
5905 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5907 TRACE("(%p)->(%p)\n", This, hWnd);
5909 This->ddraw_window = hWnd;
5910 return WINED3D_OK;
5913 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5915 TRACE("(%p)->(%p)\n", This, hWnd);
5917 *hWnd = This->ddraw_window;
5918 return WINED3D_OK;
5921 /*****
5922 * Stateblock related functions
5923 *****/
5925 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5927 IWineD3DStateBlockImpl *object;
5928 HRESULT temp_result;
5930 TRACE("(%p)", This);
5932 if (This->isRecordingState) {
5933 return WINED3DERR_INVALIDCALL;
5936 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5937 if (NULL == object ) {
5938 FIXME("(%p)Error allocating memory for stateblock\n", This);
5939 return E_OUTOFMEMORY;
5941 TRACE("(%p) created object %p\n", This, object);
5942 object->wineD3DDevice= This;
5943 /** FIXME: object->parent = parent; **/
5944 object->parent = NULL;
5945 object->blockType = WINED3DSBT_ALL;
5946 object->ref = 1;
5947 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5949 temp_result = allocate_shader_constants(object);
5950 if (WINED3D_OK != temp_result)
5951 return temp_result;
5953 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5954 This->updateStateBlock = object;
5955 This->isRecordingState = TRUE;
5957 TRACE("(%p) recording stateblock %p\n",This , object);
5958 return WINED3D_OK;
5961 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5964 if (!This->isRecordingState) {
5965 FIXME("(%p) not recording! returning error\n", This);
5966 *ppStateBlock = NULL;
5967 return WINED3DERR_INVALIDCALL;
5970 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5971 This->isRecordingState = FALSE;
5972 This->updateStateBlock = This->stateBlock;
5973 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5974 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5975 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5976 return WINED3D_OK;
5979 /*****
5980 * Scene related functions
5981 *****/
5982 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5983 /* At the moment we have no need for any functionality at the beginning
5984 of a scene */
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 TRACE("(%p) : stub\n", This);
5987 return WINED3D_OK;
5990 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5992 TRACE("(%p)\n", This);
5993 ENTER_GL();
5994 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5995 glFlush();
5996 checkGLcall("glFlush");
5998 TRACE("End Scene\n");
5999 if(This->renderTarget != NULL) {
6001 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
6002 IUnknown *targetContainer = NULL;
6003 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
6004 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
6005 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
6006 /** always dirtify for now. we must find a better way to see that surface have been modified
6007 (Modifications should will only occur via draw-primitive, but we do need better locking
6008 switching to render-to-texture should remove the overhead though.
6010 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
6011 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
6012 IWineD3DSurface_PreLoad(This->renderTarget);
6013 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
6014 IUnknown_Release(targetContainer);
6017 This->sceneEnded = TRUE;
6018 LEAVE_GL();
6019 return WINED3D_OK;
6022 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
6023 CONST RECT* pSourceRect, CONST RECT* pDestRect,
6024 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6026 IWineD3DSwapChain *swapChain = NULL;
6027 int i;
6028 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
6030 TRACE("(%p) Presenting the frame\n", This);
6032 for(i = 0 ; i < swapchains ; i ++) {
6034 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6035 TRACE("presentinng chain %d, %p\n", i, swapChain);
6036 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6037 IWineD3DSwapChain_Release(swapChain);
6040 return WINED3D_OK;
6043 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
6044 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
6045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6047 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
6048 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
6049 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6050 GLbitfield glMask = 0;
6051 GLboolean old_ztest;
6052 GLfloat old_z_clear_value;
6053 GLint old_stencil_clear_value;
6054 GLfloat old_color_clear_value[4];
6055 unsigned int i;
6056 CONST D3DRECT* curRect;
6058 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
6059 Count, pRects, Flags, Z, Stencil);
6061 ENTER_GL();
6063 glEnable(GL_SCISSOR_TEST);
6064 checkGLcall("glEnable GL_SCISSOR_TEST");
6066 if (Count > 0 && pRects) {
6067 curRect = pRects;
6068 } else {
6069 curRect = NULL;
6072 /* Only set the values up once, as they are not changing */
6073 if (Flags & D3DCLEAR_STENCIL) {
6074 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6075 glClearStencil(Stencil);
6076 checkGLcall("glClearStencil");
6077 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6078 glStencilMask(0xFFFFFFFF);
6081 if (Flags & D3DCLEAR_ZBUFFER) {
6082 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6083 glDepthMask(GL_TRUE);
6084 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6085 glClearDepth(Z);
6086 checkGLcall("glClearDepth");
6087 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6090 if (Flags & D3DCLEAR_TARGET) {
6091 TRACE("Clearing screen with glClear to color %lx\n", Color);
6092 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6093 glClearColor(D3DCOLOR_R(Color),
6094 D3DCOLOR_G(Color),
6095 D3DCOLOR_B(Color),
6096 D3DCOLOR_A(Color));
6097 checkGLcall("glClearColor");
6099 /* Clear ALL colors! */
6100 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6101 glMask = glMask | GL_COLOR_BUFFER_BIT;
6104 /* Now process each rect in turn */
6105 for (i = 0; i < Count || i == 0; i++) {
6107 if (curRect) {
6108 /* Note gl uses lower left, width/height */
6109 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
6110 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6111 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6112 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6113 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6114 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6115 checkGLcall("glScissor");
6116 } else {
6117 glScissor(This->stateBlock->viewport.X,
6118 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6119 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6120 This->stateBlock->viewport.Width,
6121 This->stateBlock->viewport.Height);
6122 checkGLcall("glScissor");
6125 /* Clear the selected rectangle (or full screen) */
6126 glClear(glMask);
6127 checkGLcall("glClear");
6129 /* Step to the next rectangle */
6130 if (curRect) curRect = curRect + sizeof(D3DRECT);
6133 /* Restore the old values (why..?) */
6134 if (Flags & D3DCLEAR_STENCIL) {
6135 glClearStencil(old_stencil_clear_value);
6136 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6138 if (Flags & D3DCLEAR_ZBUFFER) {
6139 glDepthMask(old_ztest);
6140 glClearDepth(old_z_clear_value);
6142 if (Flags & D3DCLEAR_TARGET) {
6143 glClearColor(old_color_clear_value[0],
6144 old_color_clear_value[1],
6145 old_color_clear_value[2],
6146 old_color_clear_value[3]);
6147 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6148 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6149 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6150 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6153 glDisable(GL_SCISSOR_TEST);
6154 checkGLcall("glDisable");
6155 LEAVE_GL();
6157 return WINED3D_OK;
6160 /*****
6161 * Drawing functions
6162 *****/
6163 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6164 UINT PrimitiveCount) {
6166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6167 This->stateBlock->streamIsUP = FALSE;
6169 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6170 debug_d3dprimitivetype(PrimitiveType),
6171 StartVertex, PrimitiveCount);
6172 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6173 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6176 return WINED3D_OK;
6179 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6180 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6181 D3DPRIMITIVETYPE PrimitiveType,
6182 INT baseVIndex, UINT minIndex,
6183 UINT NumVertices, UINT startIndex, UINT primCount) {
6185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6186 UINT idxStride = 2;
6187 IWineD3DIndexBuffer *pIB;
6188 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6190 pIB = This->stateBlock->pIndexData;
6191 This->stateBlock->streamIsUP = FALSE;
6193 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6194 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6195 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6197 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6198 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6199 idxStride = 2;
6200 } else {
6201 idxStride = 4;
6204 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6205 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6207 return WINED3D_OK;
6210 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6211 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6212 UINT VertexStreamZeroStride) {
6213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6215 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6216 debug_d3dprimitivetype(PrimitiveType),
6217 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6219 /* release the stream source */
6220 if (This->stateBlock->streamSource[0] != NULL) {
6221 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6224 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6225 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6226 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6227 This->stateBlock->streamIsUP = TRUE;
6229 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6230 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6232 /* MSDN specifies stream zero settings must be set to NULL */
6233 This->stateBlock->streamStride[0] = 0;
6234 This->stateBlock->streamSource[0] = NULL;
6236 /*stream zero settings set to null at end, as per the msdn */
6237 return WINED3D_OK;
6240 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6241 UINT MinVertexIndex, UINT NumVertices,
6242 UINT PrimitiveCount, CONST void* pIndexData,
6243 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6244 UINT VertexStreamZeroStride) {
6245 int idxStride;
6246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6248 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6249 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6250 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6251 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6253 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6254 idxStride = 2;
6255 } else {
6256 idxStride = 4;
6259 /* release the stream and index data */
6260 if (This->stateBlock->streamSource[0] != NULL) {
6261 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6263 if (This->stateBlock->pIndexData) {
6264 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6267 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6268 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6269 This->stateBlock->streamIsUP = TRUE;
6270 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6272 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6274 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6275 This->stateBlock->streamSource[0] = NULL;
6276 This->stateBlock->streamStride[0] = 0;
6277 This->stateBlock->pIndexData = NULL;
6279 return WINED3D_OK;
6282 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6284 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6285 return WINED3D_OK;
6287 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6288 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6290 HRESULT hr = WINED3D_OK;
6291 WINED3DRESOURCETYPE sourceType;
6292 WINED3DRESOURCETYPE destinationType;
6293 int i ,levels;
6295 /* TODO: think about moving the code into IWineD3DBaseTexture */
6297 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6299 /* verify that the source and destination textures aren't NULL */
6300 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6301 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6302 This, pSourceTexture, pDestinationTexture);
6303 hr = WINED3DERR_INVALIDCALL;
6306 if (pSourceTexture == pDestinationTexture) {
6307 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6308 This, pSourceTexture, pDestinationTexture);
6309 hr = WINED3DERR_INVALIDCALL;
6311 /* Verify that the source and destination textures are the same type */
6312 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6313 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6315 if (sourceType != destinationType) {
6316 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6317 This);
6318 hr = WINED3DERR_INVALIDCALL;
6321 /* check that both textures have the identical numbers of levels */
6322 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6323 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6324 hr = WINED3DERR_INVALIDCALL;
6327 if (WINED3D_OK == hr) {
6329 /* Make sure that the destination texture is loaded */
6330 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6332 /* Update every surface level of the texture */
6333 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6335 switch (sourceType) {
6336 case WINED3DRTYPE_TEXTURE:
6338 IWineD3DSurface *srcSurface;
6339 IWineD3DSurface *destSurface;
6341 for (i = 0 ; i < levels ; ++i) {
6342 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6343 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6344 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6345 IWineD3DSurface_Release(srcSurface);
6346 IWineD3DSurface_Release(destSurface);
6347 if (WINED3D_OK != hr) {
6348 WARN("(%p) : Call to update surface failed\n", This);
6349 return hr;
6353 break;
6354 case WINED3DRTYPE_CUBETEXTURE:
6356 IWineD3DSurface *srcSurface;
6357 IWineD3DSurface *destSurface;
6358 WINED3DCUBEMAP_FACES faceType;
6360 for (i = 0 ; i < levels ; ++i) {
6361 /* Update each cube face */
6362 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6363 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6364 if (WINED3D_OK != hr) {
6365 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6366 } else {
6367 TRACE("Got srcSurface %p\n", srcSurface);
6369 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6370 if (WINED3D_OK != hr) {
6371 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6372 } else {
6373 TRACE("Got desrSurface %p\n", destSurface);
6375 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6376 IWineD3DSurface_Release(srcSurface);
6377 IWineD3DSurface_Release(destSurface);
6378 if (WINED3D_OK != hr) {
6379 WARN("(%p) : Call to update surface failed\n", This);
6380 return hr;
6385 break;
6386 #if 0 /* TODO: Add support for volume textures */
6387 case WINED3DRTYPE_VOLUMETEXTURE:
6389 IWineD3DVolume srcVolume = NULL;
6390 IWineD3DSurface destVolume = NULL;
6392 for (i = 0 ; i < levels ; ++i) {
6393 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6394 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6395 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6396 IWineD3DVolume_Release(srcSurface);
6397 IWineD3DVolume_Release(destSurface);
6398 if (WINED3D_OK != hr) {
6399 WARN("(%p) : Call to update volume failed\n", This);
6400 return hr;
6404 break;
6405 #endif
6406 default:
6407 FIXME("(%p) : Unsupported source and destination type\n", This);
6408 hr = WINED3DERR_INVALIDCALL;
6412 return hr;
6415 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6416 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6417 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 TRACE("(%p) : stub\n", This);
6421 return WINED3D_OK;
6423 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6425 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6426 * NOTE It may be best to move the code into surface to occomplish this
6427 ****************************************/
6429 WINED3DSURFACE_DESC surfaceDesc;
6430 unsigned int surfaceWidth, surfaceHeight;
6431 glDescriptor *targetGlDescription = NULL;
6432 glDescriptor *surfaceGlDescription = NULL;
6433 IWineD3DSwapChainImpl *container = NULL;
6435 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6436 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6437 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6439 surfaceDesc.Width = &surfaceWidth;
6440 surfaceDesc.Height = &surfaceHeight;
6441 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6442 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6444 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6445 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6446 ENTER_GL();
6447 /* TODO: opengl Context switching for swapchains etc... */
6448 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6449 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6450 glReadBuffer(GL_BACK);
6451 vcheckGLcall("glReadBuffer(GL_BACK)");
6452 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6453 glReadBuffer(GL_FRONT);
6454 vcheckGLcall("glReadBuffer(GL_FRONT)");
6455 } else if (pRenderTarget == This->depthStencilBuffer) {
6456 FIXME("Reading of depthstencil not yet supported\n");
6459 glReadPixels(surfaceGlDescription->target,
6460 surfaceGlDescription->level,
6461 surfaceWidth,
6462 surfaceHeight,
6463 surfaceGlDescription->glFormat,
6464 surfaceGlDescription->glType,
6465 (void *)IWineD3DSurface_GetData(pSurface));
6466 vcheckGLcall("glReadPixels(...)");
6467 if(NULL != container ){
6468 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6470 } else {
6471 IWineD3DBaseTexture *container;
6472 GLenum textureDimensions = GL_TEXTURE_2D;
6474 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6475 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6476 IWineD3DBaseTexture_Release(container);
6478 /* TODO: 2D -> Cube surface coppies etc.. */
6479 if (surfaceGlDescription->target != textureDimensions) {
6480 FIXME("(%p) : Texture dimension mismatch\n", This);
6482 glEnable(textureDimensions);
6483 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6484 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6485 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6486 vcheckGLcall("glBindTexture");
6487 glGetTexImage(surfaceGlDescription->target,
6488 surfaceGlDescription->level,
6489 surfaceGlDescription->glFormat,
6490 surfaceGlDescription->glType,
6491 (void *)IWineD3DSurface_GetData(pSurface));
6492 glDisable(textureDimensions);
6493 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6496 LEAVE_GL();
6497 return WINED3D_OK;
6500 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6501 IWineD3DSwapChain *swapChain;
6502 HRESULT hr;
6503 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6504 if(hr == WINED3D_OK) {
6505 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6506 IWineD3DSwapChain_Release(swapChain);
6508 return hr;
6511 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6513 /* return a sensible default */
6514 *pNumPasses = 1;
6515 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6516 FIXME("(%p) : stub\n", This);
6517 return WINED3D_OK;
6520 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST 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 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6530 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6531 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6532 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6534 TRACE("(%p) : returning\n", This);
6535 return WINED3D_OK;
6538 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 int j;
6541 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6542 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6543 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6544 return WINED3DERR_INVALIDCALL;
6546 for (j = 0; j < 256; ++j) {
6547 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6548 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6549 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6550 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6552 TRACE("(%p) : returning\n", This);
6553 return WINED3D_OK;
6556 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6558 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6559 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6560 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6561 return WINED3DERR_INVALIDCALL;
6563 /*TODO: stateblocks */
6564 This->currentPalette = PaletteNumber;
6565 TRACE("(%p) : returning\n", This);
6566 return WINED3D_OK;
6569 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6571 if (PaletteNumber == NULL) {
6572 WARN("(%p) : returning Invalid Call\n", This);
6573 return WINED3DERR_INVALIDCALL;
6575 /*TODO: stateblocks */
6576 *PaletteNumber = This->currentPalette;
6577 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6578 return WINED3D_OK;
6581 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6583 static BOOL showFixmes = TRUE;
6584 if (showFixmes) {
6585 FIXME("(%p) : stub\n", This);
6586 showFixmes = FALSE;
6589 This->softwareVertexProcessing = bSoftware;
6590 return WINED3D_OK;
6594 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6596 static BOOL showFixmes = TRUE;
6597 if (showFixmes) {
6598 FIXME("(%p) : stub\n", This);
6599 showFixmes = FALSE;
6601 return This->softwareVertexProcessing;
6605 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6607 IWineD3DSwapChain *swapChain;
6608 HRESULT hr;
6610 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6612 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6613 if(hr == WINED3D_OK){
6614 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6615 IWineD3DSwapChain_Release(swapChain);
6616 }else{
6617 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6619 return hr;
6623 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6625 static BOOL showfixmes = TRUE;
6626 if(nSegments != 0.0f) {
6627 if( showfixmes) {
6628 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6629 showfixmes = FALSE;
6632 return WINED3D_OK;
6635 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6637 static BOOL showfixmes = TRUE;
6638 if( showfixmes) {
6639 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6640 showfixmes = FALSE;
6642 return 0.0f;
6645 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6647 /** TODO: remove casts to IWineD3DSurfaceImpl
6648 * NOTE: move code to surface to accomplish this
6649 ****************************************/
6650 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6651 int srcWidth, srcHeight;
6652 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6653 WINED3DFORMAT destFormat, srcFormat;
6654 UINT destSize;
6655 int destLeft, destTop;
6656 WINED3DPOOL srcPool, destPool;
6657 int offset = 0;
6658 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6659 glDescriptor *glDescription = NULL;
6660 GLenum textureDimensions = GL_TEXTURE_2D;
6661 IWineD3DBaseTexture *baseTexture;
6663 WINED3DSURFACE_DESC winedesc;
6665 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6666 memset(&winedesc, 0, sizeof(winedesc));
6667 winedesc.Width = &srcSurfaceWidth;
6668 winedesc.Height = &srcSurfaceHeight;
6669 winedesc.Pool = &srcPool;
6670 winedesc.Format = &srcFormat;
6672 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6674 winedesc.Width = &destSurfaceWidth;
6675 winedesc.Height = &destSurfaceHeight;
6676 winedesc.Pool = &destPool;
6677 winedesc.Format = &destFormat;
6678 winedesc.Size = &destSize;
6680 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6682 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6683 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6684 return WINED3DERR_INVALIDCALL;
6687 if (destFormat == WINED3DFMT_UNKNOWN) {
6688 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6689 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6691 /* Get the update surface description */
6692 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6695 /* Make sure the surface is loaded and up to date */
6696 IWineD3DSurface_PreLoad(pDestinationSurface);
6698 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6700 ENTER_GL();
6702 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6703 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6704 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6705 destLeft = pDestPoint ? pDestPoint->x : 0;
6706 destTop = pDestPoint ? pDestPoint->y : 0;
6709 /* This function doesn't support compressed textures
6710 the pitch is just bytesPerPixel * width */
6711 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6712 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6713 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6714 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6716 /* TODO DXT formats */
6718 if(pSourceRect != NULL && pSourceRect->top != 0){
6719 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6721 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6722 ,This
6723 ,glDescription->level
6724 ,destLeft
6725 ,destTop
6726 ,srcWidth
6727 ,srcHeight
6728 ,glDescription->glFormat
6729 ,glDescription->glType
6730 ,IWineD3DSurface_GetData(pSourceSurface)
6733 /* Sanity check */
6734 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6736 /* need to lock the surface to get the data */
6737 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6740 /* TODO: Cube and volume support */
6741 if(rowoffset != 0){
6742 /* not a whole row so we have to do it a line at a time */
6743 int j;
6745 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6746 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6748 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6750 glTexSubImage2D(glDescription->target
6751 ,glDescription->level
6752 ,destLeft
6754 ,srcWidth
6756 ,glDescription->glFormat
6757 ,glDescription->glType
6758 ,data /* could be quicker using */
6760 data += rowoffset;
6763 } else { /* Full width, so just write out the whole texture */
6765 if (WINED3DFMT_DXT1 == destFormat ||
6766 WINED3DFMT_DXT2 == destFormat ||
6767 WINED3DFMT_DXT3 == destFormat ||
6768 WINED3DFMT_DXT4 == destFormat ||
6769 WINED3DFMT_DXT5 == destFormat) {
6770 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6771 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6772 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6773 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6774 } if (destFormat != srcFormat) {
6775 FIXME("Updating mixed format compressed texture is not curretly support\n");
6776 } else {
6777 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6778 glDescription->level,
6779 glDescription->glFormatInternal,
6780 srcWidth,
6781 srcHeight,
6783 destSize,
6784 IWineD3DSurface_GetData(pSourceSurface));
6786 } else {
6787 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6791 } else {
6792 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6794 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6795 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6796 data returned by GetData non-power2 width/height with hardware non-power2
6797 pow2Width/height are set to surface width height, repacking isn't needed so it
6798 doesn't matter which function gets called. */
6799 glTexSubImage2D(glDescription->target
6800 ,glDescription->level
6801 ,destLeft
6802 ,destTop
6803 ,srcWidth
6804 ,srcHeight
6805 ,glDescription->glFormat
6806 ,glDescription->glType
6807 ,IWineD3DSurface_GetData(pSourceSurface)
6809 } else {
6811 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6812 glTexSubImage2D(glDescription->target
6813 ,glDescription->level
6814 ,destLeft
6815 ,destTop
6816 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6817 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6818 ,glDescription->glFormat
6819 ,glDescription->glType
6820 ,IWineD3DSurface_GetData(pSourceSurface)
6826 checkGLcall("glTexSubImage2D");
6828 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6829 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6830 * surface bigger than it needs to be hmm.. */
6831 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6832 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6833 IWineD3DBaseTexture_Release(baseTexture);
6836 glDisable(textureDimensions); /* This needs to be managed better.... */
6837 LEAVE_GL();
6839 return WINED3D_OK;
6842 /* Used by DirectX 8 */
6843 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6844 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6845 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6848 HRESULT hr = WINED3D_OK;
6849 WINED3DFORMAT srcFormat, destFormat;
6850 UINT srcWidth, destWidth;
6851 UINT srcHeight, destHeight;
6852 UINT srcSize;
6853 WINED3DSURFACE_DESC winedesc;
6855 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6856 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6859 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6860 memset(&winedesc, 0, sizeof(winedesc));
6862 winedesc.Format = &srcFormat;
6863 winedesc.Width = &srcWidth;
6864 winedesc.Height = &srcHeight;
6865 winedesc.Size = &srcSize;
6866 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6868 winedesc.Format = &destFormat;
6869 winedesc.Width = &destWidth;
6870 winedesc.Height = &destHeight;
6871 winedesc.Size = NULL;
6872 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6874 /* Check that the source and destination formats match */
6875 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6876 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6877 return WINED3DERR_INVALIDCALL;
6878 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6879 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6880 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6881 destFormat = srcFormat;
6884 /* Quick if complete copy ... */
6885 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6887 if (srcWidth == destWidth && srcHeight == destHeight) {
6888 WINED3DLOCKED_RECT lrSrc;
6889 WINED3DLOCKED_RECT lrDst;
6890 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6891 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6892 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6894 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6896 IWineD3DSurface_UnlockRect(pSourceSurface);
6897 IWineD3DSurface_UnlockRect(pDestinationSurface);
6898 TRACE("Unlocked src and dst\n");
6900 } else {
6902 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6903 hr = WINED3DERR_INVALIDCALL;
6906 } else {
6908 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6910 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6911 unsigned int i;
6913 /* Copy rect by rect */
6914 for (i = 0; i < cRects; ++i) {
6915 CONST RECT* r = &pSourceRectsArray[i];
6916 CONST POINT* p = &pDestPointsArray[i];
6917 int copyperline;
6918 int j;
6919 WINED3DLOCKED_RECT lrSrc;
6920 WINED3DLOCKED_RECT lrDst;
6921 RECT dest_rect;
6923 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6924 if (srcFormat == WINED3DFMT_DXT1) {
6925 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6926 } else {
6927 copyperline = ((r->right - r->left) * bytesPerPixel);
6930 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6931 dest_rect.left = p->x;
6932 dest_rect.top = p->y;
6933 dest_rect.right = p->x + (r->right - r->left);
6934 dest_rect.bottom= p->y + (r->bottom - r->top);
6935 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6936 TRACE("Locked src and dst\n");
6938 /* Find where to start */
6939 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6940 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6942 IWineD3DSurface_UnlockRect(pSourceSurface);
6943 IWineD3DSurface_UnlockRect(pDestinationSurface);
6944 TRACE("Unlocked src and dst\n");
6946 } else {
6947 unsigned int i;
6948 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6949 int copyperline;
6950 int j;
6951 WINED3DLOCKED_RECT lrSrc;
6952 WINED3DLOCKED_RECT lrDst;
6953 RECT dest_rect;
6955 for(i=0; i < cRects; i++) {
6956 CONST RECT* r = &pSourceRectsArray[i];
6958 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6959 if (srcFormat == WINED3DFMT_DXT1) {
6960 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6961 } else {
6962 copyperline = ((r->right - r->left) * bytesPerPixel);
6964 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6965 dest_rect.left = 0;
6966 dest_rect.top = 0;
6967 dest_rect.right = r->right - r->left;
6968 dest_rect.bottom= r->bottom - r->top;
6969 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6970 TRACE("Locked src and dst\n");
6971 /* Find where to start */
6972 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6973 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6975 IWineD3DSurface_UnlockRect(pSourceSurface);
6976 IWineD3DSurface_UnlockRect(pDestinationSurface);
6977 TRACE("Unlocked src and dst\n");
6982 return hr;
6985 /* Implementation details at http://developer.nvidia.com/attach/6494
6987 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6988 hmm.. no longer supported use
6989 OpenGL evaluators or tessellate surfaces within your application.
6992 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6993 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6995 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6996 FIXME("(%p) : Stub\n", This);
6997 return WINED3D_OK;
7001 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
7002 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
7003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7004 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
7005 FIXME("(%p) : Stub\n", This);
7006 return WINED3D_OK;
7009 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
7010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7011 TRACE("(%p) Handle(%d)\n", This, Handle);
7012 FIXME("(%p) : Stub\n", This);
7013 return WINED3D_OK;
7016 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
7017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7018 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
7019 DDBLTFX BltFx;
7020 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
7022 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
7023 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
7024 return WINED3DERR_INVALIDCALL;
7027 /* Just forward this to the DirectDraw blitting engine */
7028 memset(&BltFx, 0, sizeof(BltFx));
7029 BltFx.dwSize = sizeof(BltFx);
7030 BltFx.u5.dwFillColor = color;
7031 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
7034 /* rendertarget and deptth stencil functions */
7035 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
7036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7038 /* FIXME: Implelent RenderTargetIndex >0 */
7039 if(RenderTargetIndex > 0)
7040 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
7042 *ppRenderTarget = This->renderTarget;
7043 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
7044 /* Note inc ref on returned surface */
7045 if(*ppRenderTarget != NULL)
7046 IWineD3DSurface_AddRef(*ppRenderTarget);
7047 return WINED3D_OK;
7050 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
7051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7052 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
7053 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
7054 IWineD3DSwapChainImpl *Swapchain;
7055 HRESULT hr;
7057 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
7059 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7060 if(hr != WINED3D_OK) {
7061 ERR("Can't get the swapchain\n");
7062 return hr;
7065 /* Make sure to release the swapchain */
7066 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7068 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7069 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7070 return WINED3DERR_INVALIDCALL;
7072 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7073 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7074 return WINED3DERR_INVALIDCALL;
7077 if(Swapchain->frontBuffer != Front) {
7078 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7080 if(Swapchain->frontBuffer)
7081 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7082 Swapchain->frontBuffer = Front;
7084 if(Swapchain->frontBuffer) {
7085 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7089 if(Back && !Swapchain->backBuffer) {
7090 /* We need memory for the back buffer array - only one back buffer this way */
7091 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7092 if(!Swapchain->backBuffer) {
7093 ERR("Out of memory\n");
7094 return E_OUTOFMEMORY;
7098 if(Swapchain->backBuffer[0] != Back) {
7099 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7100 ENTER_GL();
7101 if(!Swapchain->backBuffer[0]) {
7102 /* GL was told to draw to the front buffer at creation,
7103 * undo that
7105 glDrawBuffer(GL_BACK);
7106 checkGLcall("glDrawBuffer(GL_BACK)");
7107 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7108 Swapchain->presentParms.BackBufferCount = 1;
7109 } else if (!Back) {
7110 /* That makes problems - disable for now */
7111 /* glDrawBuffer(GL_FRONT); */
7112 checkGLcall("glDrawBuffer(GL_FRONT)");
7113 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7114 Swapchain->presentParms.BackBufferCount = 0;
7116 LEAVE_GL();
7118 if(Swapchain->backBuffer[0])
7119 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7120 Swapchain->backBuffer[0] = Back;
7122 if(Swapchain->backBuffer[0]) {
7123 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7124 } else {
7125 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7130 return WINED3D_OK;
7133 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7135 *ppZStencilSurface = This->depthStencilBuffer;
7136 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7138 if(*ppZStencilSurface != NULL) {
7139 /* Note inc ref on returned surface */
7140 IWineD3DSurface_AddRef(*ppZStencilSurface);
7142 return WINED3D_OK;
7145 /* internal static helper functions */
7146 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7147 IWineD3DSurface *RenderSurface);
7149 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7151 HRESULT hr = WINED3D_OK;
7152 WINED3DVIEWPORT viewport;
7154 TRACE("(%p) Swapping rendertarget\n",This);
7155 if (RenderTargetIndex > 0) {
7156 FIXME("(%p) Render targets other than the first are not supported\n",This);
7157 RenderTargetIndex = 0;
7160 /* MSDN says that null disables the render target
7161 but a device must always be associated with a render target
7162 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7164 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7165 for more details
7167 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7168 FIXME("Trying to set render target 0 to NULL\n");
7169 return WINED3DERR_INVALIDCALL;
7171 /* TODO: replace Impl* usage with interface usage */
7172 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7173 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);
7174 return WINED3DERR_INVALIDCALL;
7176 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7177 * builds, but I think wine counts as a 'debug' build for now.
7178 ******************************/
7179 /* If we are trying to set what we already have, don't bother */
7180 if (pRenderTarget == This->renderTarget) {
7181 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7182 } else {
7183 /* Otherwise, set the render target up */
7185 if (FALSE == This->sceneEnded) {
7186 IWineD3DDevice_EndScene(iface);
7188 TRACE("clearing renderer\n");
7189 /* IWineD3DDeviceImpl_CleanRender(iface); */
7190 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7191 depending on the renter target implementation being used.
7192 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7193 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7194 stencil buffer and incure an extra memory overhead */
7195 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7198 if (SUCCEEDED(hr)) {
7199 /* Finally, reset the viewport as the MSDN states. */
7200 /* TODO: Replace impl usage */
7201 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7202 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7203 viewport.X = 0;
7204 viewport.Y = 0;
7205 viewport.MaxZ = 1.0f;
7206 viewport.MinZ = 0.0f;
7207 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7208 } else {
7209 FIXME("Unknown error setting the render target\n");
7211 This->sceneEnded = FALSE;
7212 return hr;
7215 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7217 HRESULT hr = WINED3D_OK;
7218 IWineD3DSurface *tmp;
7220 TRACE("(%p) Swapping z-buffer\n",This);
7222 if (pNewZStencil == This->stencilBufferTarget) {
7223 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7224 } else {
7225 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7226 * depending on the renter target implementation being used.
7227 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7228 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7229 * stencil buffer and incure an extra memory overhead
7230 ******************************************************/
7233 tmp = This->stencilBufferTarget;
7234 This->stencilBufferTarget = pNewZStencil;
7235 /* should we be calling the parent or the wined3d surface? */
7236 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7237 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7238 hr = WINED3D_OK;
7239 /** TODO: glEnable/glDisable on depth/stencil depending on
7240 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7241 **********************************************************/
7244 return hr;
7248 #ifdef GL_VERSION_1_3
7249 /* Internal functions not in DirectX */
7250 /** TODO: move this off to the opengl context manager
7251 *(the swapchain doesn't need to know anything about offscreen rendering!)
7252 ****************************************************/
7254 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7258 TRACE("(%p), %p\n", This, swapchain);
7260 if (swapchain->win != swapchain->drawable) {
7261 /* Set everything back the way it ws */
7262 swapchain->render_ctx = swapchain->glCtx;
7263 swapchain->drawable = swapchain->win;
7265 return WINED3D_OK;
7268 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7269 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7271 int i;
7272 unsigned int width;
7273 unsigned int height;
7274 WINED3DFORMAT format;
7275 WINED3DSURFACE_DESC surfaceDesc;
7276 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7277 surfaceDesc.Width = &width;
7278 surfaceDesc.Height = &height;
7279 surfaceDesc.Format = &format;
7280 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7281 *context = NULL;
7282 /* I need a get width/height function (and should do something with the format) */
7283 for (i = 0; i < CONTEXT_CACHE; ++i) {
7284 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7285 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7286 the pSurface can be set to 0 allowing it to be reused from cache **/
7287 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7288 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7289 *context = &This->contextCache[i];
7290 break;
7292 if (This->contextCache[i].Width == 0) {
7293 This->contextCache[i].pSurface = pSurface;
7294 This->contextCache[i].Width = width;
7295 This->contextCache[i].Height = height;
7296 *context = &This->contextCache[i];
7297 break;
7300 if (i == CONTEXT_CACHE) {
7301 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7302 glContext *dropContext = 0;
7303 for (i = 0; i < CONTEXT_CACHE; i++) {
7304 if (This->contextCache[i].usedcount < minUsage) {
7305 dropContext = &This->contextCache[i];
7306 minUsage = This->contextCache[i].usedcount;
7309 /* clean up the context (this doesn't work for ATI at the moment */
7310 #if 0
7311 glXDestroyContext(swapchain->display, dropContext->context);
7312 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7313 #endif
7314 FIXME("Leak\n");
7315 dropContext->Width = 0;
7316 dropContext->pSurface = pSurface;
7317 *context = dropContext;
7318 } else {
7319 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7320 for (i = 0; i < CONTEXT_CACHE; i++) {
7321 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7325 if (*context != NULL)
7326 return WINED3D_OK;
7327 else
7328 return E_OUTOFMEMORY;
7330 #endif
7332 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7333 * the functionality needs splitting up so that we don't do more than we should do.
7334 * this only seems to impact performance a little.
7335 ******************************/
7336 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7337 IWineD3DSurface *RenderSurface) {
7338 HRESULT ret = WINED3DERR_INVALIDCALL;
7339 BOOL oldRecording;
7340 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7343 * Currently only active for GLX >= 1.3
7344 * for others versions we'll have to use GLXPixmaps
7346 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7347 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7348 * so only check OpenGL version
7349 * ..........................
7350 * I don't believe that it is a problem with NVidia headers,
7351 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7352 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7353 * ATI Note:
7354 * Your application will report GLX version 1.2 on glXQueryVersion.
7355 * However, it is safe to call the GLX 1.3 functions as described below.
7357 #if defined(GL_VERSION_1_3)
7359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7360 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7361 IWineD3DSurface *tmp;
7362 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7363 GLXFBConfig* cfgs = NULL;
7364 int nCfgs = 0;
7365 int attribs[256];
7366 int nAttribs = 0;
7367 IWineD3DSwapChain *currentSwapchain;
7368 IWineD3DSwapChainImpl *swapchain;
7369 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7370 * but switch them off if the StencilSurface is set to NULL
7371 ** *********************************************************/
7372 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7373 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7375 /**TODO:
7376 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7377 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7380 #define PUSH1(att) attribs[nAttribs++] = (att);
7381 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7383 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7385 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7386 IWineD3DSwapChainImpl *impSwapChain;
7387 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7388 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7389 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7392 ENTER_GL();
7394 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7395 PUSH2(GLX_X_RENDERABLE, TRUE);
7396 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7397 TRACE("calling makeglcfg\n");
7398 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7399 PUSH1(None);
7401 TRACE("calling chooseFGConfig\n");
7402 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7403 attribs, &nCfgs);
7405 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7406 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7407 why we failed and only show this message once! */
7408 MESSAGE("Failed to find exact match, finding alternative but you may suffer performance issues, try changing xfree's depth to match the requested depth\n"); /**/
7409 nAttribs = 0;
7410 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7411 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7412 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7413 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7414 TRACE("calling makeglcfg\n");
7415 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7416 PUSH1(None);
7417 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7418 attribs, &nCfgs);
7421 if (NULL != cfgs) {
7422 #ifdef EXTRA_TRACES
7423 int i;
7424 for (i = 0; i < nCfgs; ++i) {
7425 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7426 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7427 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7430 if (NULL != This->renderTarget) {
7431 glFlush();
7432 vcheckGLcall("glFlush");
7433 /** This is only useful if the old render target was a swapchain,
7434 * we need to supercede this with a function that displays
7435 * the current buffer on the screen. This is easy to do in glx1.3 but
7436 * we need to do copy-write pixels in glx 1.2.
7437 ************************************************/
7438 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7440 printf("Hit Enter to get next frame ...\n");
7441 getchar();
7443 #endif
7446 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7447 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7448 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7452 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7453 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7454 **********************************************************************/
7455 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7456 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7457 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7458 TRACE("making swapchain active\n");
7459 if (RenderSurface != This->renderTarget) {
7460 BOOL backbuf = FALSE;
7461 int i;
7463 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7464 if(RenderSurface == swapchain->backBuffer[i]) {
7465 backbuf = TRUE;
7466 break;
7470 if (backbuf) {
7471 } else {
7472 /* This could be flagged so that some operations work directly with the front buffer */
7473 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7475 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7476 == False) {
7477 TRACE("Error in setting current context: context %p drawable %ld !\n",
7478 impSwapChain->glCtx, impSwapChain->win);
7481 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7483 checkGLcall("glXMakeContextCurrent");
7485 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7487 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7489 /** ********************************************************************
7490 * This is a quickly hacked out implementation of offscreen textures.
7491 * It will work in most cases but there may be problems if the client
7492 * modifies the texture directly, or expects the contents of the rendertarget
7493 * to be persistent.
7495 * There are some real speed vs compatibility issues here:
7496 * we should really use a new context for every texture, but that eats ram.
7497 * we should also be restoring the texture to the pbuffer but that eats CPU
7498 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7499 * but if this means reusing the display backbuffer then we need to make sure that
7500 * states are correctly preserved.
7501 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7502 * and gain a good performance increase at the cost of compatibility.
7503 * I would suggest that, when this is the case, a user configurable flag be made
7504 * available, allowing the user to choose the best emulated experience for them.
7505 *********************************************************************/
7507 XVisualInfo *visinfo;
7508 glContext *newContext;
7510 /* Here were using a shared context model */
7511 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7512 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7515 /* If the context doesn't exist then create a new one */
7516 /* TODO: This should really be part of findGlContext */
7517 if (NULL == newContext->context) {
7519 TRACE("making new buffer\n");
7520 nAttribs = 0;
7521 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7522 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7523 PUSH1(None);
7525 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7527 /** ****************************************
7528 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7529 *they note:
7530 * In future releases, we may provide the calls glXCreateNewContext,
7531 * glXQueryDrawable and glXMakeContextCurrent.
7532 * so until then we have to use glXGetVisualFromFBConfig &co..
7533 ********************************************/
7536 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7537 if (!visinfo) {
7538 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7539 } else {
7540 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7541 XFree(visinfo);
7544 if (NULL == newContext || NULL == newContext->context) {
7545 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7546 } else {
7547 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7548 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7549 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7552 /* Clean up the old context */
7553 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7554 /* Set the current context of the swapchain to the new context */
7555 impSwapChain->drawable = newContext->drawable;
7556 impSwapChain->render_ctx = newContext->context;
7560 /* Disable recording, and apply the stateblock to the new context
7561 * FIXME: This is a bit of a hack, each context should know it's own state,
7562 * the directX current directX state should then be applied to the context */
7563 oldUpdateStateBlock = This->updateStateBlock;
7564 oldRecording= This->isRecordingState;
7565 This->isRecordingState = FALSE;
7566 This->updateStateBlock = This->stateBlock;
7567 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7569 /* clean up the current rendertargets swapchain (if it belonged to one) */
7570 if (currentSwapchain != NULL) {
7571 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7574 /* Were done with the opengl context management, setup the rendertargets */
7576 tmp = This->renderTarget;
7577 This->renderTarget = RenderSurface;
7578 IWineD3DSurface_AddRef(This->renderTarget);
7579 IWineD3DSurface_Release(tmp);
7582 DWORD value;
7584 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7585 /* Check that the container is not a swapchain member */
7587 IWineD3DSwapChain *tmpSwapChain;
7588 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7589 This->renderUpsideDown = TRUE;
7590 }else{
7591 This->renderUpsideDown = FALSE;
7592 IWineD3DSwapChain_Release(tmpSwapChain);
7594 /* Force updating the cull mode */
7595 TRACE("setting render state\n");
7596 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7597 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7599 /* Force updating projection matrix */
7600 This->last_was_rhw = FALSE;
7601 This->proj_valid = FALSE;
7604 /* Restore recording state */
7605 This->isRecordingState = oldRecording;
7606 This->updateStateBlock = oldUpdateStateBlock;
7608 ret = WINED3D_OK;
7610 if (cfgs != NULL) {
7611 XFree(cfgs);
7612 } else {
7613 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7614 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7617 #undef PUSH1
7618 #undef PUSH2
7619 if ( NULL != impSwapChain) {
7620 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7622 LEAVE_GL();
7624 #endif
7625 return ret;
7628 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7629 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7631 /* TODO: the use of Impl is deprecated. */
7632 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7634 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7636 /* some basic validation checks */
7637 if(This->cursorTexture) {
7638 ENTER_GL();
7639 glDeleteTextures(1, &This->cursorTexture);
7640 LEAVE_GL();
7641 This->cursorTexture = 0;
7644 if(pCursorBitmap) {
7645 /* MSDN: Cursor must be A8R8G8B8 */
7646 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7647 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7648 return WINED3DERR_INVALIDCALL;
7651 /* MSDN: Cursor must be smaller than the display mode */
7652 if(pSur->currentDesc.Width > This->ddraw_width ||
7653 pSur->currentDesc.Height > This->ddraw_height) {
7654 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %ldx%ld\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7655 return WINED3DERR_INVALIDCALL;
7658 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7659 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7660 * Texture and Blitting code to draw the cursor
7662 pSur->Flags |= SFLAG_FORCELOAD;
7663 IWineD3DSurface_PreLoad(pCursorBitmap);
7664 pSur->Flags &= ~SFLAG_FORCELOAD;
7665 /* Do not store the surface's pointer because the application may release
7666 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7667 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7669 This->cursorTexture = pSur->glDescription.textureName;
7670 This->cursorWidth = pSur->currentDesc.Width;
7671 This->cursorHeight = pSur->currentDesc.Height;
7672 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7675 This->xHotSpot = XHotSpot;
7676 This->yHotSpot = YHotSpot;
7677 return WINED3D_OK;
7680 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7682 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7684 This->xScreenSpace = XScreenSpace;
7685 This->yScreenSpace = YScreenSpace;
7687 return;
7691 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7693 BOOL oldVisible = This->bCursorVisible;
7694 TRACE("(%p) : visible(%d)\n", This, bShow);
7696 if(This->cursorTexture)
7697 This->bCursorVisible = bShow;
7699 return oldVisible;
7702 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7704 TRACE("(%p) : state (%lu)\n", This, This->state);
7705 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7706 switch (This->state) {
7707 case WINED3D_OK:
7708 return WINED3D_OK;
7709 case WINED3DERR_DEVICELOST:
7711 ResourceList *resourceList = This->resources;
7712 while (NULL != resourceList) {
7713 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7714 return WINED3DERR_DEVICENOTRESET;
7715 resourceList = resourceList->next;
7717 return WINED3DERR_DEVICELOST;
7719 case WINED3DERR_DRIVERINTERNALERROR:
7720 return WINED3DERR_DRIVERINTERNALERROR;
7723 /* Unknown state */
7724 return WINED3DERR_DRIVERINTERNALERROR;
7728 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7730 /** FIXME: Resource tracking needs to be done,
7731 * The closes we can do to this is set the priorities of all managed textures low
7732 * and then reset them.
7733 ***********************************************************/
7734 FIXME("(%p) : stub\n", This);
7735 return WINED3D_OK;
7738 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7740 /** FIXME: Resource trascking needs to be done.
7741 * in effect this pulls all non only default
7742 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7743 * and should clear down the context and set it up according to pPresentationParameters
7744 ***********************************************************/
7745 FIXME("(%p) : stub\n", This);
7746 return WINED3D_OK;
7749 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7751 /** FIXME: always true at the moment **/
7752 if(bEnableDialogs == FALSE) {
7753 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7755 return WINED3D_OK;
7759 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7761 TRACE("(%p) : pParameters %p\n", This, pParameters);
7763 *pParameters = This->createParms;
7764 return WINED3D_OK;
7767 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7768 IWineD3DSwapChain *swapchain;
7769 HRESULT hrc = WINED3D_OK;
7771 TRACE("Relaying to swapchain\n");
7773 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7774 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7775 IWineD3DSwapChain_Release(swapchain);
7777 return;
7780 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7781 IWineD3DSwapChain *swapchain;
7782 HRESULT hrc = WINED3D_OK;
7784 TRACE("Relaying to swapchain\n");
7786 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7787 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7788 IWineD3DSwapChain_Release(swapchain);
7790 return;
7794 /** ********************************************************
7795 * Notification functions
7796 ** ********************************************************/
7797 /** This function must be called in the release of a resource when ref == 0,
7798 * the contents of resource must still be correct,
7799 * any handels to other resource held by the caller must be closed
7800 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7801 *****************************************************/
7802 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7804 ResourceList* resourceList;
7806 TRACE("(%p) : resource %p\n", This, resource);
7807 #if 0
7808 EnterCriticalSection(&resourceStoreCriticalSection);
7809 #endif
7810 /* add a new texture to the frot of the linked list */
7811 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7812 resourceList->resource = resource;
7814 /* Get the old head */
7815 resourceList->next = This->resources;
7817 This->resources = resourceList;
7818 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7820 #if 0
7821 LeaveCriticalSection(&resourceStoreCriticalSection);
7822 #endif
7823 return;
7826 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7828 ResourceList* resourceList = NULL;
7829 ResourceList* previousResourceList = NULL;
7831 TRACE("(%p) : resource %p\n", This, resource);
7833 #if 0
7834 EnterCriticalSection(&resourceStoreCriticalSection);
7835 #endif
7836 resourceList = This->resources;
7838 while (resourceList != NULL) {
7839 if(resourceList->resource == resource) break;
7840 previousResourceList = resourceList;
7841 resourceList = resourceList->next;
7844 if (resourceList == NULL) {
7845 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7846 #if 0
7847 LeaveCriticalSection(&resourceStoreCriticalSection);
7848 #endif
7849 return;
7850 } else {
7851 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7853 /* make sure we don't leave a hole in the list */
7854 if (previousResourceList != NULL) {
7855 previousResourceList->next = resourceList->next;
7856 } else {
7857 This->resources = resourceList->next;
7860 #if 0
7861 LeaveCriticalSection(&resourceStoreCriticalSection);
7862 #endif
7863 return;
7867 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7869 int counter;
7871 TRACE("(%p) : resource %p\n", This, resource);
7872 switch(IWineD3DResource_GetType(resource)){
7873 case WINED3DRTYPE_SURFACE:
7874 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7875 break;
7876 case WINED3DRTYPE_TEXTURE:
7877 case WINED3DRTYPE_CUBETEXTURE:
7878 case WINED3DRTYPE_VOLUMETEXTURE:
7879 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7880 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7881 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7882 This->stateBlock->textures[counter] = NULL;
7884 if (This->updateStateBlock != This->stateBlock ){
7885 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7886 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7887 This->updateStateBlock->textures[counter] = NULL;
7891 break;
7892 case WINED3DRTYPE_VOLUME:
7893 /* TODO: nothing really? */
7894 break;
7895 case WINED3DRTYPE_VERTEXBUFFER:
7896 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7898 int streamNumber;
7899 TRACE("Cleaning up stream pointers\n");
7901 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7902 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7903 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7905 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7906 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7907 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7908 This->updateStateBlock->streamSource[streamNumber] = 0;
7909 /* Set changed flag? */
7912 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) */
7913 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7914 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7915 This->stateBlock->streamSource[streamNumber] = 0;
7918 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7919 else { /* This shouldn't happen */
7920 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7922 #endif
7926 break;
7927 case WINED3DRTYPE_INDEXBUFFER:
7928 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7929 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7930 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7931 This->updateStateBlock->pIndexData = NULL;
7934 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7935 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7936 This->stateBlock->pIndexData = NULL;
7940 break;
7941 default:
7942 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7943 break;
7947 /* Remove the resoruce from the resourceStore */
7948 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7950 TRACE("Resource released\n");
7954 /**********************************************************
7955 * IWineD3DDevice VTbl follows
7956 **********************************************************/
7958 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7960 /*** IUnknown methods ***/
7961 IWineD3DDeviceImpl_QueryInterface,
7962 IWineD3DDeviceImpl_AddRef,
7963 IWineD3DDeviceImpl_Release,
7964 /*** IWineD3DDevice methods ***/
7965 IWineD3DDeviceImpl_GetParent,
7966 /*** Creation methods**/
7967 IWineD3DDeviceImpl_CreateVertexBuffer,
7968 IWineD3DDeviceImpl_CreateIndexBuffer,
7969 IWineD3DDeviceImpl_CreateStateBlock,
7970 IWineD3DDeviceImpl_CreateSurface,
7971 IWineD3DDeviceImpl_CreateTexture,
7972 IWineD3DDeviceImpl_CreateVolumeTexture,
7973 IWineD3DDeviceImpl_CreateVolume,
7974 IWineD3DDeviceImpl_CreateCubeTexture,
7975 IWineD3DDeviceImpl_CreateQuery,
7976 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7977 IWineD3DDeviceImpl_CreateVertexDeclaration,
7978 IWineD3DDeviceImpl_CreateVertexShader,
7979 IWineD3DDeviceImpl_CreatePixelShader,
7980 IWineD3DDeviceImpl_CreatePalette,
7981 /*** Odd functions **/
7982 IWineD3DDeviceImpl_Init3D,
7983 IWineD3DDeviceImpl_Uninit3D,
7984 IWineD3DDeviceImpl_EnumDisplayModes,
7985 IWineD3DDeviceImpl_EvictManagedResources,
7986 IWineD3DDeviceImpl_GetAvailableTextureMem,
7987 IWineD3DDeviceImpl_GetBackBuffer,
7988 IWineD3DDeviceImpl_GetCreationParameters,
7989 IWineD3DDeviceImpl_GetDeviceCaps,
7990 IWineD3DDeviceImpl_GetDirect3D,
7991 IWineD3DDeviceImpl_GetDisplayMode,
7992 IWineD3DDeviceImpl_SetDisplayMode,
7993 IWineD3DDeviceImpl_GetHWND,
7994 IWineD3DDeviceImpl_SetHWND,
7995 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7996 IWineD3DDeviceImpl_GetRasterStatus,
7997 IWineD3DDeviceImpl_GetSwapChain,
7998 IWineD3DDeviceImpl_Reset,
7999 IWineD3DDeviceImpl_SetDialogBoxMode,
8000 IWineD3DDeviceImpl_SetCursorProperties,
8001 IWineD3DDeviceImpl_SetCursorPosition,
8002 IWineD3DDeviceImpl_ShowCursor,
8003 IWineD3DDeviceImpl_TestCooperativeLevel,
8004 /*** Getters and setters **/
8005 IWineD3DDeviceImpl_SetClipPlane,
8006 IWineD3DDeviceImpl_GetClipPlane,
8007 IWineD3DDeviceImpl_SetClipStatus,
8008 IWineD3DDeviceImpl_GetClipStatus,
8009 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8010 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8011 IWineD3DDeviceImpl_SetDepthStencilSurface,
8012 IWineD3DDeviceImpl_GetDepthStencilSurface,
8013 IWineD3DDeviceImpl_SetFVF,
8014 IWineD3DDeviceImpl_GetFVF,
8015 IWineD3DDeviceImpl_SetGammaRamp,
8016 IWineD3DDeviceImpl_GetGammaRamp,
8017 IWineD3DDeviceImpl_SetIndices,
8018 IWineD3DDeviceImpl_GetIndices,
8019 IWineD3DDeviceImpl_SetLight,
8020 IWineD3DDeviceImpl_GetLight,
8021 IWineD3DDeviceImpl_SetLightEnable,
8022 IWineD3DDeviceImpl_GetLightEnable,
8023 IWineD3DDeviceImpl_SetMaterial,
8024 IWineD3DDeviceImpl_GetMaterial,
8025 IWineD3DDeviceImpl_SetNPatchMode,
8026 IWineD3DDeviceImpl_GetNPatchMode,
8027 IWineD3DDeviceImpl_SetPaletteEntries,
8028 IWineD3DDeviceImpl_GetPaletteEntries,
8029 IWineD3DDeviceImpl_SetPixelShader,
8030 IWineD3DDeviceImpl_GetPixelShader,
8031 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8032 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8033 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8034 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8035 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8036 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8037 IWineD3DDeviceImpl_SetRenderState,
8038 IWineD3DDeviceImpl_GetRenderState,
8039 IWineD3DDeviceImpl_SetRenderTarget,
8040 IWineD3DDeviceImpl_GetRenderTarget,
8041 IWineD3DDeviceImpl_SetFrontBackBuffers,
8042 IWineD3DDeviceImpl_SetSamplerState,
8043 IWineD3DDeviceImpl_GetSamplerState,
8044 IWineD3DDeviceImpl_SetScissorRect,
8045 IWineD3DDeviceImpl_GetScissorRect,
8046 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8047 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8048 IWineD3DDeviceImpl_SetStreamSource,
8049 IWineD3DDeviceImpl_GetStreamSource,
8050 IWineD3DDeviceImpl_SetStreamSourceFreq,
8051 IWineD3DDeviceImpl_GetStreamSourceFreq,
8052 IWineD3DDeviceImpl_SetTexture,
8053 IWineD3DDeviceImpl_GetTexture,
8054 IWineD3DDeviceImpl_SetTextureStageState,
8055 IWineD3DDeviceImpl_GetTextureStageState,
8056 IWineD3DDeviceImpl_SetTransform,
8057 IWineD3DDeviceImpl_GetTransform,
8058 IWineD3DDeviceImpl_SetVertexDeclaration,
8059 IWineD3DDeviceImpl_GetVertexDeclaration,
8060 IWineD3DDeviceImpl_SetVertexShader,
8061 IWineD3DDeviceImpl_GetVertexShader,
8062 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8063 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8064 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8065 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8066 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8067 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8068 IWineD3DDeviceImpl_SetViewport,
8069 IWineD3DDeviceImpl_GetViewport,
8070 IWineD3DDeviceImpl_MultiplyTransform,
8071 IWineD3DDeviceImpl_ValidateDevice,
8072 IWineD3DDeviceImpl_ProcessVertices,
8073 /*** State block ***/
8074 IWineD3DDeviceImpl_BeginStateBlock,
8075 IWineD3DDeviceImpl_EndStateBlock,
8076 /*** Scene management ***/
8077 IWineD3DDeviceImpl_BeginScene,
8078 IWineD3DDeviceImpl_EndScene,
8079 IWineD3DDeviceImpl_Present,
8080 IWineD3DDeviceImpl_Clear,
8081 /*** Drawing ***/
8082 IWineD3DDeviceImpl_DrawPrimitive,
8083 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8084 IWineD3DDeviceImpl_DrawPrimitiveUP,
8085 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8086 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8087 IWineD3DDeviceImpl_DrawRectPatch,
8088 IWineD3DDeviceImpl_DrawTriPatch,
8089 IWineD3DDeviceImpl_DeletePatch,
8090 IWineD3DDeviceImpl_ColorFill,
8091 IWineD3DDeviceImpl_UpdateTexture,
8092 IWineD3DDeviceImpl_UpdateSurface,
8093 IWineD3DDeviceImpl_CopyRects,
8094 IWineD3DDeviceImpl_StretchRect,
8095 IWineD3DDeviceImpl_GetRenderTargetData,
8096 IWineD3DDeviceImpl_GetFrontBufferData,
8097 /*** Internal use IWineD3DDevice methods ***/
8098 IWineD3DDeviceImpl_SetupTextureStates,
8099 /*** object tracking ***/
8100 IWineD3DDeviceImpl_ResourceReleased
8104 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8105 WINED3DRS_ALPHABLENDENABLE ,
8106 WINED3DRS_ALPHAFUNC ,
8107 WINED3DRS_ALPHAREF ,
8108 WINED3DRS_ALPHATESTENABLE ,
8109 WINED3DRS_BLENDOP ,
8110 WINED3DRS_COLORWRITEENABLE ,
8111 WINED3DRS_DESTBLEND ,
8112 WINED3DRS_DITHERENABLE ,
8113 WINED3DRS_FILLMODE ,
8114 WINED3DRS_FOGDENSITY ,
8115 WINED3DRS_FOGEND ,
8116 WINED3DRS_FOGSTART ,
8117 WINED3DRS_LASTPIXEL ,
8118 WINED3DRS_SHADEMODE ,
8119 WINED3DRS_SRCBLEND ,
8120 WINED3DRS_STENCILENABLE ,
8121 WINED3DRS_STENCILFAIL ,
8122 WINED3DRS_STENCILFUNC ,
8123 WINED3DRS_STENCILMASK ,
8124 WINED3DRS_STENCILPASS ,
8125 WINED3DRS_STENCILREF ,
8126 WINED3DRS_STENCILWRITEMASK ,
8127 WINED3DRS_STENCILZFAIL ,
8128 WINED3DRS_TEXTUREFACTOR ,
8129 WINED3DRS_WRAP0 ,
8130 WINED3DRS_WRAP1 ,
8131 WINED3DRS_WRAP2 ,
8132 WINED3DRS_WRAP3 ,
8133 WINED3DRS_WRAP4 ,
8134 WINED3DRS_WRAP5 ,
8135 WINED3DRS_WRAP6 ,
8136 WINED3DRS_WRAP7 ,
8137 WINED3DRS_ZENABLE ,
8138 WINED3DRS_ZFUNC ,
8139 WINED3DRS_ZWRITEENABLE
8142 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8143 WINED3DTSS_ADDRESSW ,
8144 WINED3DTSS_ALPHAARG0 ,
8145 WINED3DTSS_ALPHAARG1 ,
8146 WINED3DTSS_ALPHAARG2 ,
8147 WINED3DTSS_ALPHAOP ,
8148 WINED3DTSS_BUMPENVLOFFSET ,
8149 WINED3DTSS_BUMPENVLSCALE ,
8150 WINED3DTSS_BUMPENVMAT00 ,
8151 WINED3DTSS_BUMPENVMAT01 ,
8152 WINED3DTSS_BUMPENVMAT10 ,
8153 WINED3DTSS_BUMPENVMAT11 ,
8154 WINED3DTSS_COLORARG0 ,
8155 WINED3DTSS_COLORARG1 ,
8156 WINED3DTSS_COLORARG2 ,
8157 WINED3DTSS_COLOROP ,
8158 WINED3DTSS_RESULTARG ,
8159 WINED3DTSS_TEXCOORDINDEX ,
8160 WINED3DTSS_TEXTURETRANSFORMFLAGS
8163 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8164 WINED3DSAMP_ADDRESSU ,
8165 WINED3DSAMP_ADDRESSV ,
8166 WINED3DSAMP_ADDRESSW ,
8167 WINED3DSAMP_BORDERCOLOR ,
8168 WINED3DSAMP_MAGFILTER ,
8169 WINED3DSAMP_MINFILTER ,
8170 WINED3DSAMP_MIPFILTER ,
8171 WINED3DSAMP_MIPMAPLODBIAS ,
8172 WINED3DSAMP_MAXMIPLEVEL ,
8173 WINED3DSAMP_MAXANISOTROPY ,
8174 WINED3DSAMP_SRGBTEXTURE ,
8175 WINED3DSAMP_ELEMENTINDEX
8178 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8179 WINED3DRS_AMBIENT ,
8180 WINED3DRS_AMBIENTMATERIALSOURCE ,
8181 WINED3DRS_CLIPPING ,
8182 WINED3DRS_CLIPPLANEENABLE ,
8183 WINED3DRS_COLORVERTEX ,
8184 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8185 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8186 WINED3DRS_FOGDENSITY ,
8187 WINED3DRS_FOGEND ,
8188 WINED3DRS_FOGSTART ,
8189 WINED3DRS_FOGTABLEMODE ,
8190 WINED3DRS_FOGVERTEXMODE ,
8191 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8192 WINED3DRS_LIGHTING ,
8193 WINED3DRS_LOCALVIEWER ,
8194 WINED3DRS_MULTISAMPLEANTIALIAS ,
8195 WINED3DRS_MULTISAMPLEMASK ,
8196 WINED3DRS_NORMALIZENORMALS ,
8197 WINED3DRS_PATCHEDGESTYLE ,
8198 WINED3DRS_POINTSCALE_A ,
8199 WINED3DRS_POINTSCALE_B ,
8200 WINED3DRS_POINTSCALE_C ,
8201 WINED3DRS_POINTSCALEENABLE ,
8202 WINED3DRS_POINTSIZE ,
8203 WINED3DRS_POINTSIZE_MAX ,
8204 WINED3DRS_POINTSIZE_MIN ,
8205 WINED3DRS_POINTSPRITEENABLE ,
8206 WINED3DRS_RANGEFOGENABLE ,
8207 WINED3DRS_SPECULARMATERIALSOURCE ,
8208 WINED3DRS_TWEENFACTOR ,
8209 WINED3DRS_VERTEXBLEND
8212 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8213 WINED3DTSS_TEXCOORDINDEX ,
8214 WINED3DTSS_TEXTURETRANSFORMFLAGS
8217 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8218 WINED3DSAMP_DMAPOFFSET