ddraw: Pass the fullscreen flag to wined3d.
[wine.git] / dlls / wined3d / device.c
blob34026db5e2b9a56b3e1cd57b0a6875873e990068
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 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
498 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
499 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
501 /* TODO: NV_POINT_SPRITE */
502 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
503 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
504 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
505 glDisable(GL_POINT_SMOOTH);
507 /* Centre the texture on the vertex */
508 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
509 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
511 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
512 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
513 checkGLcall("glTexEnvf(...)");
514 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
515 glEnable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
517 } else {
518 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
519 glDisable( GL_POINT_SPRITE_ARB );
520 checkGLcall("glEnable(...)");
524 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
527 /**********************************************************
528 * IUnknown parts follows
529 **********************************************************/
531 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
535 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
536 if (IsEqualGUID(riid, &IID_IUnknown)
537 || IsEqualGUID(riid, &IID_IWineD3DBase)
538 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
539 IUnknown_AddRef(iface);
540 *ppobj = This;
541 return S_OK;
543 *ppobj = NULL;
544 return E_NOINTERFACE;
547 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
549 ULONG refCount = InterlockedIncrement(&This->ref);
551 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
552 return refCount;
555 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 ULONG refCount = InterlockedDecrement(&This->ref);
559 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
561 if (!refCount) {
562 /* TODO: Clean up all the surfaces and textures! */
563 /* NOTE: You must release the parent if the object was created via a callback
564 ** ***************************/
566 /* Delete any GLSL shader programs that may exist */
567 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
568 wined3d_settings.ps_selected_mode == SHADER_GLSL)
569 delete_glsl_shader_list(iface);
571 /* Release the update stateblock */
572 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
573 if(This->updateStateBlock != This->stateBlock)
574 FIXME("(%p) Something's still holding the Update stateblock\n",This);
576 This->updateStateBlock = NULL;
577 { /* because were not doing proper internal refcounts releasing the primary state block
578 causes recursion with the extra checks in ResourceReleased, to avoid this we have
579 to set this->stateBlock = NULL; first */
580 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
581 This->stateBlock = NULL;
583 /* Release the stateblock */
584 if(IWineD3DStateBlock_Release(stateBlock) > 0){
585 FIXME("(%p) Something's still holding the Update stateblock\n",This);
589 if (This->resources != NULL ) {
590 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
591 dumpResources(This->resources);
595 IWineD3D_Release(This->wineD3D);
596 This->wineD3D = NULL;
597 HeapFree(GetProcessHeap(), 0, This);
598 TRACE("Freed device %p\n", This);
599 This = NULL;
601 return refCount;
604 /**********************************************************
605 * IWineD3DDevice implementation follows
606 **********************************************************/
607 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
609 *pParent = This->parent;
610 IUnknown_AddRef(This->parent);
611 return WINED3D_OK;
614 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
615 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
616 GLenum error, glUsage;
617 DWORD vboUsage = object->resource.usage;
618 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
619 WARN("Creating a vbo failed once, not trying again\n");
620 return;
623 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
625 ENTER_GL();
626 /* Make sure that the gl error is cleared. Do not use checkGLcall
627 * here because checkGLcall just prints a fixme and continues. However,
628 * if an error during VBO creation occurs we can fall back to non-vbo operation
629 * with full functionality(but performance loss)
631 while(glGetError() != GL_NO_ERROR);
633 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
634 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
635 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
636 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
637 * to check if the rhw and color values are in the correct format.
640 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
641 error = glGetError();
642 if(object->vbo == 0 || error != GL_NO_ERROR) {
643 WARN("Failed to create a VBO with error %d\n", error);
644 goto error;
647 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
648 error = glGetError();
649 if(error != GL_NO_ERROR) {
650 WARN("Failed to bind the VBO, error %d\n", error);
651 goto error;
654 /* Transformed vertices are horribly inflexible. If the app specifies an
655 * vertex buffer with transformed vertices in default pool without DYNAMIC
656 * usage assume DYNAMIC usage and print a warning. The app will have to update
657 * the vertices regularily for them to be useful
659 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
660 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
661 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
662 vboUsage |= WINED3DUSAGE_DYNAMIC;
665 /* Don't use static, because dx apps tend to update the buffer
666 * quite often even if they specify 0 usage
668 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
669 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
670 TRACE("Gl usage = GL_STREAM_DRAW\n");
671 glUsage = GL_STREAM_DRAW_ARB;
672 break;
673 case D3DUSAGE_WRITEONLY:
674 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
675 glUsage = GL_DYNAMIC_DRAW_ARB;
676 break;
677 case D3DUSAGE_DYNAMIC:
678 TRACE("Gl usage = GL_STREAM_COPY\n");
679 glUsage = GL_STREAM_COPY_ARB;
680 break;
681 default:
682 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
683 glUsage = GL_DYNAMIC_COPY_ARB;
684 break;
687 /* Reserve memory for the buffer. The amount of data won't change
688 * so we are safe with calling glBufferData once with a NULL ptr and
689 * calling glBufferSubData on updates
691 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
692 error = glGetError();
693 if(error != GL_NO_ERROR) {
694 WARN("glBufferDataARB failed with error %d\n", error);
695 goto error;
698 LEAVE_GL();
700 return;
701 error:
702 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
703 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
704 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
705 object->vbo = 0;
706 object->Flags |= VBFLAG_VBOCREATEFAIL;
707 LEAVE_GL();
708 return;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
712 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
713 IUnknown *parent) {
714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
715 IWineD3DVertexBufferImpl *object;
716 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
717 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
718 BOOL conv;
719 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
721 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
722 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
724 if(Size == 0) return WINED3DERR_INVALIDCALL;
726 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
727 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
729 object->fvf = FVF;
731 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
732 * drawStridedFast (half-life 2).
734 * Basically converting the vertices in the buffer is quite expensive, and observations
735 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
736 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
738 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
739 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
740 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
741 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
742 * dx7 apps.
743 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
744 * more. In this call we can convert dx7 buffers too.
746 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
747 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
748 (dxVersion > 7 || !conv) ) {
749 CreateVBO(object);
751 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
752 if(dxVersion == 7 && object->vbo) {
753 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
754 object->resource.allocatedMemory = NULL;
758 return WINED3D_OK;
761 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
762 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
763 HANDLE *sharedHandle, IUnknown *parent) {
764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
765 IWineD3DIndexBufferImpl *object;
766 TRACE("(%p) Creating index buffer\n", This);
768 /* Allocate the storage for the device */
769 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
771 /*TODO: use VBO's */
772 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
773 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
776 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
777 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
778 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
780 return WINED3D_OK;
783 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
786 IWineD3DStateBlockImpl *object;
787 int i, j;
788 HRESULT temp_result;
790 D3DCREATEOBJECTINSTANCE(object, StateBlock)
791 object->blockType = Type;
793 /* Special case - Used during initialization to produce a placeholder stateblock
794 so other functions called can update a state block */
795 if (Type == WINED3DSBT_INIT) {
796 /* Don't bother increasing the reference count otherwise a device will never
797 be freed due to circular dependencies */
798 return WINED3D_OK;
801 temp_result = allocate_shader_constants(object);
802 if (WINED3D_OK != temp_result)
803 return temp_result;
805 /* Otherwise, might as well set the whole state block to the appropriate values */
806 if (This->stateBlock != NULL)
807 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
808 else
809 memset(object->streamFreq, 1, sizeof(object->streamFreq));
811 /* Reset the ref and type after kludging it */
812 object->wineD3DDevice = This;
813 object->ref = 1;
814 object->blockType = Type;
816 TRACE("Updating changed flags appropriate for type %d\n", Type);
818 if (Type == WINED3DSBT_ALL) {
820 TRACE("ALL => Pretend everything has changed\n");
821 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
823 } else if (Type == WINED3DSBT_PIXELSTATE) {
825 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
826 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
828 object->changed.pixelShader = TRUE;
830 /* Pixel Shader Constants */
831 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
832 object->changed.pixelShaderConstantsF[i] = TRUE;
833 for (i = 0; i < MAX_CONST_B; ++i)
834 object->changed.pixelShaderConstantsB[i] = TRUE;
835 for (i = 0; i < MAX_CONST_I; ++i)
836 object->changed.pixelShaderConstantsI[i] = TRUE;
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
839 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
841 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
842 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
843 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
846 for (j = 0 ; j < 16; j++) {
847 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
849 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
853 } else if (Type == WINED3DSBT_VERTEXSTATE) {
855 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
856 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
858 object->changed.vertexShader = TRUE;
860 /* Vertex Shader Constants */
861 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
862 object->changed.vertexShaderConstantsF[i] = TRUE;
863 for (i = 0; i < MAX_CONST_B; ++i)
864 object->changed.vertexShaderConstantsB[i] = TRUE;
865 for (i = 0; i < MAX_CONST_I; ++i)
866 object->changed.vertexShaderConstantsI[i] = TRUE;
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
869 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
871 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
872 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
873 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
876 for (j = 0 ; j < 16; j++){
877 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
878 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
882 /* Duplicate light chain */
884 PLIGHTINFOEL *src = NULL;
885 PLIGHTINFOEL *dst = NULL;
886 PLIGHTINFOEL *newEl = NULL;
887 src = This->stateBlock->lights;
888 object->lights = NULL;
891 while (src) {
892 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
893 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
894 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
895 newEl->prev = dst;
896 newEl->changed = TRUE;
897 newEl->enabledChanged = TRUE;
898 if (dst == NULL) {
899 object->lights = newEl;
900 } else {
901 dst->next = newEl;
903 dst = newEl;
904 src = src->next;
909 } else {
910 FIXME("Unrecognized state block type %d\n", Type);
913 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
914 return WINED3D_OK;
918 /* ************************************
919 MSDN:
920 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
922 Discard
923 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
925 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.
927 ******************************** */
929 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) {
930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
931 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
932 unsigned int pow2Width, pow2Height;
933 unsigned int Size = 1;
934 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
935 TRACE("(%p) Create surface\n",This);
937 /** FIXME: Check ranges on the inputs are valid
938 * MSDN
939 * MultisampleQuality
940 * [in] Quality level. The valid range is between zero and one less than the level
941 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
942 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
943 * values of paired render targets, depth stencil surfaces, and the MultiSample type
944 * must all match.
945 *******************************/
949 * TODO: Discard MSDN
950 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
952 * If this flag is set, the contents of the depth stencil buffer will be
953 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
954 * with a different depth surface.
956 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
957 ***************************/
959 if(MultisampleQuality < 0) {
960 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
961 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
964 if(MultisampleQuality > 0) {
965 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
966 MultisampleQuality=0;
969 /** FIXME: Check that the format is supported
970 * by the device.
971 *******************************/
973 /* Non-power2 support */
975 /* Find the nearest pow2 match */
976 pow2Width = pow2Height = 1;
977 while (pow2Width < Width) pow2Width <<= 1;
978 while (pow2Height < Height) pow2Height <<= 1;
980 if (pow2Width > Width || pow2Height > Height) {
981 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
982 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
983 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
984 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
985 This, Width, Height);
986 return WINED3DERR_NOTAVAILABLE;
990 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
991 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
992 * space!
993 *********************************/
994 if (WINED3DFMT_UNKNOWN == Format) {
995 Size = 0;
996 } else if (Format == WINED3DFMT_DXT1) {
997 /* DXT1 is half byte per pixel */
998 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1000 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1001 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1002 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1003 } else {
1004 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1007 /** Create and initialise the surface resource **/
1008 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1009 /* "Standalone" surface */
1010 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.MultiSampleType = MultiSample;
1015 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1017 /* Setup some glformat defaults */
1018 object->glDescription.glFormat = tableEntry->glFormat;
1019 object->glDescription.glFormatInternal = tableEntry->glInternal;
1020 object->glDescription.glType = tableEntry->glType;
1022 object->glDescription.textureName = 0;
1023 object->glDescription.level = Level;
1024 object->glDescription.target = GL_TEXTURE_2D;
1026 /* Internal data */
1027 object->pow2Width = pow2Width;
1028 object->pow2Height = pow2Height;
1030 /* Flags */
1031 object->Flags = 0; /* We start without flags set */
1032 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1033 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1034 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1035 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1038 if (WINED3DFMT_UNKNOWN != Format) {
1039 object->bytesPerPixel = tableEntry->bpp;
1040 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1041 } else {
1042 object->bytesPerPixel = 0;
1043 object->pow2Size = 0;
1046 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1048 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1050 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1051 * this function is too deap to need to care about things like this.
1052 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1053 * ****************************************/
1054 switch(Pool) {
1055 case WINED3DPOOL_SCRATCH:
1056 if(Lockable == FALSE)
1057 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1058 which are mutually exclusive, setting lockable to true\n");
1059 Lockable = TRUE;
1060 break;
1061 case WINED3DPOOL_SYSTEMMEM:
1062 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1063 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1064 case WINED3DPOOL_MANAGED:
1065 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1066 Usage of DYNAMIC which are mutually exclusive, not doing \
1067 anything just telling you.\n");
1068 break;
1069 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1070 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1071 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1072 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1073 break;
1074 default:
1075 FIXME("(%p) Unknown pool %d\n", This, Pool);
1076 break;
1079 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1080 FIXME("Trying to create a render target that isn't in the default pool\n");
1083 /* mark the texture as dirty so that it get's loaded first time around*/
1084 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1085 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1086 This, Width, Height, Format, debug_d3dformat(Format),
1087 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1089 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1090 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1091 This->ddraw_primary = (IWineD3DSurface *) object;
1093 /* Look at the implementation and set the correct Vtable */
1094 switch(Impl) {
1095 case SURFACE_OPENGL:
1096 /* Nothing to do, it's set already */
1097 break;
1099 case SURFACE_GDI:
1100 object->lpVtbl = &IWineGDISurface_Vtbl;
1101 break;
1103 default:
1104 /* To be sure to catch this */
1105 ERR("Unknown requested surface implementation %d!\n", Impl);
1106 IWineD3DSurface_Release((IWineD3DSurface *) object);
1107 return WINED3DERR_INVALIDCALL;
1110 /* Call the private setup routine */
1111 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1115 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1116 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1117 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1118 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1121 IWineD3DTextureImpl *object;
1122 unsigned int i;
1123 UINT tmpW;
1124 UINT tmpH;
1125 HRESULT hr;
1126 unsigned int pow2Width = Width;
1127 unsigned int pow2Height = Height;
1130 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#lx\n", This, Width, Height, Levels, Usage);
1131 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1132 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1134 /* TODO: It should only be possible to create textures for formats
1135 that are reported as supported */
1136 if (WINED3DFMT_UNKNOWN >= Format) {
1137 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1138 return WINED3DERR_INVALIDCALL;
1141 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1142 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1143 object->width = Width;
1144 object->height = Height;
1146 /** Non-power2 support **/
1147 /* Find the nearest pow2 match */
1148 pow2Width = pow2Height = 1;
1149 while (pow2Width < Width) pow2Width <<= 1;
1150 while (pow2Height < Height) pow2Height <<= 1;
1152 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1153 /* Precalculated scaling for 'faked' non power of two texture coords */
1154 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1155 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1156 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1158 /* Calculate levels for mip mapping */
1159 if (Levels == 0) {
1160 TRACE("calculating levels %d\n", object->baseTexture.levels);
1161 object->baseTexture.levels++;
1162 tmpW = Width;
1163 tmpH = Height;
1164 while (tmpW > 1 || tmpH > 1) {
1165 tmpW = max(1, tmpW >> 1);
1166 tmpH = max(1, tmpH >> 1);
1167 object->baseTexture.levels++;
1169 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1172 /* Generate all the surfaces */
1173 tmpW = Width;
1174 tmpH = Height;
1175 for (i = 0; i < object->baseTexture.levels; i++)
1177 /* use the callback to create the texture surface */
1178 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1179 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1180 FIXME("Failed to create surface %p\n", object);
1181 /* clean up */
1182 object->surfaces[i] = NULL;
1183 IWineD3DTexture_Release((IWineD3DTexture *)object);
1185 *ppTexture = NULL;
1186 return hr;
1189 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1190 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1191 /* calculate the next mipmap level */
1192 tmpW = max(1, tmpW >> 1);
1193 tmpH = max(1, tmpH >> 1);
1196 TRACE("(%p) : Created texture %p\n", This, object);
1197 return WINED3D_OK;
1200 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1201 UINT Width, UINT Height, UINT Depth,
1202 UINT Levels, DWORD Usage,
1203 WINED3DFORMAT Format, WINED3DPOOL Pool,
1204 IWineD3DVolumeTexture **ppVolumeTexture,
1205 HANDLE *pSharedHandle, IUnknown *parent,
1206 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1209 IWineD3DVolumeTextureImpl *object;
1210 unsigned int i;
1211 UINT tmpW;
1212 UINT tmpH;
1213 UINT tmpD;
1215 /* TODO: It should only be possible to create textures for formats
1216 that are reported as supported */
1217 if (WINED3DFMT_UNKNOWN >= Format) {
1218 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1219 return WINED3DERR_INVALIDCALL;
1222 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1223 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1225 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1226 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1228 object->width = Width;
1229 object->height = Height;
1230 object->depth = Depth;
1232 /* Calculate levels for mip mapping */
1233 if (Levels == 0) {
1234 object->baseTexture.levels++;
1235 tmpW = Width;
1236 tmpH = Height;
1237 tmpD = Depth;
1238 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1239 tmpW = max(1, tmpW >> 1);
1240 tmpH = max(1, tmpH >> 1);
1241 tmpD = max(1, tmpD >> 1);
1242 object->baseTexture.levels++;
1244 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1247 /* Generate all the surfaces */
1248 tmpW = Width;
1249 tmpH = Height;
1250 tmpD = Depth;
1252 for (i = 0; i < object->baseTexture.levels; i++)
1254 /* Create the volume */
1255 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1256 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1258 /* Set it's container to this object */
1259 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1261 /* calcualte the next mipmap level */
1262 tmpW = max(1, tmpW >> 1);
1263 tmpH = max(1, tmpH >> 1);
1264 tmpD = max(1, tmpD >> 1);
1267 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1268 TRACE("(%p) : Created volume texture %p\n", This, object);
1269 return WINED3D_OK;
1272 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1273 UINT Width, UINT Height, UINT Depth,
1274 DWORD Usage,
1275 WINED3DFORMAT Format, WINED3DPOOL Pool,
1276 IWineD3DVolume** ppVolume,
1277 HANDLE* pSharedHandle, IUnknown *parent) {
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1280 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1281 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1283 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1285 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1286 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1288 object->currentDesc.Width = Width;
1289 object->currentDesc.Height = Height;
1290 object->currentDesc.Depth = Depth;
1291 object->bytesPerPixel = formatDesc->bpp;
1293 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1294 object->lockable = TRUE;
1295 object->locked = FALSE;
1296 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1297 object->dirty = TRUE;
1299 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1302 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1303 UINT Levels, DWORD Usage,
1304 WINED3DFORMAT Format, WINED3DPOOL Pool,
1305 IWineD3DCubeTexture **ppCubeTexture,
1306 HANDLE *pSharedHandle, IUnknown *parent,
1307 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1310 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1311 unsigned int i, j;
1312 UINT tmpW;
1313 HRESULT hr;
1314 unsigned int pow2EdgeLength = EdgeLength;
1316 /* TODO: It should only be possible to create textures for formats
1317 that are reported as supported */
1318 if (WINED3DFMT_UNKNOWN >= Format) {
1319 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1320 return WINED3DERR_INVALIDCALL;
1323 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1324 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1326 TRACE("(%p) Create Cube Texture\n", This);
1328 /** Non-power2 support **/
1330 /* Find the nearest pow2 match */
1331 pow2EdgeLength = 1;
1332 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1334 object->edgeLength = EdgeLength;
1335 /* TODO: support for native non-power 2 */
1336 /* Precalculated scaling for 'faked' non power of two texture coords */
1337 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1339 /* Calculate levels for mip mapping */
1340 if (Levels == 0) {
1341 object->baseTexture.levels++;
1342 tmpW = EdgeLength;
1343 while (tmpW > 1) {
1344 tmpW = max(1, tmpW >> 1);
1345 object->baseTexture.levels++;
1347 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1350 /* Generate all the surfaces */
1351 tmpW = EdgeLength;
1352 for (i = 0; i < object->baseTexture.levels; i++) {
1354 /* Create the 6 faces */
1355 for (j = 0; j < 6; j++) {
1357 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1358 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1360 if(hr!= WINED3D_OK) {
1361 /* clean up */
1362 int k;
1363 int l;
1364 for (l = 0; l < j; l++) {
1365 IWineD3DSurface_Release(object->surfaces[j][i]);
1367 for (k = 0; k < i; k++) {
1368 for (l = 0; l < 6; l++) {
1369 IWineD3DSurface_Release(object->surfaces[l][j]);
1373 FIXME("(%p) Failed to create surface\n",object);
1374 HeapFree(GetProcessHeap(),0,object);
1375 *ppCubeTexture = NULL;
1376 return hr;
1378 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1379 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1381 tmpW = max(1, tmpW >> 1);
1384 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1385 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1386 return WINED3D_OK;
1389 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1391 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1393 if (NULL == ppQuery) {
1394 /* Just a check to see if we support this type of query */
1395 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1396 switch(Type) {
1397 case WINED3DQUERYTYPE_OCCLUSION:
1398 TRACE("(%p) occlusion query\n", This);
1399 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1400 hr = WINED3D_OK;
1401 else
1402 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1403 break;
1404 case WINED3DQUERYTYPE_VCACHE:
1405 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1406 case WINED3DQUERYTYPE_VERTEXSTATS:
1407 case WINED3DQUERYTYPE_EVENT:
1408 case WINED3DQUERYTYPE_TIMESTAMP:
1409 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1410 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1411 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1412 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1413 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1414 case WINED3DQUERYTYPE_PIXELTIMINGS:
1415 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1416 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1417 default:
1418 FIXME("(%p) Unhandled query type %d\n", This, Type);
1420 return hr;
1423 D3DCREATEOBJECTINSTANCE(object, Query)
1424 object->type = Type;
1425 /* allocated the 'extended' data based on the type of query requested */
1426 switch(Type){
1427 case D3DQUERYTYPE_OCCLUSION:
1428 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1429 TRACE("(%p) Allocating data for an occlusion query\n", This);
1430 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1431 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1432 break;
1434 case D3DQUERYTYPE_VCACHE:
1435 case D3DQUERYTYPE_RESOURCEMANAGER:
1436 case D3DQUERYTYPE_VERTEXSTATS:
1437 case D3DQUERYTYPE_EVENT:
1438 case D3DQUERYTYPE_TIMESTAMP:
1439 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1440 case D3DQUERYTYPE_TIMESTAMPFREQ:
1441 case D3DQUERYTYPE_PIPELINETIMINGS:
1442 case D3DQUERYTYPE_INTERFACETIMINGS:
1443 case D3DQUERYTYPE_VERTEXTIMINGS:
1444 case D3DQUERYTYPE_PIXELTIMINGS:
1445 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1446 case D3DQUERYTYPE_CACHEUTILIZATION:
1447 default:
1448 object->extendedData = 0;
1449 FIXME("(%p) Unhandled query type %d\n",This , Type);
1451 TRACE("(%p) : Created Query %p\n", This, object);
1452 return WINED3D_OK;
1455 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1456 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1457 IUnknown* parent,
1458 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1459 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1462 HDC hDc;
1463 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1464 int num;
1465 XVisualInfo template;
1466 GLXContext oldContext;
1467 Drawable oldDrawable;
1468 HRESULT hr = WINED3D_OK;
1470 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1472 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1473 * does a device hold a reference to a swap chain giving them a lifetime of the device
1474 * or does the swap chain notify the device of its destruction.
1475 *******************************/
1477 /* Check the params */
1478 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1479 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1480 return WINED3DERR_INVALIDCALL;
1481 } else if (*pPresentationParameters->BackBufferCount > 1) {
1482 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");
1485 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1487 /*********************
1488 * Lookup the window Handle and the relating X window handle
1489 ********************/
1491 /* Setup hwnd we are using, plus which display this equates to */
1492 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1493 if (!object->win_handle) {
1494 object->win_handle = This->createParms.hFocusWindow;
1497 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1498 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1499 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1500 return WINED3DERR_NOTAVAILABLE;
1502 hDc = GetDC(object->win_handle);
1503 object->display = get_display(hDc);
1504 ReleaseDC(object->win_handle, hDc);
1505 TRACE("Using a display of %p %p\n", object->display, hDc);
1507 if (NULL == object->display || NULL == hDc) {
1508 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1509 return WINED3DERR_NOTAVAILABLE;
1512 if (object->win == 0) {
1513 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1514 return WINED3DERR_NOTAVAILABLE;
1517 * Create an opengl context for the display visual
1518 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1519 * use different properties after that point in time. FIXME: How to handle when requested format
1520 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1521 * it chooses is identical to the one already being used!
1522 **********************************/
1524 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1525 ENTER_GL();
1527 /* Create a new context for this swapchain */
1528 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1529 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1530 (or the best possible if none is requested) */
1531 TRACE("Found x visual ID : %ld\n", template.visualid);
1533 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1534 if (NULL == object->visInfo) {
1535 ERR("cannot really get XVisual\n");
1536 LEAVE_GL();
1537 return WINED3DERR_NOTAVAILABLE;
1538 } else {
1539 int n, value;
1540 /* Write out some debug info about the visual/s */
1541 TRACE("Using x visual ID : %ld\n", template.visualid);
1542 TRACE(" visual info: %p\n", object->visInfo);
1543 TRACE(" num items : %d\n", num);
1544 for (n = 0;n < num; n++) {
1545 TRACE("=====item=====: %d\n", n + 1);
1546 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1547 TRACE(" screen : %d\n", object->visInfo[n].screen);
1548 TRACE(" depth : %u\n", object->visInfo[n].depth);
1549 TRACE(" class : %d\n", object->visInfo[n].class);
1550 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1551 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1552 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1553 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1554 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1555 /* log some extra glx info */
1556 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1557 TRACE(" gl_aux_buffers : %d\n", value);
1558 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1559 TRACE(" gl_buffer_size : %d\n", value);
1560 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1561 TRACE(" gl_red_size : %d\n", value);
1562 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1563 TRACE(" gl_green_size : %d\n", value);
1564 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1565 TRACE(" gl_blue_size : %d\n", value);
1566 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1567 TRACE(" gl_alpha_size : %d\n", value);
1568 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1569 TRACE(" gl_depth_size : %d\n", value);
1570 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1571 TRACE(" gl_stencil_size : %d\n", value);
1573 /* Now choose a simila visual ID*/
1575 #ifdef USE_CONTEXT_MANAGER
1577 /** TODO: use a context mamager **/
1578 #endif
1581 IWineD3DSwapChain *implSwapChain;
1582 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1583 /* The first time around we create the context that is shared with all other swapchains and render targets */
1584 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1585 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1586 } else {
1588 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1589 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1590 /* and create a new context with the implicit swapchains context as the shared context */
1591 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1592 IWineD3DSwapChain_Release(implSwapChain);
1596 /* Cleanup */
1597 XFree(object->visInfo);
1598 object->visInfo = NULL;
1600 LEAVE_GL();
1602 if (!object->glCtx) {
1603 ERR("Failed to create GLX context\n");
1604 return WINED3DERR_NOTAVAILABLE;
1605 } else {
1606 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1607 object->win_handle, object->glCtx, object->win, object->visInfo);
1610 /*********************
1611 * Windowed / Fullscreen
1612 *******************/
1615 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1616 * so we should really check to see if there is a fullscreen swapchain already
1617 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1618 **************************************/
1620 if (!*(pPresentationParameters->Windowed)) {
1622 DEVMODEW devmode;
1623 HDC hdc;
1624 int bpp = 0;
1626 /* Get info on the current display setup */
1627 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1628 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1629 DeleteDC(hdc);
1631 /* Change the display settings */
1632 memset(&devmode, 0, sizeof(DEVMODEW));
1633 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1634 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1635 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1636 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1637 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1638 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1640 /* Make popup window */
1641 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1642 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1643 *(pPresentationParameters->BackBufferWidth),
1644 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1646 /* For GetDisplayMode */
1647 This->ddraw_width = devmode.dmPelsWidth;
1648 This->ddraw_height = devmode.dmPelsHeight;
1649 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1653 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1654 * then the corresponding dimension of the client area of the hDeviceWindow
1655 * (or the focus window, if hDeviceWindow is NULL) is taken.
1656 **********************/
1658 if (*(pPresentationParameters->Windowed) &&
1659 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1660 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1662 RECT Rect;
1663 GetClientRect(object->win_handle, &Rect);
1665 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1666 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1667 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1669 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1670 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1671 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1675 /*********************
1676 * finish off parameter initialization
1677 *******************/
1679 /* Put the correct figures in the presentation parameters */
1680 TRACE("Coppying accross presentaion paraneters\n");
1681 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1682 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1683 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1684 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1685 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1686 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1687 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1688 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1689 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1690 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1691 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1692 object->presentParms.Flags = *(pPresentationParameters->Flags);
1693 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1694 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1697 /*********************
1698 * Create the back, front and stencil buffers
1699 *******************/
1701 TRACE("calling rendertarget CB\n");
1702 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1703 object->presentParms.BackBufferWidth,
1704 object->presentParms.BackBufferHeight,
1705 object->presentParms.BackBufferFormat,
1706 object->presentParms.MultiSampleType,
1707 object->presentParms.MultiSampleQuality,
1708 TRUE /* Lockable */,
1709 &object->frontBuffer,
1710 NULL /* pShared (always null)*/);
1711 if (object->frontBuffer != NULL)
1712 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1714 if(object->presentParms.BackBufferCount > 0) {
1715 int i;
1717 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1718 if(!object->backBuffer) {
1719 ERR("Out of memory\n");
1721 if (object->frontBuffer) {
1722 IUnknown *bufferParent;
1723 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1724 IUnknown_Release(bufferParent); /* once for the get parent */
1725 if (IUnknown_Release(bufferParent) > 0) {
1726 FIXME("(%p) Something's still holding the front buffer\n",This);
1729 HeapFree(GetProcessHeap(), 0, object);
1730 return E_OUTOFMEMORY;
1733 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1734 TRACE("calling rendertarget CB\n");
1735 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1736 object->presentParms.BackBufferWidth,
1737 object->presentParms.BackBufferHeight,
1738 object->presentParms.BackBufferFormat,
1739 object->presentParms.MultiSampleType,
1740 object->presentParms.MultiSampleQuality,
1741 TRUE /* Lockable */,
1742 &object->backBuffer[i],
1743 NULL /* pShared (always null)*/);
1744 if(hr == WINED3D_OK && object->backBuffer[i]) {
1745 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1746 } else {
1747 break;
1750 } else {
1751 object->backBuffer = NULL;
1754 if (object->backBuffer != NULL) {
1755 ENTER_GL();
1756 glDrawBuffer(GL_BACK);
1757 checkGLcall("glDrawBuffer(GL_BACK)");
1758 LEAVE_GL();
1759 } else {
1760 /* Single buffering - draw to front buffer */
1761 ENTER_GL();
1762 glDrawBuffer(GL_FRONT);
1763 checkGLcall("glDrawBuffer(GL_FRONT)");
1764 LEAVE_GL();
1767 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1768 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1769 TRACE("Creating depth stencil buffer\n");
1770 if (This->depthStencilBuffer == NULL ) {
1771 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1772 object->presentParms.BackBufferWidth,
1773 object->presentParms.BackBufferHeight,
1774 object->presentParms.AutoDepthStencilFormat,
1775 object->presentParms.MultiSampleType,
1776 object->presentParms.MultiSampleQuality,
1777 FALSE /* FIXME: Discard */,
1778 &This->depthStencilBuffer,
1779 NULL /* pShared (always null)*/ );
1780 if (This->depthStencilBuffer != NULL)
1781 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1784 /** TODO: A check on width, height and multisample types
1785 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1786 ****************************/
1787 object->wantsDepthStencilBuffer = TRUE;
1788 } else {
1789 object->wantsDepthStencilBuffer = FALSE;
1792 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1795 /*********************
1796 * init the default renderTarget management
1797 *******************/
1798 object->drawable = object->win;
1799 object->render_ctx = object->glCtx;
1801 if (hr == WINED3D_OK) {
1802 /*********************
1803 * Setup some defaults and clear down the buffers
1804 *******************/
1805 ENTER_GL();
1806 /** save current context and drawable **/
1807 oldContext = glXGetCurrentContext();
1808 oldDrawable = glXGetCurrentDrawable();
1810 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1811 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1812 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1814 checkGLcall("glXMakeCurrent");
1816 TRACE("Setting up the screen\n");
1817 /* Clear the screen */
1818 glClearColor(1.0, 0.0, 0.0, 0.0);
1819 checkGLcall("glClearColor");
1820 glClearIndex(0);
1821 glClearDepth(1);
1822 glClearStencil(0xffff);
1824 checkGLcall("glClear");
1826 glColor3f(1.0, 1.0, 1.0);
1827 checkGLcall("glColor3f");
1829 glEnable(GL_LIGHTING);
1830 checkGLcall("glEnable");
1832 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1833 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1835 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1836 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1838 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1839 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1841 /* switch back to the original context (if there was one)*/
1842 if (This->swapchains) {
1843 /** TODO: restore the context and drawable **/
1844 glXMakeCurrent(object->display, oldDrawable, oldContext);
1847 LEAVE_GL();
1849 TRACE("Set swapchain to %p\n", object);
1850 } else { /* something went wrong so clean up */
1851 IUnknown* bufferParent;
1852 if (object->frontBuffer) {
1854 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1855 IUnknown_Release(bufferParent); /* once for the get parent */
1856 if (IUnknown_Release(bufferParent) > 0) {
1857 FIXME("(%p) Something's still holding the front buffer\n",This);
1860 if (object->backBuffer) {
1861 int i;
1862 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1863 if(object->backBuffer[i]) {
1864 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1865 IUnknown_Release(bufferParent); /* once for the get parent */
1866 if (IUnknown_Release(bufferParent) > 0) {
1867 FIXME("(%p) Something's still holding the back buffer\n",This);
1871 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1872 object->backBuffer = NULL;
1874 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1875 /* Clean up the context */
1876 /* check that we are the current context first (we shouldn't be though!) */
1877 if (object->glCtx != 0) {
1878 if(glXGetCurrentContext() == object->glCtx) {
1879 glXMakeCurrent(object->display, None, NULL);
1881 glXDestroyContext(object->display, object->glCtx);
1883 HeapFree(GetProcessHeap(), 0, object);
1887 return hr;
1890 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1891 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 TRACE("(%p)\n", This);
1895 return This->NumberOfSwapChains;
1898 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1900 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1902 if(iSwapChain < This->NumberOfSwapChains) {
1903 *pSwapChain = This->swapchains[iSwapChain];
1904 IWineD3DSwapChain_AddRef(*pSwapChain);
1905 TRACE("(%p) returning %p\n", This, *pSwapChain);
1906 return WINED3D_OK;
1907 } else {
1908 TRACE("Swapchain out of range\n");
1909 *pSwapChain = NULL;
1910 return WINED3DERR_INVALIDCALL;
1914 /*****
1915 * Vertex Declaration
1916 *****/
1917 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1919 IWineD3DVertexDeclarationImpl *object = NULL;
1920 HRESULT hr = WINED3D_OK;
1921 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1922 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1923 object->allFVF = 0;
1925 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1927 return hr;
1930 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1931 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1933 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1934 HRESULT hr = WINED3D_OK;
1935 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1936 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1938 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1940 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1941 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1942 if (pDeclaration != NULL) {
1943 IWineD3DVertexDeclaration *vertexDeclaration;
1944 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1945 if (WINED3D_OK == hr) {
1946 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1947 object->vertexDeclaration = vertexDeclaration;
1948 } else {
1949 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1950 IWineD3DVertexShader_Release(*ppVertexShader);
1951 return WINED3DERR_INVALIDCALL;
1955 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1957 if (WINED3D_OK != hr) {
1958 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1959 IWineD3DVertexShader_Release(*ppVertexShader);
1960 return WINED3DERR_INVALIDCALL;
1963 #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. */
1964 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1965 /* Foo */
1966 } else {
1967 /* Bar */
1970 #endif
1972 return WINED3D_OK;
1975 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1977 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1978 HRESULT hr = WINED3D_OK;
1980 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1981 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1982 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1983 if (WINED3D_OK == hr) {
1984 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1985 } else {
1986 WARN("(%p) : Failed to create pixel shader\n", This);
1989 return hr;
1992 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1994 IWineD3DPaletteImpl *object;
1995 HRESULT hr;
1996 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1998 /* Create the new object */
1999 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2000 if(!object) {
2001 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2002 return E_OUTOFMEMORY;
2005 object->lpVtbl = &IWineD3DPalette_Vtbl;
2006 object->ref = 1;
2007 object->Flags = Flags;
2008 object->parent = Parent;
2009 object->wineD3DDevice = This;
2010 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2012 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2014 if(!object->hpal) {
2015 HeapFree( GetProcessHeap(), 0, object);
2016 return E_OUTOFMEMORY;
2019 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2020 if(FAILED(hr)) {
2021 IWineD3DPalette_Release((IWineD3DPalette *) object);
2022 return hr;
2025 *Palette = (IWineD3DPalette *) object;
2027 return WINED3D_OK;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2032 IWineD3DSwapChainImpl *swapchain;
2034 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2035 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2037 /* TODO: Test if OpenGL is compiled in and loaded */
2039 /* Setup the implicit swapchain */
2040 TRACE("Creating implicit swapchain\n");
2041 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2042 WARN("Failed to create implicit swapchain\n");
2043 return WINED3DERR_INVALIDCALL;
2046 This->NumberOfSwapChains = 1;
2047 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2048 if(!This->swapchains) {
2049 ERR("Out of memory!\n");
2050 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2051 return E_OUTOFMEMORY;
2053 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2055 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2056 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2057 This->renderTarget = swapchain->backBuffer[0];
2059 else {
2060 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2061 This->renderTarget = swapchain->frontBuffer;
2063 IWineD3DSurface_AddRef(This->renderTarget);
2064 /* Depth Stencil support */
2065 This->stencilBufferTarget = This->depthStencilBuffer;
2066 if (NULL != This->stencilBufferTarget) {
2067 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2070 /* Set up some starting GL setup */
2071 ENTER_GL();
2073 * Initialize openGL extension related variables
2074 * with Default values
2077 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2078 /* Setup all the devices defaults */
2079 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2080 #if 0
2081 IWineD3DImpl_CheckGraphicsMemory();
2082 #endif
2083 LEAVE_GL();
2085 /* Initialize our list of GLSL programs */
2086 list_init(&This->glsl_shader_progs);
2088 { /* Set a default viewport */
2089 D3DVIEWPORT9 vp;
2090 vp.X = 0;
2091 vp.Y = 0;
2092 vp.Width = *(pPresentationParameters->BackBufferWidth);
2093 vp.Height = *(pPresentationParameters->BackBufferHeight);
2094 vp.MinZ = 0.0f;
2095 vp.MaxZ = 1.0f;
2096 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2099 /* Initialize the current view state */
2100 This->modelview_valid = 1;
2101 This->proj_valid = 0;
2102 This->view_ident = 1;
2103 This->last_was_rhw = 0;
2104 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2105 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2107 /* Clear the screen */
2108 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2110 This->d3d_initialized = TRUE;
2111 return WINED3D_OK;
2114 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2116 int sampler;
2117 IUnknown* stencilBufferParent;
2118 IUnknown* swapChainParent;
2119 uint i;
2120 TRACE("(%p)\n", This);
2122 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2124 /* Delete the mouse cursor texture */
2125 if(This->cursorTexture) {
2126 ENTER_GL();
2127 glDeleteTextures(1, &This->cursorTexture);
2128 LEAVE_GL();
2129 This->cursorTexture = 0;
2132 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2133 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2136 /* Release the buffers (with sanity checks)*/
2137 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2138 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2139 if(This->depthStencilBuffer != This->stencilBufferTarget)
2140 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2142 This->stencilBufferTarget = NULL;
2144 TRACE("Releasing the render target at %p\n", This->renderTarget);
2145 if(IWineD3DSurface_Release(This->renderTarget) >0){
2146 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2148 TRACE("Setting rendertarget to NULL\n");
2149 This->renderTarget = NULL;
2151 if (This->depthStencilBuffer) {
2152 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2153 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2154 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2155 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2157 This->depthStencilBuffer = NULL;
2160 for(i=0; i < This->NumberOfSwapChains; i++) {
2161 TRACE("Releasing the implicit swapchain %d\n", i);
2162 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2163 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2164 IUnknown_Release(swapChainParent); /* once for the get parent */
2165 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2170 HeapFree(GetProcessHeap(), 0, This->swapchains);
2171 This->swapchains = NULL;
2172 This->NumberOfSwapChains = 0;
2174 This->d3d_initialized = FALSE;
2175 return WINED3D_OK;
2178 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2180 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2182 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2183 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2184 * DDraw doesn't necessarilly have a swapchain, so we have to store the fullscreen flag
2185 * seperately.
2187 This->ddraw_fullscreen = fullscreen;
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 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3329 func = GL_ALWAYS;
3330 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3331 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3332 func = GL_ALWAYS;
3333 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3334 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3335 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3336 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3337 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3338 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3339 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3340 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3341 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3342 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3343 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3344 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3345 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3346 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3347 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3348 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3350 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3351 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3352 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3353 onesided_enable, twosided_enable, ref, mask,
3354 func, stencilFail, depthFail, stencilPass,
3355 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3357 if (twosided_enable) {
3358 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3359 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3360 } else {
3361 if (onesided_enable) {
3362 glEnable(GL_STENCIL_TEST);
3363 checkGLcall("glEnable GL_STENCIL_TEST");
3364 glStencilFunc(func, ref, mask);
3365 checkGLcall("glStencilFunc(...)");
3366 glStencilOp(stencilFail, depthFail, stencilPass);
3367 checkGLcall("glStencilOp(...)");
3368 } else {
3369 glDisable(GL_STENCIL_TEST);
3370 checkGLcall("glDisable GL_STENCIL_TEST");
3375 /*****
3376 * Get / Set Render States
3377 * TODO: Verify against dx9 definitions
3378 *****/
3379 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 DWORD OldValue = This->stateBlock->renderState[State];
3384 /* Simple way of referring to either a DWORD or a 4 byte float */
3385 union {
3386 DWORD d;
3387 float f;
3388 } tmpvalue;
3390 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3391 This->updateStateBlock->changed.renderState[State] = TRUE;
3392 This->updateStateBlock->set.renderState[State] = TRUE;
3393 This->updateStateBlock->renderState[State] = Value;
3395 /* Handle recording of state blocks */
3396 if (This->isRecordingState) {
3397 TRACE("Recording... not performing anything\n");
3398 return WINED3D_OK;
3401 ENTER_GL();
3403 switch (State) {
3404 case WINED3DRS_FILLMODE :
3405 switch ((D3DFILLMODE) Value) {
3406 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3407 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3408 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3409 default:
3410 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3412 checkGLcall("glPolygonMode (fillmode)");
3413 break;
3415 case WINED3DRS_LIGHTING :
3416 if (Value) {
3417 glEnable(GL_LIGHTING);
3418 checkGLcall("glEnable GL_LIGHTING");
3419 } else {
3420 glDisable(GL_LIGHTING);
3421 checkGLcall("glDisable GL_LIGHTING");
3423 break;
3425 case WINED3DRS_ZENABLE :
3426 switch ((D3DZBUFFERTYPE) Value) {
3427 case D3DZB_FALSE:
3428 glDisable(GL_DEPTH_TEST);
3429 checkGLcall("glDisable GL_DEPTH_TEST");
3430 break;
3431 case D3DZB_TRUE:
3432 glEnable(GL_DEPTH_TEST);
3433 checkGLcall("glEnable GL_DEPTH_TEST");
3434 break;
3435 case D3DZB_USEW:
3436 glEnable(GL_DEPTH_TEST);
3437 checkGLcall("glEnable GL_DEPTH_TEST");
3438 FIXME("W buffer is not well handled\n");
3439 break;
3440 default:
3441 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3443 break;
3445 case WINED3DRS_CULLMODE :
3447 /* If we are culling "back faces with clockwise vertices" then
3448 set front faces to be counter clockwise and enable culling
3449 of back faces */
3450 switch ((D3DCULL) Value) {
3451 case D3DCULL_NONE:
3452 glDisable(GL_CULL_FACE);
3453 checkGLcall("glDisable GL_CULL_FACE");
3454 break;
3455 case D3DCULL_CW:
3456 glEnable(GL_CULL_FACE);
3457 checkGLcall("glEnable GL_CULL_FACE");
3458 if (This->renderUpsideDown) {
3459 glFrontFace(GL_CW);
3460 checkGLcall("glFrontFace GL_CW");
3461 } else {
3462 glFrontFace(GL_CCW);
3463 checkGLcall("glFrontFace GL_CCW");
3465 glCullFace(GL_BACK);
3466 break;
3467 case D3DCULL_CCW:
3468 glEnable(GL_CULL_FACE);
3469 checkGLcall("glEnable GL_CULL_FACE");
3470 if (This->renderUpsideDown) {
3471 glFrontFace(GL_CCW);
3472 checkGLcall("glFrontFace GL_CCW");
3473 } else {
3474 glFrontFace(GL_CW);
3475 checkGLcall("glFrontFace GL_CW");
3477 glCullFace(GL_BACK);
3478 break;
3479 default:
3480 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3482 break;
3484 case WINED3DRS_SHADEMODE :
3485 switch ((D3DSHADEMODE) Value) {
3486 case D3DSHADE_FLAT:
3487 glShadeModel(GL_FLAT);
3488 checkGLcall("glShadeModel");
3489 break;
3490 case D3DSHADE_GOURAUD:
3491 glShadeModel(GL_SMOOTH);
3492 checkGLcall("glShadeModel");
3493 break;
3494 case D3DSHADE_PHONG:
3495 FIXME("D3DSHADE_PHONG isn't supported\n");
3496 break;
3497 default:
3498 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3500 break;
3502 case WINED3DRS_DITHERENABLE :
3503 if (Value) {
3504 glEnable(GL_DITHER);
3505 checkGLcall("glEnable GL_DITHER");
3506 } else {
3507 glDisable(GL_DITHER);
3508 checkGLcall("glDisable GL_DITHER");
3510 break;
3512 case WINED3DRS_ZWRITEENABLE :
3513 if (Value) {
3514 glDepthMask(1);
3515 checkGLcall("glDepthMask");
3516 } else {
3517 glDepthMask(0);
3518 checkGLcall("glDepthMask");
3520 break;
3522 case WINED3DRS_ZFUNC :
3524 int glParm = CompareFunc(Value);
3526 if(glParm) {
3527 glDepthFunc(glParm);
3528 checkGLcall("glDepthFunc");
3531 break;
3533 case WINED3DRS_AMBIENT :
3535 float col[4];
3536 D3DCOLORTOGLFLOAT4(Value, col);
3537 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3538 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3539 checkGLcall("glLightModel for MODEL_AMBIENT");
3542 break;
3544 case WINED3DRS_ALPHABLENDENABLE :
3545 if (Value) {
3546 glEnable(GL_BLEND);
3547 checkGLcall("glEnable GL_BLEND");
3548 } else {
3549 glDisable(GL_BLEND);
3550 checkGLcall("glDisable GL_BLEND");
3552 break;
3554 case WINED3DRS_SRCBLEND :
3555 case WINED3DRS_DESTBLEND :
3557 int newVal = GL_ZERO;
3558 switch (Value) {
3559 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3560 case D3DBLEND_ONE : newVal = GL_ONE; break;
3561 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3562 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3563 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3564 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3565 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3566 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3567 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3568 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3569 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3571 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3572 This->srcBlend = newVal;
3573 This->dstBlend = newVal;
3574 break;
3576 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3577 This->srcBlend = newVal;
3578 This->dstBlend = newVal;
3579 break;
3580 case D3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3581 case D3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3582 default:
3583 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3586 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3587 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3588 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3589 glBlendFunc(This->srcBlend, This->dstBlend);
3591 checkGLcall("glBlendFunc");
3593 break;
3595 case WINED3DRS_ALPHATESTENABLE :
3596 case WINED3DRS_ALPHAFUNC :
3597 case WINED3DRS_ALPHAREF :
3598 case WINED3DRS_COLORKEYENABLE :
3600 int glParm = 0;
3601 float ref;
3602 BOOL enable_ckey = FALSE;
3604 IWineD3DSurfaceImpl *surf;
3606 /* Find out if the texture on the first stage has a ckey set */
3607 if(This->stateBlock->textures[0]) {
3608 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3609 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3612 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3613 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3614 glEnable(GL_ALPHA_TEST);
3615 checkGLcall("glEnable GL_ALPHA_TEST");
3616 } else {
3617 glDisable(GL_ALPHA_TEST);
3618 checkGLcall("glDisable GL_ALPHA_TEST");
3619 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3620 * enable call
3622 break;
3625 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3626 glParm = GL_NOTEQUAL;
3627 ref = 0.0;
3628 } else {
3629 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3630 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3632 if(glParm) {
3633 This->alphafunc = glParm;
3634 glAlphaFunc(glParm, ref);
3635 checkGLcall("glAlphaFunc");
3638 break;
3640 case WINED3DRS_CLIPPLANEENABLE :
3641 case WINED3DRS_CLIPPING :
3643 /* Ensure we only do the changed clip planes */
3644 DWORD enable = 0xFFFFFFFF;
3645 DWORD disable = 0x00000000;
3647 /* If enabling / disabling all */
3648 if (State == WINED3DRS_CLIPPING) {
3649 if (Value) {
3650 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3651 disable = 0x00;
3652 } else {
3653 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3654 enable = 0x00;
3656 } else {
3657 enable = Value & ~OldValue;
3658 disable = ~Value & OldValue;
3661 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3662 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3663 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3664 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3665 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3666 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3668 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3669 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3670 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3671 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3672 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3673 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3675 /** update clipping status */
3676 if (enable) {
3677 This->stateBlock->clip_status.ClipUnion = 0;
3678 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3679 } else {
3680 This->stateBlock->clip_status.ClipUnion = 0;
3681 This->stateBlock->clip_status.ClipIntersection = 0;
3684 break;
3686 case WINED3DRS_BLENDOP :
3688 int glParm = GL_FUNC_ADD;
3690 switch ((D3DBLENDOP) Value) {
3691 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3692 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3693 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3694 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3695 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3696 default:
3697 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3700 if(GL_SUPPORT(ARB_IMAGING)) {
3701 TRACE("glBlendEquation(%x)\n", glParm);
3702 GL_EXTCALL(glBlendEquation(glParm));
3703 checkGLcall("glBlendEquation");
3704 } else {
3705 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3708 break;
3710 case WINED3DRS_TEXTUREFACTOR :
3712 unsigned int i;
3714 /* Note the texture color applies to all textures whereas
3715 GL_TEXTURE_ENV_COLOR applies to active only */
3716 float col[4];
3717 D3DCOLORTOGLFLOAT4(Value, col);
3719 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3720 /* And now the default texture color as well */
3721 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3722 /* Note the D3DRS value applies to all textures, but GL has one
3723 per texture, so apply it now ready to be used! */
3724 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3725 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3726 checkGLcall("glActiveTextureARB");
3727 } else if (i>0) {
3728 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3731 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3732 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3736 break;
3738 case WINED3DRS_SPECULARENABLE :
3740 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3741 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3742 specular color. This is wrong:
3743 Separate specular color means the specular colour is maintained separately, whereas
3744 single color means it is merged in. However in both cases they are being used to
3745 some extent.
3746 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3747 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3748 running 1.4 yet!
3751 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3752 * Instead, we need to setup the FinalCombiner properly.
3754 * The default setup for the FinalCombiner is:
3756 * <variable> <input> <mapping> <usage>
3757 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3758 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3759 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3760 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3761 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3762 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3763 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3765 * That's pretty much fine as it is, except for variable B, which needs to take
3766 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3767 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3770 if (Value) {
3771 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3772 checkGLcall("glMaterialfv");
3773 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3774 glEnable(GL_COLOR_SUM_EXT);
3775 } else {
3776 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3778 checkGLcall("glEnable(GL_COLOR_SUM)");
3780 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3781 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3782 checkGLcall("glFinalCombinerInputNV()");
3784 } else {
3785 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3787 /* for the case of enabled lighting: */
3788 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3789 checkGLcall("glMaterialfv");
3791 /* for the case of disabled lighting: */
3792 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3793 glDisable(GL_COLOR_SUM_EXT);
3794 } else {
3795 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3797 checkGLcall("glDisable(GL_COLOR_SUM)");
3799 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3800 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3801 checkGLcall("glFinalCombinerInputNV()");
3805 break;
3807 case WINED3DRS_STENCILENABLE :
3808 case WINED3DRS_TWOSIDEDSTENCILMODE :
3809 case WINED3DRS_STENCILFUNC :
3810 case WINED3DRS_CCW_STENCILFUNC :
3811 case WINED3DRS_STENCILREF :
3812 case WINED3DRS_STENCILMASK :
3813 case WINED3DRS_STENCILFAIL :
3814 case WINED3DRS_STENCILZFAIL :
3815 case WINED3DRS_STENCILPASS :
3816 case WINED3DRS_CCW_STENCILFAIL :
3817 case WINED3DRS_CCW_STENCILZFAIL :
3818 case WINED3DRS_CCW_STENCILPASS :
3819 renderstate_stencil(This, State, Value);
3820 break;
3821 case WINED3DRS_STENCILWRITEMASK :
3823 glStencilMask(Value);
3824 TRACE("glStencilMask(%lu)\n", Value);
3825 checkGLcall("glStencilMask");
3827 break;
3829 case WINED3DRS_FOGENABLE :
3831 if (Value) {
3832 glEnable(GL_FOG);
3833 checkGLcall("glEnable GL_FOG");
3834 } else {
3835 glDisable(GL_FOG);
3836 checkGLcall("glDisable GL_FOG");
3839 break;
3841 case WINED3DRS_RANGEFOGENABLE :
3843 if (Value) {
3844 TRACE("Enabled RANGEFOG\n");
3845 } else {
3846 TRACE("Disabled RANGEFOG\n");
3849 break;
3851 case WINED3DRS_FOGCOLOR :
3853 float col[4];
3854 D3DCOLORTOGLFLOAT4(Value, col);
3855 /* Set the default alpha blend color */
3856 glFogfv(GL_FOG_COLOR, &col[0]);
3857 checkGLcall("glFog GL_FOG_COLOR");
3859 break;
3861 case WINED3DRS_FOGTABLEMODE :
3862 case WINED3DRS_FOGVERTEXMODE :
3864 /* 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." */
3865 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3866 glHint(GL_FOG_HINT, GL_FASTEST);
3867 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3868 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3869 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3870 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3872 case D3DFOG_EXP: {
3873 if(!This->last_was_rhw) {
3874 glFogi(GL_FOG_MODE, GL_EXP);
3875 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3876 if(GL_SUPPORT(EXT_FOG_COORD)) {
3877 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3878 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3879 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3880 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3882 break;
3885 case D3DFOG_EXP2: {
3886 if(!This->last_was_rhw) {
3887 glFogi(GL_FOG_MODE, GL_EXP2);
3888 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3889 if(GL_SUPPORT(EXT_FOG_COORD)) {
3890 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3891 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3892 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3893 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3895 break;
3898 case D3DFOG_LINEAR: {
3899 if(!This->last_was_rhw) {
3900 glFogi(GL_FOG_MODE, GL_LINEAR);
3901 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3902 if(GL_SUPPORT(EXT_FOG_COORD)) {
3903 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3904 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3905 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3906 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3908 break;
3911 case D3DFOG_NONE: {
3912 /* Both are none? According to msdn the alpha channel of the specular
3913 * color contains a fog factor. Set it in drawStridedSlow.
3914 * Same happens with Vertexfog on transformed vertices
3916 if(GL_SUPPORT(EXT_FOG_COORD)) {
3917 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3918 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3919 glFogi(GL_FOG_MODE, GL_LINEAR);
3920 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3921 glFogf(GL_FOG_START, (float) 0xff);
3922 checkGLcall("glFogfv GL_FOG_START");
3923 glFogf(GL_FOG_END, 0.0);
3924 checkGLcall("glFogfv GL_FOG_END");
3925 } else {
3926 /* Disable GL fog, handle this in software in drawStridedSlow */
3927 glDisable(GL_FOG);
3928 checkGLcall("glDisable(GL_FOG)");
3930 break;
3932 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3934 } else {
3935 glHint(GL_FOG_HINT, GL_NICEST);
3936 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3937 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3938 case D3DFOG_EXP: 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;
3947 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3948 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3949 if(GL_SUPPORT(EXT_FOG_COORD)) {
3950 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3951 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3952 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3953 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3955 break;
3956 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3957 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3958 if(GL_SUPPORT(EXT_FOG_COORD)) {
3959 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3960 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3961 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3962 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3964 break;
3965 case D3DFOG_NONE: /* Won't happen */
3966 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3969 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3970 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3973 break;
3975 case WINED3DRS_FOGSTART :
3977 tmpvalue.d = Value;
3978 glFogfv(GL_FOG_START, &tmpvalue.f);
3979 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
3980 TRACE("Fog Start == %f\n", tmpvalue.f);
3982 break;
3984 case WINED3DRS_FOGEND :
3986 tmpvalue.d = Value;
3987 glFogfv(GL_FOG_END, &tmpvalue.f);
3988 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
3989 TRACE("Fog End == %f\n", tmpvalue.f);
3991 break;
3993 case WINED3DRS_FOGDENSITY :
3995 tmpvalue.d = Value;
3996 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
3997 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
3999 break;
4001 case WINED3DRS_VERTEXBLEND :
4003 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4004 TRACE("Vertex Blending state to %ld\n", Value);
4006 break;
4008 case WINED3DRS_TWEENFACTOR :
4010 tmpvalue.d = Value;
4011 This->updateStateBlock->tween_factor = tmpvalue.f;
4012 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4014 break;
4016 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4018 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4020 break;
4022 case WINED3DRS_COLORVERTEX :
4023 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4024 case WINED3DRS_SPECULARMATERIALSOURCE :
4025 case WINED3DRS_AMBIENTMATERIALSOURCE :
4026 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4028 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4030 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4031 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4032 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4033 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4034 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4035 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4037 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4038 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4039 Parm = GL_AMBIENT_AND_DIFFUSE;
4040 } else {
4041 Parm = GL_DIFFUSE;
4043 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4044 Parm = GL_AMBIENT;
4045 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4046 Parm = GL_EMISSION;
4047 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4048 Parm = GL_SPECULAR;
4049 } else {
4050 Parm = -1;
4053 if (Parm == -1) {
4054 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4055 } else {
4056 This->tracking_color = NEEDS_TRACKING;
4057 This->tracking_parm = Parm;
4060 } else {
4061 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4064 break;
4066 case WINED3DRS_LINEPATTERN :
4068 union {
4069 DWORD d;
4070 D3DLINEPATTERN lp;
4071 } tmppattern;
4072 tmppattern.d = Value;
4074 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4076 if (tmppattern.lp.wRepeatFactor) {
4077 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4078 checkGLcall("glLineStipple(repeat, linepattern)");
4079 glEnable(GL_LINE_STIPPLE);
4080 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4081 } else {
4082 glDisable(GL_LINE_STIPPLE);
4083 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4086 break;
4088 case WINED3DRS_ZBIAS : /* D3D8 only */
4090 if (Value) {
4091 tmpvalue.d = Value;
4092 TRACE("ZBias value %f\n", tmpvalue.f);
4093 glPolygonOffset(0, -tmpvalue.f);
4094 checkGLcall("glPolygonOffset(0, -Value)");
4095 glEnable(GL_POLYGON_OFFSET_FILL);
4096 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4097 glEnable(GL_POLYGON_OFFSET_LINE);
4098 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4099 glEnable(GL_POLYGON_OFFSET_POINT);
4100 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4101 } else {
4102 glDisable(GL_POLYGON_OFFSET_FILL);
4103 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4104 glDisable(GL_POLYGON_OFFSET_LINE);
4105 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4106 glDisable(GL_POLYGON_OFFSET_POINT);
4107 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4110 break;
4112 case WINED3DRS_NORMALIZENORMALS :
4113 if (Value) {
4114 glEnable(GL_NORMALIZE);
4115 checkGLcall("glEnable(GL_NORMALIZE);");
4116 } else {
4117 glDisable(GL_NORMALIZE);
4118 checkGLcall("glDisable(GL_NORMALIZE);");
4120 break;
4122 case WINED3DRS_POINTSIZE :
4123 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4124 tmpvalue.d = Value;
4125 TRACE("Set point size to %f\n", tmpvalue.f);
4126 glPointSize(tmpvalue.f);
4127 checkGLcall("glPointSize(...);");
4128 break;
4130 case WINED3DRS_POINTSIZE_MIN :
4131 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4132 tmpvalue.d = Value;
4133 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4134 checkGLcall("glPointParameterfEXT(...);");
4135 } else {
4136 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4138 break;
4140 case WINED3DRS_POINTSIZE_MAX :
4141 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4142 tmpvalue.d = Value;
4143 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4144 checkGLcall("glPointParameterfEXT(...);");
4145 } else {
4146 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4148 break;
4150 case WINED3DRS_POINTSCALE_A :
4151 case WINED3DRS_POINTSCALE_B :
4152 case WINED3DRS_POINTSCALE_C :
4153 case WINED3DRS_POINTSCALEENABLE :
4156 * POINTSCALEENABLE controls how point size value is treated. If set to
4157 * true, the point size is scaled with respect to height of viewport.
4158 * When set to false point size is in pixels.
4160 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4163 /* Default values */
4164 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4167 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4168 * This means that OpenGL will clamp really small point sizes to 1.0f.
4169 * To correct for this we need to multiply by the scale factor when sizes
4170 * are less than 1.0f. scale_factor = 1.0f / point_size.
4172 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4173 if(pointSize > 0.0f) {
4174 GLfloat scaleFactor;
4176 if(pointSize < 1.0f) {
4177 scaleFactor = pointSize * pointSize;
4178 } else {
4179 scaleFactor = 1.0f;
4182 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4183 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4184 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4185 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4186 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4187 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4188 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4192 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4193 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4194 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4196 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4197 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4198 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4199 } else {
4200 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4202 break;
4204 case WINED3DRS_COLORWRITEENABLE :
4206 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4207 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4208 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4209 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4210 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4211 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4212 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4213 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4214 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4215 checkGLcall("glColorMask(...)");
4217 break;
4219 case WINED3DRS_LOCALVIEWER :
4221 GLint state = (Value) ? 1 : 0;
4222 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4223 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4225 break;
4227 case WINED3DRS_LASTPIXEL :
4229 if (Value) {
4230 TRACE("Last Pixel Drawing Enabled\n");
4231 } else {
4232 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4235 break;
4237 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4239 if (Value) {
4240 TRACE("Software Processing Enabled\n");
4241 } else {
4242 TRACE("Software Processing Disabled\n");
4245 break;
4247 /** not supported */
4248 case WINED3DRS_ZVISIBLE :
4250 LEAVE_GL();
4251 return WINED3DERR_INVALIDCALL;
4253 case WINED3DRS_POINTSPRITEENABLE :
4255 /* TODO: NV_POINT_SPRITE */
4256 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4257 TRACE("Point sprites not supported\n");
4258 break;
4262 * Point sprites are always enabled. Value controls texture coordinate
4263 * replacement mode. Must be set true for point sprites to use
4264 * textures.
4266 glEnable(GL_POINT_SPRITE_ARB);
4267 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4269 if (Value) {
4270 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4271 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4272 } else {
4273 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4274 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4276 break;
4278 case WINED3DRS_EDGEANTIALIAS :
4280 if(Value) {
4281 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4282 glEnable(GL_BLEND);
4283 checkGLcall("glEnable(GL_BLEND)");
4284 glEnable(GL_LINE_SMOOTH);
4285 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4286 } else {
4287 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4288 glDisable(GL_BLEND);
4289 checkGLcall("glDisable(GL_BLEND)");
4291 glDisable(GL_LINE_SMOOTH);
4292 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4294 break;
4296 case WINED3DRS_WRAP0 :
4297 case WINED3DRS_WRAP1 :
4298 case WINED3DRS_WRAP2 :
4299 case WINED3DRS_WRAP3 :
4300 case WINED3DRS_WRAP4 :
4301 case WINED3DRS_WRAP5 :
4302 case WINED3DRS_WRAP6 :
4303 case WINED3DRS_WRAP7 :
4304 case WINED3DRS_WRAP8 :
4305 case WINED3DRS_WRAP9 :
4306 case WINED3DRS_WRAP10 :
4307 case WINED3DRS_WRAP11 :
4308 case WINED3DRS_WRAP12 :
4309 case WINED3DRS_WRAP13 :
4310 case WINED3DRS_WRAP14 :
4311 case WINED3DRS_WRAP15 :
4313 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4314 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4315 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4316 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4317 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4319 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4322 if(Value) {
4323 ERR("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4325 break;
4328 case WINED3DRS_MULTISAMPLEANTIALIAS :
4330 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4331 if(Value) {
4332 glEnable(GL_MULTISAMPLE_ARB);
4333 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4334 } else {
4335 glDisable(GL_MULTISAMPLE_ARB);
4336 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4338 } else {
4339 if(Value) {
4340 ERR("Multisample antialiasing not supported by gl\n");
4343 break;
4346 case WINED3DRS_SCISSORTESTENABLE :
4348 if(Value) {
4349 glEnable(GL_SCISSOR_TEST);
4350 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4351 } else {
4352 glDisable(GL_SCISSOR_TEST);
4353 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4355 break;
4357 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4359 if(Value) {
4360 tmpvalue.d = Value;
4361 glEnable(GL_POLYGON_OFFSET_FILL);
4362 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4363 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4364 checkGLcall("glPolygonOffset(...)");
4365 } else {
4366 glDisable(GL_POLYGON_OFFSET_FILL);
4367 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4369 break;
4371 case WINED3DRS_ANTIALIASEDLINEENABLE :
4373 if(Value) {
4374 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4375 glEnable(GL_BLEND);
4376 checkGLcall("glEnable(GL_BLEND)");
4377 glEnable(GL_LINE_SMOOTH);
4378 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4379 } else {
4380 glDisable(GL_BLEND);
4381 checkGLcall("glDisable(GL_BLEND)");
4382 glDisable(GL_LINE_SMOOTH);
4383 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4385 break;
4387 case WINED3DRS_DEPTHBIAS :
4389 if(Value) {
4390 tmpvalue.d = Value;
4391 glEnable(GL_POLYGON_OFFSET_FILL);
4392 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4393 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4394 checkGLcall("glPolygonOffset(...)");
4395 } else {
4396 glDisable(GL_POLYGON_OFFSET_FILL);
4397 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4399 break;
4402 case WINED3DRS_TEXTUREPERSPECTIVE :
4404 if (Value)
4405 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4406 else
4407 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4408 break;
4411 case WINED3DRS_STIPPLEDALPHA :
4413 if (Value)
4414 ERR(" Stippled Alpha not supported yet.\n");
4415 break;
4417 case WINED3DRS_ANTIALIAS :
4419 if (Value)
4420 ERR(" Antialias not supported yet.\n");
4421 break;
4424 case WINED3DRS_MULTISAMPLEMASK :
4426 if(0xFFFFFFFF != Value)
4427 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4428 break;
4431 case WINED3DRS_PATCHEDGESTYLE :
4433 if(D3DPATCHEDGE_DISCRETE != Value)
4434 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4435 break;
4438 case WINED3DRS_PATCHSEGMENTS :
4440 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4441 tmpvalue.f = 1.0f;
4442 if(tmpvalue.d != Value)
4443 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4444 break;
4447 case WINED3DRS_DEBUGMONITORTOKEN :
4449 /* Only useful for "debug builds". */
4450 if(0xbaadcafe != Value) {
4451 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4452 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4453 * but our tests disagree.
4454 * We do not claim to implement a debugging lib, so do not write an ERR
4456 WARN("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4458 break;
4461 case WINED3DRS_POSITIONDEGREE :
4463 if(D3DDEGREE_CUBIC != Value)
4464 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4465 break;
4468 case WINED3DRS_NORMALDEGREE :
4470 if(D3DDEGREE_LINEAR != Value)
4471 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4472 break;
4475 case WINED3DRS_MINTESSELLATIONLEVEL :
4476 case WINED3DRS_MAXTESSELLATIONLEVEL :
4477 case WINED3DRS_ADAPTIVETESS_X :
4478 case WINED3DRS_ADAPTIVETESS_Y :
4479 case WINED3DRS_ADAPTIVETESS_Z :
4480 case WINED3DRS_ADAPTIVETESS_W :
4482 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4483 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4484 else
4485 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4486 break;
4489 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4491 if(Value)
4492 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4493 break;
4496 case WINED3DRS_COLORWRITEENABLE1 :
4497 case WINED3DRS_COLORWRITEENABLE2 :
4498 case WINED3DRS_COLORWRITEENABLE3 :
4500 /* depends on WINED3DRS_COLORWRITEENABLE. */
4501 if(0x0000000F != Value)
4502 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4503 break;
4506 case WINED3DRS_BLENDFACTOR :
4508 float col[4];
4509 if (GL_SUPPORT(ARB_IMAGING)) {
4511 TRACE("Setting BlendFactor to %ld", Value);
4513 D3DCOLORTOGLFLOAT4(Value, col);
4514 if (0xFFFFFFFF != Value) {
4515 glEnable(GL_BLEND);
4516 checkGLcall("glEnable(GL_BLEND)");
4518 else {
4519 glDisable(GL_BLEND);
4520 checkGLcall("glDisable(GL_BLEND)");
4522 glBlendColor (col[0],col[1],col[2],col[3]);
4523 } else {
4524 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
4526 break;
4529 case WINED3DRS_SRGBWRITEENABLE :
4531 if(Value)
4532 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4533 break;
4536 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4538 if(Value)
4539 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4540 break;
4543 case WINED3DRS_SRCBLENDALPHA :
4544 case WINED3DRS_DESTBLENDALPHA :
4545 case WINED3DRS_BLENDOPALPHA :
4547 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4548 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4549 else
4550 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4551 break;
4554 default:
4555 FIXME("(%p)->(%s,%ld) unknown state\n", This, debug_d3drenderstate(State), Value);
4558 LEAVE_GL();
4560 return WINED3D_OK;
4563 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4565 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4566 *pValue = This->stateBlock->renderState[State];
4567 return WINED3D_OK;
4570 /*****
4571 * Get / Set Sampler States
4572 * TODO: Verify against dx9 definitions
4573 *****/
4575 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 * SetSampler is designed to allow for more than the standard up to 8 textures
4579 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4580 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4582 * http://developer.nvidia.com/object/General_FAQ.html#t6
4584 * There are two new settings for GForce
4585 * the sampler one:
4586 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4587 * and the texture one:
4588 * GL_MAX_TEXTURE_COORDS_ARB.
4589 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4590 ******************/
4591 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4592 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4593 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4594 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4595 return WINED3DERR_INVALIDCALL;
4598 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4599 debug_d3dsamplerstate(Type), Type, Value);
4600 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4601 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4602 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4604 /* Handle recording of state blocks */
4605 if (This->isRecordingState) {
4606 TRACE("Recording... not performing anything\n");
4607 return WINED3D_OK;
4610 return WINED3D_OK;
4613 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 /** TODO: check that sampler is in range **/
4616 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4617 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4619 return WINED3D_OK;
4622 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 ENTER_GL();
4626 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4627 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4628 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4629 LEAVE_GL();
4631 return WINED3D_OK;
4634 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4636 GLint scissorBox[4];
4638 ENTER_GL();
4639 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4640 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4641 pRect->left = scissorBox[0];
4642 pRect->top = scissorBox[1];
4643 pRect->right = scissorBox[0] + scissorBox[2];
4644 pRect->bottom = scissorBox[1] + scissorBox[3];
4645 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4646 LEAVE_GL();
4647 return WINED3D_OK;
4650 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4652 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4654 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4656 This->updateStateBlock->vertexDecl = pDecl;
4657 This->updateStateBlock->changed.vertexDecl = TRUE;
4658 This->updateStateBlock->set.vertexDecl = TRUE;
4660 if (This->isRecordingState) {
4661 TRACE("Recording... not performing anything\n");
4664 if (NULL != pDecl) {
4665 IWineD3DVertexDeclaration_AddRef(pDecl);
4667 if (NULL != oldDecl) {
4668 IWineD3DVertexDeclaration_Release(oldDecl);
4670 return WINED3D_OK;
4673 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4676 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4678 *ppDecl = This->stateBlock->vertexDecl;
4679 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4680 return WINED3D_OK;
4683 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4687 This->updateStateBlock->vertexShader = pShader;
4688 This->updateStateBlock->changed.vertexShader = TRUE;
4689 This->updateStateBlock->set.vertexShader = TRUE;
4691 if (This->isRecordingState) {
4692 TRACE("Recording... not performing anything\n");
4695 if (NULL != pShader) {
4696 IWineD3DVertexShader_AddRef(pShader);
4698 if (NULL != oldShader) {
4699 IWineD3DVertexShader_Release(oldShader);
4702 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4704 * TODO: merge HAL shaders context switching from prototype
4706 return WINED3D_OK;
4709 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 if (NULL == ppShader) {
4713 return WINED3DERR_INVALIDCALL;
4715 *ppShader = This->stateBlock->vertexShader;
4716 if( NULL != *ppShader)
4717 IWineD3DVertexShader_AddRef(*ppShader);
4719 TRACE("(%p) : returning %p\n", This, *ppShader);
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4724 IWineD3DDevice *iface,
4725 UINT start,
4726 CONST BOOL *srcData,
4727 UINT count) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 int i, cnt = min(count, MAX_CONST_B - start);
4732 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4733 iface, srcData, start, count);
4735 if (srcData == NULL || cnt < 0)
4736 return WINED3DERR_INVALIDCALL;
4738 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4739 for (i = 0; i < cnt; i++)
4740 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4742 for (i = start; i < cnt + start; ++i) {
4743 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4744 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4747 return WINED3D_OK;
4750 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4751 IWineD3DDevice *iface,
4752 UINT start,
4753 BOOL *dstData,
4754 UINT count) {
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 int cnt = min(count, MAX_CONST_B - start);
4759 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4760 iface, dstData, start, count);
4762 if (dstData == NULL || cnt < 0)
4763 return WINED3DERR_INVALIDCALL;
4765 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4766 return WINED3D_OK;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4770 IWineD3DDevice *iface,
4771 UINT start,
4772 CONST int *srcData,
4773 UINT count) {
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 int i, cnt = min(count, MAX_CONST_I - start);
4778 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4779 iface, srcData, start, count);
4781 if (srcData == NULL || cnt < 0)
4782 return WINED3DERR_INVALIDCALL;
4784 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4785 for (i = 0; i < cnt; i++)
4786 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4787 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4789 for (i = start; i < cnt + start; ++i) {
4790 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4791 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4794 return WINED3D_OK;
4797 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4798 IWineD3DDevice *iface,
4799 UINT start,
4800 int *dstData,
4801 UINT count) {
4803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4804 int cnt = min(count, MAX_CONST_I - start);
4806 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4807 iface, dstData, start, count);
4809 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4810 return WINED3DERR_INVALIDCALL;
4812 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4813 return WINED3D_OK;
4816 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4817 IWineD3DDevice *iface,
4818 UINT start,
4819 CONST float *srcData,
4820 UINT count) {
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4825 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4826 iface, srcData, start, count);
4828 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4829 return WINED3DERR_INVALIDCALL;
4831 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4832 for (i = 0; i < cnt; i++)
4833 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4834 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4836 for (i = start; i < cnt + start; ++i) {
4837 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4838 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4839 ptr->idx = i;
4840 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4841 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4843 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4846 return WINED3D_OK;
4849 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4850 IWineD3DDevice *iface,
4851 UINT start,
4852 float *dstData,
4853 UINT count) {
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4858 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4859 iface, dstData, start, count);
4861 if (dstData == NULL || cnt < 0)
4862 return WINED3DERR_INVALIDCALL;
4864 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4865 return WINED3D_OK;
4868 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4870 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4871 This->updateStateBlock->pixelShader = pShader;
4872 This->updateStateBlock->changed.pixelShader = TRUE;
4873 This->updateStateBlock->set.pixelShader = TRUE;
4875 /* Handle recording of state blocks */
4876 if (This->isRecordingState) {
4877 TRACE("Recording... not performing anything\n");
4880 if (NULL != pShader) {
4881 IWineD3DPixelShader_AddRef(pShader);
4883 if (NULL != oldShader) {
4884 IWineD3DPixelShader_Release(oldShader);
4887 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4889 * TODO: merge HAL shaders context switching from prototype
4891 return WINED3D_OK;
4894 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 if (NULL == ppShader) {
4898 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4899 return WINED3DERR_INVALIDCALL;
4902 *ppShader = This->stateBlock->pixelShader;
4903 if (NULL != *ppShader) {
4904 IWineD3DPixelShader_AddRef(*ppShader);
4906 TRACE("(%p) : returning %p\n", This, *ppShader);
4907 return WINED3D_OK;
4910 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4911 IWineD3DDevice *iface,
4912 UINT start,
4913 CONST BOOL *srcData,
4914 UINT count) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 int i, cnt = min(count, MAX_CONST_B - start);
4919 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4920 iface, srcData, start, count);
4922 if (srcData == NULL || cnt < 0)
4923 return WINED3DERR_INVALIDCALL;
4925 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4926 for (i = 0; i < cnt; i++)
4927 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4929 for (i = start; i < cnt + start; ++i) {
4930 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4931 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4934 return WINED3D_OK;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4938 IWineD3DDevice *iface,
4939 UINT start,
4940 BOOL *dstData,
4941 UINT count) {
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4944 int cnt = min(count, MAX_CONST_B - start);
4946 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4947 iface, dstData, start, count);
4949 if (dstData == NULL || cnt < 0)
4950 return WINED3DERR_INVALIDCALL;
4952 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4953 return WINED3D_OK;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4957 IWineD3DDevice *iface,
4958 UINT start,
4959 CONST int *srcData,
4960 UINT count) {
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 int i, cnt = min(count, MAX_CONST_I - start);
4965 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4966 iface, srcData, start, count);
4968 if (srcData == NULL || cnt < 0)
4969 return WINED3DERR_INVALIDCALL;
4971 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4972 for (i = 0; i < cnt; i++)
4973 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4974 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4976 for (i = start; i < cnt + start; ++i) {
4977 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4978 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4981 return WINED3D_OK;
4984 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4985 IWineD3DDevice *iface,
4986 UINT start,
4987 int *dstData,
4988 UINT count) {
4990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4991 int cnt = min(count, MAX_CONST_I - start);
4993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4994 iface, dstData, start, count);
4996 if (dstData == NULL || cnt < 0)
4997 return WINED3DERR_INVALIDCALL;
4999 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5000 return WINED3D_OK;
5003 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5004 IWineD3DDevice *iface,
5005 UINT start,
5006 CONST float *srcData,
5007 UINT count) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5010 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5012 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5013 iface, srcData, start, count);
5015 if (srcData == NULL || cnt < 0)
5016 return WINED3DERR_INVALIDCALL;
5018 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5019 for (i = 0; i < cnt; i++)
5020 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5021 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5023 for (i = start; i < cnt + start; ++i) {
5024 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5025 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5026 ptr->idx = i;
5027 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5028 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5030 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5033 return WINED3D_OK;
5036 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5037 IWineD3DDevice *iface,
5038 UINT start,
5039 float *dstData,
5040 UINT count) {
5042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5043 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5045 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5046 iface, dstData, start, count);
5048 if (dstData == NULL || cnt < 0)
5049 return WINED3DERR_INVALIDCALL;
5051 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5052 return WINED3D_OK;
5055 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5056 static HRESULT
5057 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5058 char *dest_ptr, *dest_conv = NULL;
5059 unsigned int i;
5060 DWORD DestFVF = dest->fvf;
5061 D3DVIEWPORT9 vp;
5062 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5063 BOOL doClip;
5064 int numTextures;
5066 if (SrcFVF & D3DFVF_NORMAL) {
5067 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5070 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5071 ERR("Source has no position mask\n");
5072 return WINED3DERR_INVALIDCALL;
5075 /* We might access VBOs from this code, so hold the lock */
5076 ENTER_GL();
5078 if (dest->resource.allocatedMemory == NULL) {
5079 /* This may happen if we do direct locking into a vbo. Unlikely,
5080 * but theoretically possible(ddraw processvertices test)
5082 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5083 if(!dest->resource.allocatedMemory) {
5084 LEAVE_GL();
5085 ERR("Out of memory\n");
5086 return E_OUTOFMEMORY;
5088 if(dest->vbo) {
5089 void *src;
5090 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5091 checkGLcall("glBindBufferARB");
5092 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5093 if(src) {
5094 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5096 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5097 checkGLcall("glUnmapBufferARB");
5101 /* Get a pointer into the destination vbo(create one if none exists) and
5102 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5104 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5105 CreateVBO(dest);
5108 if(dest->vbo) {
5109 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5110 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5111 if(!dest_conv) {
5112 ERR("glMapBuffer failed\n");
5113 /* Continue without storing converted vertices */
5117 /* Should I clip?
5118 * a) D3DRS_CLIPPING is enabled
5119 * b) WINED3DVOP_CLIP is passed
5121 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5122 static BOOL warned = FALSE;
5124 * The clipping code is not quite correct. Some things need
5125 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5126 * so disable clipping for now.
5127 * (The graphics in Half-Life are broken, and my processvertices
5128 * test crashes with IDirect3DDevice3)
5129 doClip = TRUE;
5131 doClip = FALSE;
5132 if(!warned) {
5133 warned = TRUE;
5134 FIXME("Clipping is broken and disabled for now\n");
5136 } else doClip = FALSE;
5137 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5138 if(dest_conv) {
5139 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5142 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5143 WINED3DTS_VIEW,
5144 &view_mat);
5145 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5146 WINED3DTS_PROJECTION,
5147 &proj_mat);
5148 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5149 WINED3DTS_WORLDMATRIX(0),
5150 &world_mat);
5152 TRACE("View mat:\n");
5153 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); \
5154 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); \
5155 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); \
5156 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); \
5158 TRACE("Proj mat:\n");
5159 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); \
5160 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); \
5161 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); \
5162 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); \
5164 TRACE("World mat:\n");
5165 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); \
5166 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); \
5167 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); \
5168 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); \
5170 /* Get the viewport */
5171 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5172 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5173 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5175 multiply_matrix(&mat,&view_mat,&world_mat);
5176 multiply_matrix(&mat,&proj_mat,&mat);
5178 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5180 for (i = 0; i < dwCount; i+= 1) {
5181 unsigned int tex_index;
5183 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5184 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5185 /* The position first */
5186 float *p =
5187 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5188 float x, y, z, rhw;
5189 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5191 /* Multiplication with world, view and projection matrix */
5192 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);
5193 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);
5194 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);
5195 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);
5197 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5199 /* WARNING: The following things are taken from d3d7 and were not yet checked
5200 * against d3d8 or d3d9!
5203 /* Clipping conditions: From
5204 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5206 * A vertex is clipped if it does not match the following requirements
5207 * -rhw < x <= rhw
5208 * -rhw < y <= rhw
5209 * 0 < z <= rhw
5210 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5212 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5213 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5217 if( doClip == FALSE ||
5218 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5219 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5220 ( rhw > eps ) ) ) {
5222 /* "Normal" viewport transformation (not clipped)
5223 * 1) The values are divided by rhw
5224 * 2) The y axis is negative, so multiply it with -1
5225 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5226 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5227 * 4) Multiply x with Width/2 and add Width/2
5228 * 5) The same for the height
5229 * 6) Add the viewpoint X and Y to the 2D coordinates and
5230 * The minimum Z value to z
5231 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5233 * Well, basically it's simply a linear transformation into viewport
5234 * coordinates
5237 x /= rhw;
5238 y /= rhw;
5239 z /= rhw;
5241 y *= -1;
5243 x *= vp.Width / 2;
5244 y *= vp.Height / 2;
5245 z *= vp.MaxZ - vp.MinZ;
5247 x += vp.Width / 2 + vp.X;
5248 y += vp.Height / 2 + vp.Y;
5249 z += vp.MinZ;
5251 rhw = 1 / rhw;
5252 } else {
5253 /* That vertex got clipped
5254 * Contrary to OpenGL it is not dropped completely, it just
5255 * undergoes a different calculation.
5257 TRACE("Vertex got clipped\n");
5258 x += rhw;
5259 y += rhw;
5261 x /= 2;
5262 y /= 2;
5264 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5265 * outside of the main vertex buffer memory. That needs some more
5266 * investigation...
5270 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5273 ( (float *) dest_ptr)[0] = x;
5274 ( (float *) dest_ptr)[1] = y;
5275 ( (float *) dest_ptr)[2] = z;
5276 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5278 dest_ptr += 3 * sizeof(float);
5280 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5281 dest_ptr += sizeof(float);
5284 if(dest_conv) {
5285 float w = 1 / rhw;
5286 ( (float *) dest_conv)[0] = x * w;
5287 ( (float *) dest_conv)[1] = y * w;
5288 ( (float *) dest_conv)[2] = z * w;
5289 ( (float *) dest_conv)[3] = w;
5291 dest_conv += 3 * sizeof(float);
5293 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5294 dest_conv += sizeof(float);
5298 if (DestFVF & D3DFVF_PSIZE) {
5299 dest_ptr += sizeof(DWORD);
5300 if(dest_conv) dest_conv += sizeof(DWORD);
5302 if (DestFVF & D3DFVF_NORMAL) {
5303 float *normal =
5304 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5305 /* AFAIK this should go into the lighting information */
5306 FIXME("Didn't expect the destination to have a normal\n");
5307 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5308 if(dest_conv) {
5309 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5313 if (DestFVF & D3DFVF_DIFFUSE) {
5314 DWORD *color_d =
5315 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5316 if(!color_d) {
5317 static BOOL warned = FALSE;
5319 if(warned == FALSE) {
5320 ERR("No diffuse color in source, but destination has one\n");
5321 warned = TRUE;
5324 *( (DWORD *) dest_ptr) = 0xffffffff;
5325 dest_ptr += sizeof(DWORD);
5327 if(dest_conv) {
5328 *( (DWORD *) dest_conv) = 0xffffffff;
5329 dest_conv += sizeof(DWORD);
5332 else {
5333 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5334 if(dest_conv) {
5335 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5336 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5337 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5338 dest_conv += sizeof(DWORD);
5343 if (DestFVF & D3DFVF_SPECULAR) {
5344 /* What's the color value in the feedback buffer? */
5345 DWORD *color_s =
5346 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5347 if(!color_s) {
5348 static BOOL warned = FALSE;
5350 if(warned == FALSE) {
5351 ERR("No specular color in source, but destination has one\n");
5352 warned = TRUE;
5355 *( (DWORD *) dest_ptr) = 0xFF000000;
5356 dest_ptr += sizeof(DWORD);
5358 if(dest_conv) {
5359 *( (DWORD *) dest_conv) = 0xFF000000;
5360 dest_conv += sizeof(DWORD);
5363 else {
5364 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5365 if(dest_conv) {
5366 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5367 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5368 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5369 dest_conv += sizeof(DWORD);
5374 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5375 float *tex_coord =
5376 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5377 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5378 if(!tex_coord) {
5379 ERR("No source texture, but destination requests one\n");
5380 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5381 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5383 else {
5384 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5385 if(dest_conv) {
5386 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5392 if(dest_conv) {
5393 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5394 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5397 LEAVE_GL();
5399 return WINED3D_OK;
5401 #undef copy_and_next
5403 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5405 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5406 WineDirect3DVertexStridedData strided;
5407 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5409 if (!SrcImpl) {
5410 WARN("NULL source vertex buffer\n");
5411 return WINED3DERR_INVALIDCALL;
5413 /* We don't need the source vbo because this buffer is only used as
5414 * a source for ProcessVertices. Avoid wasting resources by converting the
5415 * buffer and loading the VBO
5417 if(SrcImpl->vbo) {
5418 TRACE("Releaseing the source vbo, it won't be needed\n");
5420 if(!SrcImpl->resource.allocatedMemory) {
5421 /* Rescue the data from the buffer */
5422 void *src;
5423 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5424 if(!SrcImpl->resource.allocatedMemory) {
5425 ERR("Out of memory\n");
5426 return E_OUTOFMEMORY;
5429 ENTER_GL();
5430 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5431 checkGLcall("glBindBufferARB");
5433 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5434 if(src) {
5435 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5438 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5439 checkGLcall("glUnmapBufferARB");
5440 } else {
5441 ENTER_GL();
5444 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5445 checkGLcall("glBindBufferARB");
5446 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5447 checkGLcall("glDeleteBuffersARB");
5448 LEAVE_GL();
5450 SrcImpl->vbo = 0;
5453 memset(&strided, 0, sizeof(strided));
5454 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5456 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5459 /*****
5460 * Apply / Get / Set Texture Stage States
5461 * TODO: Verify against dx9 definitions
5462 *****/
5464 /* 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 */
5465 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5467 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5468 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5470 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5472 /* Check that the stage is within limits */
5473 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5474 TRACE("Attempt to access invalid texture rejected\n");
5475 return;
5478 ENTER_GL();
5480 switch (Type) {
5481 case WINED3DTSS_ALPHAOP :
5482 case WINED3DTSS_COLOROP :
5483 /* nothing to do as moved to drawprim for now */
5484 break;
5485 case WINED3DTSS_ADDRESSW :
5486 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5487 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5488 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5490 } else {
5491 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5492 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5493 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5494 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5496 #endif
5497 case WINED3DTSS_TEXCOORDINDEX :
5499 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5501 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5502 one flag, you can still specify an index value, which the system uses to
5503 determine the texture wrapping mode.
5504 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5505 means use the vertex position (camera-space) as the input texture coordinates
5506 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5507 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5508 to the TEXCOORDINDEX value */
5511 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5513 switch (Value & 0xFFFF0000) {
5514 case D3DTSS_TCI_PASSTHRU:
5515 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5516 glDisable(GL_TEXTURE_GEN_S);
5517 glDisable(GL_TEXTURE_GEN_T);
5518 glDisable(GL_TEXTURE_GEN_R);
5519 glDisable(GL_TEXTURE_GEN_Q);
5520 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5521 break;
5523 case D3DTSS_TCI_CAMERASPACEPOSITION:
5524 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5525 as the input texture coordinates for this stage's texture transformation. This
5526 equates roughly to EYE_LINEAR */
5528 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5529 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5530 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5531 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5532 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5534 glMatrixMode(GL_MODELVIEW);
5535 glPushMatrix();
5536 glLoadIdentity();
5537 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5538 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5539 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5540 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5541 glPopMatrix();
5543 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5544 glEnable(GL_TEXTURE_GEN_S);
5545 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5546 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5547 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5548 glEnable(GL_TEXTURE_GEN_T);
5549 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5550 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5551 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5552 glEnable(GL_TEXTURE_GEN_R);
5553 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5554 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5555 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5557 break;
5559 case D3DTSS_TCI_CAMERASPACENORMAL:
5561 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5562 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5563 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5564 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5565 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5566 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5568 glMatrixMode(GL_MODELVIEW);
5569 glPushMatrix();
5570 glLoadIdentity();
5571 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5572 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5573 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5574 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5575 glPopMatrix();
5577 glEnable(GL_TEXTURE_GEN_S);
5578 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5579 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5580 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5581 glEnable(GL_TEXTURE_GEN_T);
5582 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5583 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5584 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5585 glEnable(GL_TEXTURE_GEN_R);
5586 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5587 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5588 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5591 break;
5593 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5595 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5596 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5597 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5598 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5599 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5600 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5602 glMatrixMode(GL_MODELVIEW);
5603 glPushMatrix();
5604 glLoadIdentity();
5605 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5606 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5607 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5608 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5609 glPopMatrix();
5611 glEnable(GL_TEXTURE_GEN_S);
5612 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5613 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5614 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5615 glEnable(GL_TEXTURE_GEN_T);
5616 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5617 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5618 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5619 glEnable(GL_TEXTURE_GEN_R);
5620 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5621 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5622 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5625 break;
5627 /* Unhandled types: */
5628 default:
5629 /* Todo: */
5630 /* ? disable GL_TEXTURE_GEN_n ? */
5631 glDisable(GL_TEXTURE_GEN_S);
5632 glDisable(GL_TEXTURE_GEN_T);
5633 glDisable(GL_TEXTURE_GEN_R);
5634 glDisable(GL_TEXTURE_GEN_Q);
5635 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5636 break;
5639 break;
5641 /* Unhandled */
5642 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5643 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);
5644 break;
5646 case WINED3DTSS_BUMPENVMAT00 :
5647 case WINED3DTSS_BUMPENVMAT01 :
5648 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5649 break;
5650 case WINED3DTSS_BUMPENVMAT10 :
5651 case WINED3DTSS_BUMPENVMAT11 :
5652 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5653 break;
5655 case WINED3DTSS_BUMPENVLSCALE :
5656 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5657 break;
5659 case WINED3DTSS_BUMPENVLOFFSET :
5660 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5661 break;
5663 case WINED3DTSS_RESULTARG :
5664 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5665 break;
5667 default:
5668 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5669 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5672 LEAVE_GL();
5674 return;
5677 /*****
5678 * Get / Set Texture Stage States
5679 * TODO: Verify against dx9 definitions
5680 *****/
5681 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5686 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5688 /* Reject invalid texture units */
5689 if (Stage >= GL_LIMITS(texture_stages)) {
5690 TRACE("Attempt to access invalid texture rejected\n");
5691 return WINED3DERR_INVALIDCALL;
5694 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5695 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5696 This->updateStateBlock->textureState[Stage][Type] = Value;
5698 return WINED3D_OK;
5701 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5704 *pValue = This->updateStateBlock->textureState[Stage][Type];
5705 return WINED3D_OK;
5708 /*****
5709 * Get / Set Texture
5710 *****/
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5714 IWineD3DBaseTexture *oldTexture;
5716 oldTexture = This->updateStateBlock->textures[Stage];
5717 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5719 #if 0 /* TODO: check so vertex textures */
5720 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5721 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5722 return WINED3D_OK;
5724 #endif
5726 /* Reject invalid texture units */
5727 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5728 WARN("Attempt to access invalid texture rejected\n");
5729 return WINED3DERR_INVALIDCALL;
5732 if(pTexture != NULL) {
5733 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5735 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5736 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5737 return WINED3DERR_INVALIDCALL;
5741 oldTexture = This->updateStateBlock->textures[Stage];
5742 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5743 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5745 This->updateStateBlock->set.textures[Stage] = TRUE;
5746 This->updateStateBlock->changed.textures[Stage] = TRUE;
5747 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5748 This->updateStateBlock->textures[Stage] = pTexture;
5750 /* Handle recording of state blocks */
5751 if (This->isRecordingState) {
5752 TRACE("Recording... not performing anything\n");
5753 return WINED3D_OK;
5756 /** NOTE: MSDN says that setTexture increases the reference count,
5757 * and the the application nust set the texture back to null (or have a leaky application),
5758 * This means we should pass the refcount up to the parent
5759 *******************************/
5760 if (NULL != This->updateStateBlock->textures[Stage]) {
5761 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5764 if (NULL != oldTexture) {
5765 IWineD3DBaseTexture_Release(oldTexture);
5768 /* Reset color keying */
5769 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5770 BOOL enable_ckey = FALSE;
5772 if(pTexture) {
5773 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5774 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5777 if(enable_ckey) {
5778 glAlphaFunc(GL_NOTEQUAL, 0.0);
5779 checkGLcall("glAlphaFunc");
5783 return WINED3D_OK;
5786 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5788 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5790 /* Reject invalid texture units */
5791 if (Stage >= GL_LIMITS(sampler_stages)) {
5792 TRACE("Attempt to access invalid texture rejected\n");
5793 return WINED3DERR_INVALIDCALL;
5795 *ppTexture=This->updateStateBlock->textures[Stage];
5796 if (*ppTexture)
5797 IWineD3DBaseTexture_AddRef(*ppTexture);
5798 else
5799 return WINED3DERR_INVALIDCALL;
5800 return WINED3D_OK;
5803 /*****
5804 * Get Back Buffer
5805 *****/
5806 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5807 IWineD3DSurface **ppBackBuffer) {
5808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 IWineD3DSwapChain *swapChain;
5810 HRESULT hr;
5812 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5814 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5815 if (hr == WINED3D_OK) {
5816 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5817 IWineD3DSwapChain_Release(swapChain);
5818 } else {
5819 *ppBackBuffer = NULL;
5821 return hr;
5824 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5826 WARN("(%p) : stub, calling idirect3d for now\n", This);
5827 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5830 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 IWineD3DSwapChain *swapChain;
5833 HRESULT hr;
5835 if(iSwapChain > 0) {
5836 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5837 if (hr == WINED3D_OK) {
5838 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5839 IWineD3DSwapChain_Release(swapChain);
5840 } else {
5841 FIXME("(%p) Error getting display mode\n", This);
5843 } else {
5844 /* Don't read the real display mode,
5845 but return the stored mode instead. X11 can't change the color
5846 depth, and some apps are pretty angry if they SetDisplayMode from
5847 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5849 Also don't relay to the swapchain because with ddraw it's possible
5850 that there isn't a swapchain at all */
5851 pMode->Width = This->ddraw_width;
5852 pMode->Height = This->ddraw_height;
5853 pMode->Format = This->ddraw_format;
5854 pMode->RefreshRate = 0;
5855 hr = WINED3D_OK;
5858 return hr;
5861 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 TRACE("(%p)->(%p)\n", This, hWnd);
5865 This->ddraw_window = hWnd;
5866 return WINED3D_OK;
5869 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5871 TRACE("(%p)->(%p)\n", This, hWnd);
5873 *hWnd = This->ddraw_window;
5874 return WINED3D_OK;
5877 /*****
5878 * Stateblock related functions
5879 *****/
5881 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 IWineD3DStateBlockImpl *object;
5884 HRESULT temp_result;
5886 TRACE("(%p)", This);
5888 if (This->isRecordingState) {
5889 return WINED3DERR_INVALIDCALL;
5892 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5893 if (NULL == object ) {
5894 FIXME("(%p)Error allocating memory for stateblock\n", This);
5895 return E_OUTOFMEMORY;
5897 TRACE("(%p) created object %p\n", This, object);
5898 object->wineD3DDevice= This;
5899 /** FIXME: object->parent = parent; **/
5900 object->parent = NULL;
5901 object->blockType = WINED3DSBT_ALL;
5902 object->ref = 1;
5903 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5905 temp_result = allocate_shader_constants(object);
5906 if (WINED3D_OK != temp_result)
5907 return temp_result;
5909 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5910 This->updateStateBlock = object;
5911 This->isRecordingState = TRUE;
5913 TRACE("(%p) recording stateblock %p\n",This , object);
5914 return WINED3D_OK;
5917 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 if (!This->isRecordingState) {
5921 FIXME("(%p) not recording! returning error\n", This);
5922 *ppStateBlock = NULL;
5923 return WINED3DERR_INVALIDCALL;
5926 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5927 This->isRecordingState = FALSE;
5928 This->updateStateBlock = This->stateBlock;
5929 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5930 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5931 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5932 return WINED3D_OK;
5935 /*****
5936 * Scene related functions
5937 *****/
5938 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5939 /* At the moment we have no need for any functionality at the beginning
5940 of a scene */
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5942 TRACE("(%p) : stub\n", This);
5943 return WINED3D_OK;
5946 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5948 TRACE("(%p)\n", This);
5949 ENTER_GL();
5950 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5951 glFlush();
5952 checkGLcall("glFlush");
5954 TRACE("End Scene\n");
5955 if(This->renderTarget != NULL) {
5957 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5958 IUnknown *targetContainer = NULL;
5959 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5960 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5961 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5962 /** always dirtify for now. we must find a better way to see that surface have been modified
5963 (Modifications should will only occur via draw-primitive, but we do need better locking
5964 switching to render-to-texture should remove the overhead though.
5966 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5967 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5968 IWineD3DSurface_PreLoad(This->renderTarget);
5969 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5970 IUnknown_Release(targetContainer);
5973 This->sceneEnded = TRUE;
5974 LEAVE_GL();
5975 return WINED3D_OK;
5978 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5979 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5980 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5982 IWineD3DSwapChain *swapChain = NULL;
5983 int i;
5984 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5986 TRACE("(%p) Presenting the frame\n", This);
5988 for(i = 0 ; i < swapchains ; i ++) {
5990 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5991 TRACE("presentinng chain %d, %p\n", i, swapChain);
5992 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5993 IWineD3DSwapChain_Release(swapChain);
5996 return WINED3D_OK;
5999 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
6000 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
6001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6003 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
6004 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
6005 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6006 GLbitfield glMask = 0;
6007 GLboolean old_ztest;
6008 GLfloat old_z_clear_value;
6009 GLint old_stencil_clear_value;
6010 GLfloat old_color_clear_value[4];
6011 unsigned int i;
6012 CONST D3DRECT* curRect;
6014 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
6015 Count, pRects, Flags, Z, Stencil);
6017 ENTER_GL();
6019 glEnable(GL_SCISSOR_TEST);
6020 checkGLcall("glEnable GL_SCISSOR_TEST");
6022 if (Count > 0 && pRects) {
6023 curRect = pRects;
6024 } else {
6025 curRect = NULL;
6028 /* Only set the values up once, as they are not changing */
6029 if (Flags & D3DCLEAR_STENCIL) {
6030 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6031 glClearStencil(Stencil);
6032 checkGLcall("glClearStencil");
6033 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6034 glStencilMask(0xFFFFFFFF);
6037 if (Flags & D3DCLEAR_ZBUFFER) {
6038 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6039 glDepthMask(GL_TRUE);
6040 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6041 glClearDepth(Z);
6042 checkGLcall("glClearDepth");
6043 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6046 if (Flags & D3DCLEAR_TARGET) {
6047 TRACE("Clearing screen with glClear to color %lx\n", Color);
6048 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6049 glClearColor(D3DCOLOR_R(Color),
6050 D3DCOLOR_G(Color),
6051 D3DCOLOR_B(Color),
6052 D3DCOLOR_A(Color));
6053 checkGLcall("glClearColor");
6055 /* Clear ALL colors! */
6056 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6057 glMask = glMask | GL_COLOR_BUFFER_BIT;
6060 /* Now process each rect in turn */
6061 for (i = 0; i < Count || i == 0; i++) {
6063 if (curRect) {
6064 /* Note gl uses lower left, width/height */
6065 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
6066 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6067 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6068 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6069 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6070 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6071 checkGLcall("glScissor");
6072 } else {
6073 glScissor(This->stateBlock->viewport.X,
6074 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6075 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6076 This->stateBlock->viewport.Width,
6077 This->stateBlock->viewport.Height);
6078 checkGLcall("glScissor");
6081 /* Clear the selected rectangle (or full screen) */
6082 glClear(glMask);
6083 checkGLcall("glClear");
6085 /* Step to the next rectangle */
6086 if (curRect) curRect = curRect + sizeof(D3DRECT);
6089 /* Restore the old values (why..?) */
6090 if (Flags & D3DCLEAR_STENCIL) {
6091 glClearStencil(old_stencil_clear_value);
6092 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6094 if (Flags & D3DCLEAR_ZBUFFER) {
6095 glDepthMask(old_ztest);
6096 glClearDepth(old_z_clear_value);
6098 if (Flags & D3DCLEAR_TARGET) {
6099 glClearColor(old_color_clear_value[0],
6100 old_color_clear_value[1],
6101 old_color_clear_value[2],
6102 old_color_clear_value[3]);
6103 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6104 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6105 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6106 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6109 glDisable(GL_SCISSOR_TEST);
6110 checkGLcall("glDisable");
6111 LEAVE_GL();
6113 return WINED3D_OK;
6116 /*****
6117 * Drawing functions
6118 *****/
6119 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6120 UINT PrimitiveCount) {
6122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6123 This->stateBlock->streamIsUP = FALSE;
6125 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6126 debug_d3dprimitivetype(PrimitiveType),
6127 StartVertex, PrimitiveCount);
6128 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6129 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6132 return WINED3D_OK;
6135 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6136 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6137 D3DPRIMITIVETYPE PrimitiveType,
6138 INT baseVIndex, UINT minIndex,
6139 UINT NumVertices, UINT startIndex, UINT primCount) {
6141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6142 UINT idxStride = 2;
6143 IWineD3DIndexBuffer *pIB;
6144 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6146 pIB = This->stateBlock->pIndexData;
6147 This->stateBlock->streamIsUP = FALSE;
6149 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6150 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6151 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6153 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6154 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6155 idxStride = 2;
6156 } else {
6157 idxStride = 4;
6160 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6161 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6163 return WINED3D_OK;
6166 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6167 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6168 UINT VertexStreamZeroStride) {
6169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6171 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6172 debug_d3dprimitivetype(PrimitiveType),
6173 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6175 /* release the stream source */
6176 if (This->stateBlock->streamSource[0] != NULL) {
6177 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6180 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6181 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6182 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6183 This->stateBlock->streamIsUP = TRUE;
6185 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6186 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6188 /* MSDN specifies stream zero settings must be set to NULL */
6189 This->stateBlock->streamStride[0] = 0;
6190 This->stateBlock->streamSource[0] = NULL;
6192 /*stream zero settings set to null at end, as per the msdn */
6193 return WINED3D_OK;
6196 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6197 UINT MinVertexIndex, UINT NumVertices,
6198 UINT PrimitiveCount, CONST void* pIndexData,
6199 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6200 UINT VertexStreamZeroStride) {
6201 int idxStride;
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6204 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6205 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6206 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6207 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6209 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6210 idxStride = 2;
6211 } else {
6212 idxStride = 4;
6215 /* release the stream and index data */
6216 if (This->stateBlock->streamSource[0] != NULL) {
6217 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6219 if (This->stateBlock->pIndexData) {
6220 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6223 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6224 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6225 This->stateBlock->streamIsUP = TRUE;
6226 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6228 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6230 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6231 This->stateBlock->streamSource[0] = NULL;
6232 This->stateBlock->streamStride[0] = 0;
6233 This->stateBlock->pIndexData = NULL;
6235 return WINED3D_OK;
6238 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6240 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6241 return WINED3D_OK;
6243 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6244 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6246 HRESULT hr = WINED3D_OK;
6247 WINED3DRESOURCETYPE sourceType;
6248 WINED3DRESOURCETYPE destinationType;
6249 int i ,levels;
6251 /* TODO: think about moving the code into IWineD3DBaseTexture */
6253 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6255 /* verify that the source and destination textures aren't NULL */
6256 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6257 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6258 This, pSourceTexture, pDestinationTexture);
6259 hr = WINED3DERR_INVALIDCALL;
6262 if (pSourceTexture == pDestinationTexture) {
6263 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6264 This, pSourceTexture, pDestinationTexture);
6265 hr = WINED3DERR_INVALIDCALL;
6267 /* Verify that the source and destination textures are the same type */
6268 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6269 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6271 if (sourceType != destinationType) {
6272 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6273 This);
6274 hr = WINED3DERR_INVALIDCALL;
6277 /* check that both textures have the identical numbers of levels */
6278 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6279 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6280 hr = WINED3DERR_INVALIDCALL;
6283 if (WINED3D_OK == hr) {
6285 /* Make sure that the destination texture is loaded */
6286 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6288 /* Update every surface level of the texture */
6289 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6291 switch (sourceType) {
6292 case WINED3DRTYPE_TEXTURE:
6294 IWineD3DSurface *srcSurface;
6295 IWineD3DSurface *destSurface;
6297 for (i = 0 ; i < levels ; ++i) {
6298 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6299 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6300 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6301 IWineD3DSurface_Release(srcSurface);
6302 IWineD3DSurface_Release(destSurface);
6303 if (WINED3D_OK != hr) {
6304 WARN("(%p) : Call to update surface failed\n", This);
6305 return hr;
6309 break;
6310 case WINED3DRTYPE_CUBETEXTURE:
6312 IWineD3DSurface *srcSurface;
6313 IWineD3DSurface *destSurface;
6314 WINED3DCUBEMAP_FACES faceType;
6316 for (i = 0 ; i < levels ; ++i) {
6317 /* Update each cube face */
6318 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6319 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6320 if (WINED3D_OK != hr) {
6321 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6322 } else {
6323 TRACE("Got srcSurface %p\n", srcSurface);
6325 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6326 if (WINED3D_OK != hr) {
6327 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6328 } else {
6329 TRACE("Got desrSurface %p\n", destSurface);
6331 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6332 IWineD3DSurface_Release(srcSurface);
6333 IWineD3DSurface_Release(destSurface);
6334 if (WINED3D_OK != hr) {
6335 WARN("(%p) : Call to update surface failed\n", This);
6336 return hr;
6341 break;
6342 #if 0 /* TODO: Add support for volume textures */
6343 case WINED3DRTYPE_VOLUMETEXTURE:
6345 IWineD3DVolume srcVolume = NULL;
6346 IWineD3DSurface destVolume = NULL;
6348 for (i = 0 ; i < levels ; ++i) {
6349 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6350 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6351 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6352 IWineD3DVolume_Release(srcSurface);
6353 IWineD3DVolume_Release(destSurface);
6354 if (WINED3D_OK != hr) {
6355 WARN("(%p) : Call to update volume failed\n", This);
6356 return hr;
6360 break;
6361 #endif
6362 default:
6363 FIXME("(%p) : Unsupported source and destination type\n", This);
6364 hr = WINED3DERR_INVALIDCALL;
6368 return hr;
6371 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6372 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6373 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6376 TRACE("(%p) : stub\n", This);
6377 return WINED3D_OK;
6379 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6381 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6382 * NOTE It may be best to move the code into surface to occomplish this
6383 ****************************************/
6385 WINED3DSURFACE_DESC surfaceDesc;
6386 unsigned int surfaceWidth, surfaceHeight;
6387 glDescriptor *targetGlDescription = NULL;
6388 glDescriptor *surfaceGlDescription = NULL;
6389 IWineD3DSwapChainImpl *container = NULL;
6391 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6392 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6393 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6395 surfaceDesc.Width = &surfaceWidth;
6396 surfaceDesc.Height = &surfaceHeight;
6397 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6398 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6400 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6401 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6402 ENTER_GL();
6403 /* TODO: opengl Context switching for swapchains etc... */
6404 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6405 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6406 glReadBuffer(GL_BACK);
6407 vcheckGLcall("glReadBuffer(GL_BACK)");
6408 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6409 glReadBuffer(GL_FRONT);
6410 vcheckGLcall("glReadBuffer(GL_FRONT)");
6411 } else if (pRenderTarget == This->depthStencilBuffer) {
6412 FIXME("Reading of depthstencil not yet supported\n");
6415 glReadPixels(surfaceGlDescription->target,
6416 surfaceGlDescription->level,
6417 surfaceWidth,
6418 surfaceHeight,
6419 surfaceGlDescription->glFormat,
6420 surfaceGlDescription->glType,
6421 (void *)IWineD3DSurface_GetData(pSurface));
6422 vcheckGLcall("glReadPixels(...)");
6423 if(NULL != container ){
6424 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6426 } else {
6427 IWineD3DBaseTexture *container;
6428 GLenum textureDimensions = GL_TEXTURE_2D;
6430 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6431 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6432 IWineD3DBaseTexture_Release(container);
6434 /* TODO: 2D -> Cube surface coppies etc.. */
6435 if (surfaceGlDescription->target != textureDimensions) {
6436 FIXME("(%p) : Texture dimension mismatch\n", This);
6438 glEnable(textureDimensions);
6439 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6440 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6441 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6442 vcheckGLcall("glBindTexture");
6443 glGetTexImage(surfaceGlDescription->target,
6444 surfaceGlDescription->level,
6445 surfaceGlDescription->glFormat,
6446 surfaceGlDescription->glType,
6447 (void *)IWineD3DSurface_GetData(pSurface));
6448 glDisable(textureDimensions);
6449 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6452 LEAVE_GL();
6453 return WINED3D_OK;
6456 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6457 IWineD3DSwapChain *swapChain;
6458 HRESULT hr;
6459 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6460 if(hr == WINED3D_OK) {
6461 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6462 IWineD3DSwapChain_Release(swapChain);
6464 return hr;
6467 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6469 /* return a sensible default */
6470 *pNumPasses = 1;
6471 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6472 FIXME("(%p) : stub\n", This);
6473 return WINED3D_OK;
6476 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6478 int j;
6479 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6480 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6481 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6482 return WINED3DERR_INVALIDCALL;
6484 for (j = 0; j < 256; ++j) {
6485 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6486 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6487 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6488 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6490 TRACE("(%p) : returning\n", This);
6491 return WINED3D_OK;
6494 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6496 int j;
6497 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6498 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6499 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6500 return WINED3DERR_INVALIDCALL;
6502 for (j = 0; j < 256; ++j) {
6503 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6504 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6505 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6506 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6508 TRACE("(%p) : returning\n", This);
6509 return WINED3D_OK;
6512 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6514 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6515 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6516 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6517 return WINED3DERR_INVALIDCALL;
6519 /*TODO: stateblocks */
6520 This->currentPalette = PaletteNumber;
6521 TRACE("(%p) : returning\n", This);
6522 return WINED3D_OK;
6525 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6527 if (PaletteNumber == NULL) {
6528 WARN("(%p) : returning Invalid Call\n", This);
6529 return WINED3DERR_INVALIDCALL;
6531 /*TODO: stateblocks */
6532 *PaletteNumber = This->currentPalette;
6533 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6534 return WINED3D_OK;
6537 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6539 static BOOL showFixmes = TRUE;
6540 if (showFixmes) {
6541 FIXME("(%p) : stub\n", This);
6542 showFixmes = FALSE;
6545 This->softwareVertexProcessing = bSoftware;
6546 return WINED3D_OK;
6550 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6552 static BOOL showFixmes = TRUE;
6553 if (showFixmes) {
6554 FIXME("(%p) : stub\n", This);
6555 showFixmes = FALSE;
6557 return This->softwareVertexProcessing;
6561 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6563 IWineD3DSwapChain *swapChain;
6564 HRESULT hr;
6566 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6568 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6569 if(hr == WINED3D_OK){
6570 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6571 IWineD3DSwapChain_Release(swapChain);
6572 }else{
6573 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6575 return hr;
6579 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6581 static BOOL showfixmes = TRUE;
6582 if(nSegments != 0.0f) {
6583 if( showfixmes) {
6584 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6585 showfixmes = FALSE;
6588 return WINED3D_OK;
6591 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6593 static BOOL showfixmes = TRUE;
6594 if( showfixmes) {
6595 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6596 showfixmes = FALSE;
6598 return 0.0f;
6601 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6603 /** TODO: remove casts to IWineD3DSurfaceImpl
6604 * NOTE: move code to surface to accomplish this
6605 ****************************************/
6606 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6607 int srcWidth, srcHeight;
6608 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6609 WINED3DFORMAT destFormat, srcFormat;
6610 UINT destSize;
6611 int destLeft, destTop;
6612 WINED3DPOOL srcPool, destPool;
6613 int offset = 0;
6614 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6615 glDescriptor *glDescription = NULL;
6616 GLenum textureDimensions = GL_TEXTURE_2D;
6617 IWineD3DBaseTexture *baseTexture;
6619 WINED3DSURFACE_DESC winedesc;
6621 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6622 memset(&winedesc, 0, sizeof(winedesc));
6623 winedesc.Width = &srcSurfaceWidth;
6624 winedesc.Height = &srcSurfaceHeight;
6625 winedesc.Pool = &srcPool;
6626 winedesc.Format = &srcFormat;
6628 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6630 winedesc.Width = &destSurfaceWidth;
6631 winedesc.Height = &destSurfaceHeight;
6632 winedesc.Pool = &destPool;
6633 winedesc.Format = &destFormat;
6634 winedesc.Size = &destSize;
6636 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6638 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6639 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6640 return WINED3DERR_INVALIDCALL;
6643 if (destFormat == WINED3DFMT_UNKNOWN) {
6644 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6645 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6647 /* Get the update surface description */
6648 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6651 /* Make sure the surface is loaded and up to date */
6652 IWineD3DSurface_PreLoad(pDestinationSurface);
6654 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6656 ENTER_GL();
6658 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6659 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6660 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6661 destLeft = pDestPoint ? pDestPoint->x : 0;
6662 destTop = pDestPoint ? pDestPoint->y : 0;
6665 /* This function doesn't support compressed textures
6666 the pitch is just bytesPerPixel * width */
6667 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6668 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6669 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6670 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6672 /* TODO DXT formats */
6674 if(pSourceRect != NULL && pSourceRect->top != 0){
6675 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6677 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6678 ,This
6679 ,glDescription->level
6680 ,destLeft
6681 ,destTop
6682 ,srcWidth
6683 ,srcHeight
6684 ,glDescription->glFormat
6685 ,glDescription->glType
6686 ,IWineD3DSurface_GetData(pSourceSurface)
6689 /* Sanity check */
6690 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6692 /* need to lock the surface to get the data */
6693 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6696 /* TODO: Cube and volume support */
6697 if(rowoffset != 0){
6698 /* not a whole row so we have to do it a line at a time */
6699 int j;
6701 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6702 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6704 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6706 glTexSubImage2D(glDescription->target
6707 ,glDescription->level
6708 ,destLeft
6710 ,srcWidth
6712 ,glDescription->glFormat
6713 ,glDescription->glType
6714 ,data /* could be quicker using */
6716 data += rowoffset;
6719 } else { /* Full width, so just write out the whole texture */
6721 if (WINED3DFMT_DXT1 == destFormat ||
6722 WINED3DFMT_DXT2 == destFormat ||
6723 WINED3DFMT_DXT3 == destFormat ||
6724 WINED3DFMT_DXT4 == destFormat ||
6725 WINED3DFMT_DXT5 == destFormat) {
6726 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6727 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6728 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6729 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6730 } if (destFormat != srcFormat) {
6731 FIXME("Updating mixed format compressed texture is not curretly support\n");
6732 } else {
6733 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6734 glDescription->level,
6735 glDescription->glFormatInternal,
6736 srcWidth,
6737 srcHeight,
6739 destSize,
6740 IWineD3DSurface_GetData(pSourceSurface));
6742 } else {
6743 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6747 } else {
6748 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6750 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6751 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6752 data returned by GetData non-power2 width/height with hardware non-power2
6753 pow2Width/height are set to surface width height, repacking isn't needed so it
6754 doesn't matter which function gets called. */
6755 glTexSubImage2D(glDescription->target
6756 ,glDescription->level
6757 ,destLeft
6758 ,destTop
6759 ,srcWidth
6760 ,srcHeight
6761 ,glDescription->glFormat
6762 ,glDescription->glType
6763 ,IWineD3DSurface_GetData(pSourceSurface)
6765 } else {
6767 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6768 glTexSubImage2D(glDescription->target
6769 ,glDescription->level
6770 ,destLeft
6771 ,destTop
6772 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6773 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6774 ,glDescription->glFormat
6775 ,glDescription->glType
6776 ,IWineD3DSurface_GetData(pSourceSurface)
6782 checkGLcall("glTexSubImage2D");
6783 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6785 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6786 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6787 * surface bigger than it needs to be hmm.. */
6788 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6789 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6790 IWineD3DBaseTexture_Release(baseTexture);
6793 glDisable(textureDimensions); /* This needs to be managed better.... */
6794 LEAVE_GL();
6796 return WINED3D_OK;
6799 /* Used by DirectX 8 */
6800 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6801 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6802 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6805 HRESULT hr = WINED3D_OK;
6806 WINED3DFORMAT srcFormat, destFormat;
6807 UINT srcWidth, destWidth;
6808 UINT srcHeight, destHeight;
6809 UINT srcSize;
6810 WINED3DSURFACE_DESC winedesc;
6812 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6813 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6816 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6817 memset(&winedesc, 0, sizeof(winedesc));
6819 winedesc.Format = &srcFormat;
6820 winedesc.Width = &srcWidth;
6821 winedesc.Height = &srcHeight;
6822 winedesc.Size = &srcSize;
6823 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6825 winedesc.Format = &destFormat;
6826 winedesc.Width = &destWidth;
6827 winedesc.Height = &destHeight;
6828 winedesc.Size = NULL;
6829 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6831 /* Check that the source and destination formats match */
6832 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6833 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6834 return WINED3DERR_INVALIDCALL;
6835 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6836 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6837 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6838 destFormat = srcFormat;
6841 /* Quick if complete copy ... */
6842 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6844 if (srcWidth == destWidth && srcHeight == destHeight) {
6845 WINED3DLOCKED_RECT lrSrc;
6846 WINED3DLOCKED_RECT lrDst;
6847 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6848 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6849 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6851 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6853 IWineD3DSurface_UnlockRect(pSourceSurface);
6854 IWineD3DSurface_UnlockRect(pDestinationSurface);
6855 TRACE("Unlocked src and dst\n");
6857 } else {
6859 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6860 hr = WINED3DERR_INVALIDCALL;
6863 } else {
6865 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6867 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6868 unsigned int i;
6870 /* Copy rect by rect */
6871 for (i = 0; i < cRects; ++i) {
6872 CONST RECT* r = &pSourceRectsArray[i];
6873 CONST POINT* p = &pDestPointsArray[i];
6874 int copyperline;
6875 int j;
6876 WINED3DLOCKED_RECT lrSrc;
6877 WINED3DLOCKED_RECT lrDst;
6878 RECT dest_rect;
6880 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6881 if (srcFormat == WINED3DFMT_DXT1) {
6882 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6883 } else {
6884 copyperline = ((r->right - r->left) * bytesPerPixel);
6887 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6888 dest_rect.left = p->x;
6889 dest_rect.top = p->y;
6890 dest_rect.right = p->x + (r->right - r->left);
6891 dest_rect.bottom= p->y + (r->bottom - r->top);
6892 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6893 TRACE("Locked src and dst\n");
6895 /* Find where to start */
6896 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6897 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6899 IWineD3DSurface_UnlockRect(pSourceSurface);
6900 IWineD3DSurface_UnlockRect(pDestinationSurface);
6901 TRACE("Unlocked src and dst\n");
6903 } else {
6904 unsigned int i;
6905 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6906 int copyperline;
6907 int j;
6908 WINED3DLOCKED_RECT lrSrc;
6909 WINED3DLOCKED_RECT lrDst;
6910 RECT dest_rect;
6912 for(i=0; i < cRects; i++) {
6913 CONST RECT* r = &pSourceRectsArray[i];
6915 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6916 if (srcFormat == WINED3DFMT_DXT1) {
6917 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6918 } else {
6919 copyperline = ((r->right - r->left) * bytesPerPixel);
6921 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6922 dest_rect.left = 0;
6923 dest_rect.top = 0;
6924 dest_rect.right = r->right - r->left;
6925 dest_rect.bottom= r->bottom - r->top;
6926 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6927 TRACE("Locked src and dst\n");
6928 /* Find where to start */
6929 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6930 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6932 IWineD3DSurface_UnlockRect(pSourceSurface);
6933 IWineD3DSurface_UnlockRect(pDestinationSurface);
6934 TRACE("Unlocked src and dst\n");
6939 return hr;
6942 /* Implementation details at http://developer.nvidia.com/attach/6494
6944 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6945 hmm.. no longer supported use
6946 OpenGL evaluators or tessellate surfaces within your application.
6949 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6950 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6952 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6953 FIXME("(%p) : Stub\n", This);
6954 return WINED3D_OK;
6958 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6959 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6961 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6962 FIXME("(%p) : Stub\n", This);
6963 return WINED3D_OK;
6966 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6968 TRACE("(%p) Handle(%d)\n", This, Handle);
6969 FIXME("(%p) : Stub\n", This);
6970 return WINED3D_OK;
6973 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6975 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6976 DDBLTFX BltFx;
6977 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6979 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6980 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6981 return WINED3DERR_INVALIDCALL;
6984 /* Just forward this to the DirectDraw blitting engine */
6985 memset(&BltFx, 0, sizeof(BltFx));
6986 BltFx.dwSize = sizeof(BltFx);
6987 BltFx.u5.dwFillColor = color;
6988 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6991 /* rendertarget and deptth stencil functions */
6992 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6995 /* FIXME: Implelent RenderTargetIndex >0 */
6996 if(RenderTargetIndex > 0)
6997 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6999 *ppRenderTarget = This->renderTarget;
7000 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
7001 /* Note inc ref on returned surface */
7002 if(*ppRenderTarget != NULL)
7003 IWineD3DSurface_AddRef(*ppRenderTarget);
7004 return WINED3D_OK;
7007 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7009 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
7010 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
7011 IWineD3DSwapChainImpl *Swapchain;
7012 HRESULT hr;
7014 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
7016 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7017 if(hr != WINED3D_OK) {
7018 ERR("Can't get the swapchain\n");
7019 return hr;
7022 /* Make sure to release the swapchain */
7023 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7025 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7026 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7027 return WINED3DERR_INVALIDCALL;
7029 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7030 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7031 return WINED3DERR_INVALIDCALL;
7034 if(Swapchain->frontBuffer != Front) {
7035 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7037 if(Swapchain->frontBuffer)
7038 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7039 Swapchain->frontBuffer = Front;
7041 if(Swapchain->frontBuffer) {
7042 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7046 if(Back && !Swapchain->backBuffer) {
7047 /* We need memory for the back buffer array - only one back buffer this way */
7048 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7049 if(!Swapchain->backBuffer) {
7050 ERR("Out of memory\n");
7051 return E_OUTOFMEMORY;
7055 if(Swapchain->backBuffer[0] != Back) {
7056 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7057 ENTER_GL();
7058 if(!Swapchain->backBuffer[0]) {
7059 /* GL was told to draw to the front buffer at creation,
7060 * undo that
7062 glDrawBuffer(GL_BACK);
7063 checkGLcall("glDrawBuffer(GL_BACK)");
7064 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7065 Swapchain->presentParms.BackBufferCount = 1;
7066 } else if (!Back) {
7067 /* That makes problems - disable for now */
7068 /* glDrawBuffer(GL_FRONT); */
7069 checkGLcall("glDrawBuffer(GL_FRONT)");
7070 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7071 Swapchain->presentParms.BackBufferCount = 0;
7073 LEAVE_GL();
7075 if(Swapchain->backBuffer[0])
7076 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7077 Swapchain->backBuffer[0] = Back;
7079 if(Swapchain->backBuffer[0]) {
7080 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7081 } else {
7082 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7087 return WINED3D_OK;
7090 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7092 *ppZStencilSurface = This->depthStencilBuffer;
7093 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7095 if(*ppZStencilSurface != NULL) {
7096 /* Note inc ref on returned surface */
7097 IWineD3DSurface_AddRef(*ppZStencilSurface);
7099 return WINED3D_OK;
7102 /* internal static helper functions */
7103 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7104 IWineD3DSurface *RenderSurface);
7106 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7108 HRESULT hr = WINED3D_OK;
7109 WINED3DVIEWPORT viewport;
7111 TRACE("(%p) Swapping rendertarget\n",This);
7112 if (RenderTargetIndex > 0) {
7113 FIXME("(%p) Render targets other than the first are not supported\n",This);
7114 RenderTargetIndex = 0;
7117 /* MSDN says that null disables the render target
7118 but a device must always be associated with a render target
7119 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7121 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7122 for more details
7124 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7125 FIXME("Trying to set render target 0 to NULL\n");
7126 return WINED3DERR_INVALIDCALL;
7128 /* TODO: replace Impl* usage with interface usage */
7129 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7130 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);
7131 return WINED3DERR_INVALIDCALL;
7133 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7134 * builds, but I think wine counts as a 'debug' build for now.
7135 ******************************/
7136 /* If we are trying to set what we already have, don't bother */
7137 if (pRenderTarget == This->renderTarget) {
7138 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7139 } else {
7140 /* Otherwise, set the render target up */
7142 if (FALSE == This->sceneEnded) {
7143 IWineD3DDevice_EndScene(iface);
7145 TRACE("clearing renderer\n");
7146 /* IWineD3DDeviceImpl_CleanRender(iface); */
7147 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7148 depending on the renter target implementation being used.
7149 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7150 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7151 stencil buffer and incure an extra memory overhead */
7152 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7155 if (SUCCEEDED(hr)) {
7156 /* Finally, reset the viewport as the MSDN states. */
7157 /* TODO: Replace impl usage */
7158 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7159 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7160 viewport.X = 0;
7161 viewport.Y = 0;
7162 viewport.MaxZ = 1.0f;
7163 viewport.MinZ = 0.0f;
7164 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7165 } else {
7166 FIXME("Unknown error setting the render target\n");
7168 This->sceneEnded = FALSE;
7169 return hr;
7172 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7174 HRESULT hr = WINED3D_OK;
7175 IWineD3DSurface *tmp;
7177 TRACE("(%p) Swapping z-buffer\n",This);
7179 if (pNewZStencil == This->stencilBufferTarget) {
7180 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7181 } else {
7182 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7183 * depending on the renter target implementation being used.
7184 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7185 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7186 * stencil buffer and incure an extra memory overhead
7187 ******************************************************/
7190 tmp = This->stencilBufferTarget;
7191 This->stencilBufferTarget = pNewZStencil;
7192 /* should we be calling the parent or the wined3d surface? */
7193 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7194 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7195 hr = WINED3D_OK;
7196 /** TODO: glEnable/glDisable on depth/stencil depending on
7197 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7198 **********************************************************/
7201 return hr;
7205 #ifdef GL_VERSION_1_3
7206 /* Internal functions not in DirectX */
7207 /** TODO: move this off to the opengl context manager
7208 *(the swapchain doesn't need to know anything about offscreen rendering!)
7209 ****************************************************/
7211 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7215 TRACE("(%p), %p\n", This, swapchain);
7217 if (swapchain->win != swapchain->drawable) {
7218 /* Set everything back the way it ws */
7219 swapchain->render_ctx = swapchain->glCtx;
7220 swapchain->drawable = swapchain->win;
7222 return WINED3D_OK;
7225 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7226 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7228 int i;
7229 unsigned int width;
7230 unsigned int height;
7231 WINED3DFORMAT format;
7232 WINED3DSURFACE_DESC surfaceDesc;
7233 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7234 surfaceDesc.Width = &width;
7235 surfaceDesc.Height = &height;
7236 surfaceDesc.Format = &format;
7237 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7238 *context = NULL;
7239 /* I need a get width/height function (and should do something with the format) */
7240 for (i = 0; i < CONTEXT_CACHE; ++i) {
7241 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7242 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7243 the pSurface can be set to 0 allowing it to be reused from cache **/
7244 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7245 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7246 *context = &This->contextCache[i];
7247 break;
7249 if (This->contextCache[i].Width == 0) {
7250 This->contextCache[i].pSurface = pSurface;
7251 This->contextCache[i].Width = width;
7252 This->contextCache[i].Height = height;
7253 *context = &This->contextCache[i];
7254 break;
7257 if (i == CONTEXT_CACHE) {
7258 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7259 glContext *dropContext = 0;
7260 for (i = 0; i < CONTEXT_CACHE; i++) {
7261 if (This->contextCache[i].usedcount < minUsage) {
7262 dropContext = &This->contextCache[i];
7263 minUsage = This->contextCache[i].usedcount;
7266 /* clean up the context (this doesn't work for ATI at the moment */
7267 #if 0
7268 glXDestroyContext(swapchain->display, dropContext->context);
7269 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7270 #endif
7271 FIXME("Leak\n");
7272 dropContext->Width = 0;
7273 dropContext->pSurface = pSurface;
7274 *context = dropContext;
7275 } else {
7276 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7277 for (i = 0; i < CONTEXT_CACHE; i++) {
7278 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7282 if (*context != NULL)
7283 return WINED3D_OK;
7284 else
7285 return E_OUTOFMEMORY;
7287 #endif
7289 /* Reapply the device stateblock */
7290 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7292 BOOL oldRecording;
7293 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7295 /* Disable recording */
7296 oldUpdateStateBlock = This->updateStateBlock;
7297 oldRecording= This->isRecordingState;
7298 This->isRecordingState = FALSE;
7299 This->updateStateBlock = This->stateBlock;
7301 /* Reapply the state block */
7302 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7304 /* Restore recording */
7305 This->isRecordingState = oldRecording;
7306 This->updateStateBlock = oldUpdateStateBlock;
7309 /* Set the device to render to a texture, or not.
7310 * This involves changing renderUpsideDown */
7312 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7314 DWORD cullMode;
7315 BOOL oldRecording;
7316 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7318 /* Disable recording */
7319 oldUpdateStateBlock = This->updateStateBlock;
7320 oldRecording= This->isRecordingState;
7321 This->isRecordingState = FALSE;
7322 This->updateStateBlock = This->stateBlock;
7324 /* Set upside-down rendering, and update the cull mode */
7325 /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
7326 This->renderUpsideDown = isTexture;
7327 This->last_was_rhw = FALSE;
7328 This->proj_valid = FALSE;
7329 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7330 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7332 /* Restore recording */
7333 This->isRecordingState = oldRecording;
7334 This->updateStateBlock = oldUpdateStateBlock;
7337 /* Returns an array of compatible FBconfig(s).
7338 * The array must be freed with XFree. Requires ENTER_GL() */
7340 static GLXFBConfig* device_find_fbconfigs(
7341 IWineD3DDeviceImpl* This,
7342 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7343 IWineD3DSurface* RenderSurface) {
7345 GLXFBConfig* cfgs = NULL;
7346 int nCfgs = 0;
7347 int attribs[256];
7348 int nAttribs = 0;
7350 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7351 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7352 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7354 /**TODO:
7355 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7356 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7359 #define PUSH1(att) attribs[nAttribs++] = (att);
7360 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7362 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7364 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7365 PUSH2(GLX_X_RENDERABLE, TRUE);
7366 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7367 TRACE("calling makeglcfg\n");
7368 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7369 PUSH1(None);
7370 TRACE("calling chooseFGConfig\n");
7371 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7372 DefaultScreen(implicitSwapchainImpl->display),
7373 attribs, &nCfgs);
7374 if (cfgs == NULL) {
7375 /* OK we didn't find the exact config, so use any reasonable match */
7376 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7377 why we failed and only show this message once! */
7378 MESSAGE("Failed to find exact match, finding alternative but you may "
7379 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7380 nAttribs = 0;
7381 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7382 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7383 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7384 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7385 TRACE("calling makeglcfg\n");
7386 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7387 PUSH1(None);
7388 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7389 DefaultScreen(implicitSwapchainImpl->display),
7390 attribs, &nCfgs);
7393 if (cfgs == NULL) {
7394 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7395 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7396 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7397 } else {
7398 #ifdef EXTRA_TRACES
7399 int i;
7400 for (i = 0; i < nCfgs; ++i) {
7401 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7402 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7403 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7405 if (NULL != This->renderTarget) {
7406 glFlush();
7407 vcheckGLcall("glFlush");
7408 /** This is only useful if the old render target was a swapchain,
7409 * we need to supercede this with a function that displays
7410 * the current buffer on the screen. This is easy to do in glx1.3 but
7411 * we need to do copy-write pixels in glx 1.2.
7412 ************************************************/
7413 glXSwapBuffers(implicitSwapChainImpl->display,
7414 implicitSwapChainImpl->drawable);
7415 printf("Hit Enter to get next frame ...\n");
7416 getchar();
7418 #endif
7420 #undef PUSH1
7421 #undef PUSH2
7423 return cfgs;
7426 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7427 * the functionality needs splitting up so that we don't do more than we should do.
7428 * this only seems to impact performance a little.
7429 ******************************/
7430 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7431 IWineD3DSurface *RenderSurface) {
7434 * Currently only active for GLX >= 1.3
7435 * for others versions we'll have to use GLXPixmaps
7437 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7438 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7439 * so only check OpenGL version
7440 * ..........................
7441 * I don't believe that it is a problem with NVidia headers,
7442 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7443 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7444 * ATI Note:
7445 * Your application will report GLX version 1.2 on glXQueryVersion.
7446 * However, it is safe to call the GLX 1.3 functions as described below.
7448 #if defined(GL_VERSION_1_3)
7450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7451 IWineD3DSurface *tmp;
7452 GLXFBConfig* cfgs = NULL;
7453 IWineD3DSwapChain *currentSwapchain;
7454 IWineD3DSwapChainImpl *currentSwapchainImpl;
7455 IWineD3DSwapChain *implicitSwapchain;
7456 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7457 IWineD3DSwapChain *renderSurfaceSwapchain;
7458 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7460 /* Obtain a reference to the device implicit swapchain,
7461 * the swapchain of the current render target,
7462 * and the swapchain of the new render target.
7463 * Fallback to device implicit swapchain if the current render target doesn't have one */
7464 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7465 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7466 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7467 if (currentSwapchain == NULL)
7468 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7470 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7471 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7472 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7474 ENTER_GL();
7477 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7478 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7479 **********************************************************************/
7480 if (renderSurfaceSwapchain != NULL) {
7482 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7483 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7484 TRACE("making swapchain active\n");
7485 if (RenderSurface != This->renderTarget) {
7486 BOOL backbuf = FALSE;
7487 int i;
7489 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7490 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7491 backbuf = TRUE;
7492 break;
7496 if (backbuf) {
7497 } else {
7498 /* This could be flagged so that some operations work directly with the front buffer */
7499 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7501 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7502 renderSurfaceSwapchainImpl->win,
7503 renderSurfaceSwapchainImpl->glCtx) == False) {
7505 TRACE("Error in setting current context: context %p drawable %ld !\n",
7506 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7508 checkGLcall("glXMakeContextCurrent");
7510 /* Clean up the old context */
7511 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7513 /* Reapply the stateblock, and set the device not to render to texture */
7514 device_reapply_stateblock(This);
7515 device_render_to_texture(This, FALSE);
7518 /* Offscreen rendering: PBuffers (currently disabled).
7519 * Also note that this path is never reached if FBOs are supported */
7520 } else if (pbuffer_support &&
7521 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7523 /** ********************************************************************
7524 * This is a quickly hacked out implementation of offscreen textures.
7525 * It will work in most cases but there may be problems if the client
7526 * modifies the texture directly, or expects the contents of the rendertarget
7527 * to be persistent.
7529 * There are some real speed vs compatibility issues here:
7530 * we should really use a new context for every texture, but that eats ram.
7531 * we should also be restoring the texture to the pbuffer but that eats CPU
7532 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7533 * but if this means reusing the display backbuffer then we need to make sure that
7534 * states are correctly preserved.
7535 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7536 * and gain a good performance increase at the cost of compatibility.
7537 * I would suggest that, when this is the case, a user configurable flag be made
7538 * available, allowing the user to choose the best emulated experience for them.
7539 *********************************************************************/
7541 XVisualInfo *visinfo;
7542 glContext *newContext;
7544 /* Here were using a shared context model */
7545 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7546 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7549 /* If the context doesn't exist then create a new one */
7550 /* TODO: This should really be part of findGlContext */
7551 if (NULL == newContext->context) {
7553 int attribs[256];
7554 int nAttribs = 0;
7556 TRACE("making new buffer\n");
7557 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7558 attribs[nAttribs++] = newContext->Width;
7559 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7560 attribs[nAttribs++] = newContext->Height;
7561 attribs[nAttribs++] = None;
7563 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7565 /** ****************************************
7566 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7567 *they note:
7568 * In future releases, we may provide the calls glXCreateNewContext,
7569 * glXQueryDrawable and glXMakeContextCurrent.
7570 * so until then we have to use glXGetVisualFromFBConfig &co..
7571 ********************************************/
7573 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7574 if (!visinfo) {
7575 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7576 } else {
7577 newContext->context = glXCreateContext(
7578 implicitSwapchainImpl->display, visinfo,
7579 implicitSwapchainImpl->glCtx, GL_TRUE);
7581 XFree(visinfo);
7584 if (NULL == newContext || NULL == newContext->context) {
7585 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7586 } else {
7587 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7588 if (glXMakeCurrent(implicitSwapchainImpl->display,
7589 newContext->drawable, newContext->context) == False) {
7591 TRACE("Error in setting current context: context %p drawable %ld\n",
7592 newContext->context, newContext->drawable);
7594 checkGLcall("glXMakeContextCurrent");
7596 /* Clean up the old context */
7597 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7599 /* Reapply stateblock, and set device to render to a texture */
7600 device_reapply_stateblock(This);
7601 device_render_to_texture(This, TRUE);
7603 /* Set the current context of the swapchain to the new context */
7604 implicitSwapchainImpl->drawable = newContext->drawable;
7605 implicitSwapchainImpl->render_ctx = newContext->context;
7609 /* Replace the render target */
7610 tmp = This->renderTarget;
7611 This->renderTarget = RenderSurface;
7612 IWineD3DSurface_AddRef(This->renderTarget);
7613 IWineD3DSurface_Release(tmp);
7615 if (cfgs != NULL) XFree(cfgs);
7616 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
7617 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7618 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7619 LEAVE_GL();
7620 #endif
7621 return WINED3D_OK;
7624 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7625 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7627 /* TODO: the use of Impl is deprecated. */
7628 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7630 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7632 /* some basic validation checks */
7633 if(This->cursorTexture) {
7634 ENTER_GL();
7635 glDeleteTextures(1, &This->cursorTexture);
7636 LEAVE_GL();
7637 This->cursorTexture = 0;
7640 if(pCursorBitmap) {
7641 /* MSDN: Cursor must be A8R8G8B8 */
7642 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7643 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7644 return WINED3DERR_INVALIDCALL;
7647 /* MSDN: Cursor must be smaller than the display mode */
7648 if(pSur->currentDesc.Width > This->ddraw_width ||
7649 pSur->currentDesc.Height > This->ddraw_height) {
7650 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);
7651 return WINED3DERR_INVALIDCALL;
7654 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7655 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7656 * Texture and Blitting code to draw the cursor
7658 pSur->Flags |= SFLAG_FORCELOAD;
7659 IWineD3DSurface_PreLoad(pCursorBitmap);
7660 pSur->Flags &= ~SFLAG_FORCELOAD;
7661 /* Do not store the surface's pointer because the application may release
7662 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7663 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7665 This->cursorTexture = pSur->glDescription.textureName;
7666 This->cursorWidth = pSur->currentDesc.Width;
7667 This->cursorHeight = pSur->currentDesc.Height;
7668 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7671 This->xHotSpot = XHotSpot;
7672 This->yHotSpot = YHotSpot;
7673 return WINED3D_OK;
7676 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7678 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7680 This->xScreenSpace = XScreenSpace;
7681 This->yScreenSpace = YScreenSpace;
7683 return;
7687 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7689 BOOL oldVisible = This->bCursorVisible;
7690 TRACE("(%p) : visible(%d)\n", This, bShow);
7692 if(This->cursorTexture)
7693 This->bCursorVisible = bShow;
7695 return oldVisible;
7698 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7700 TRACE("(%p) : state (%lu)\n", This, This->state);
7701 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7702 switch (This->state) {
7703 case WINED3D_OK:
7704 return WINED3D_OK;
7705 case WINED3DERR_DEVICELOST:
7707 ResourceList *resourceList = This->resources;
7708 while (NULL != resourceList) {
7709 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7710 return WINED3DERR_DEVICENOTRESET;
7711 resourceList = resourceList->next;
7713 return WINED3DERR_DEVICELOST;
7715 case WINED3DERR_DRIVERINTERNALERROR:
7716 return WINED3DERR_DRIVERINTERNALERROR;
7719 /* Unknown state */
7720 return WINED3DERR_DRIVERINTERNALERROR;
7724 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7726 /** FIXME: Resource tracking needs to be done,
7727 * The closes we can do to this is set the priorities of all managed textures low
7728 * and then reset them.
7729 ***********************************************************/
7730 FIXME("(%p) : stub\n", This);
7731 return WINED3D_OK;
7734 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7736 /** FIXME: Resource trascking needs to be done.
7737 * in effect this pulls all non only default
7738 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7739 * and should clear down the context and set it up according to pPresentationParameters
7740 ***********************************************************/
7741 FIXME("(%p) : stub\n", This);
7742 return WINED3D_OK;
7745 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7747 /** FIXME: always true at the moment **/
7748 if(bEnableDialogs == FALSE) {
7749 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7751 return WINED3D_OK;
7755 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7757 TRACE("(%p) : pParameters %p\n", This, pParameters);
7759 *pParameters = This->createParms;
7760 return WINED3D_OK;
7763 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7764 IWineD3DSwapChain *swapchain;
7765 HRESULT hrc = WINED3D_OK;
7767 TRACE("Relaying to swapchain\n");
7769 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7770 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7771 IWineD3DSwapChain_Release(swapchain);
7773 return;
7776 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7777 IWineD3DSwapChain *swapchain;
7778 HRESULT hrc = WINED3D_OK;
7780 TRACE("Relaying to swapchain\n");
7782 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7783 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7784 IWineD3DSwapChain_Release(swapchain);
7786 return;
7790 /** ********************************************************
7791 * Notification functions
7792 ** ********************************************************/
7793 /** This function must be called in the release of a resource when ref == 0,
7794 * the contents of resource must still be correct,
7795 * any handels to other resource held by the caller must be closed
7796 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7797 *****************************************************/
7798 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7800 ResourceList* resourceList;
7802 TRACE("(%p) : resource %p\n", This, resource);
7803 #if 0
7804 EnterCriticalSection(&resourceStoreCriticalSection);
7805 #endif
7806 /* add a new texture to the frot of the linked list */
7807 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7808 resourceList->resource = resource;
7810 /* Get the old head */
7811 resourceList->next = This->resources;
7813 This->resources = resourceList;
7814 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7816 #if 0
7817 LeaveCriticalSection(&resourceStoreCriticalSection);
7818 #endif
7819 return;
7822 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7824 ResourceList* resourceList = NULL;
7825 ResourceList* previousResourceList = NULL;
7827 TRACE("(%p) : resource %p\n", This, resource);
7829 #if 0
7830 EnterCriticalSection(&resourceStoreCriticalSection);
7831 #endif
7832 resourceList = This->resources;
7834 while (resourceList != NULL) {
7835 if(resourceList->resource == resource) break;
7836 previousResourceList = resourceList;
7837 resourceList = resourceList->next;
7840 if (resourceList == NULL) {
7841 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7842 #if 0
7843 LeaveCriticalSection(&resourceStoreCriticalSection);
7844 #endif
7845 return;
7846 } else {
7847 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7849 /* make sure we don't leave a hole in the list */
7850 if (previousResourceList != NULL) {
7851 previousResourceList->next = resourceList->next;
7852 } else {
7853 This->resources = resourceList->next;
7856 #if 0
7857 LeaveCriticalSection(&resourceStoreCriticalSection);
7858 #endif
7859 return;
7863 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7865 int counter;
7867 TRACE("(%p) : resource %p\n", This, resource);
7868 switch(IWineD3DResource_GetType(resource)){
7869 case WINED3DRTYPE_SURFACE:
7870 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7871 break;
7872 case WINED3DRTYPE_TEXTURE:
7873 case WINED3DRTYPE_CUBETEXTURE:
7874 case WINED3DRTYPE_VOLUMETEXTURE:
7875 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7876 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7877 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7878 This->stateBlock->textures[counter] = NULL;
7880 if (This->updateStateBlock != This->stateBlock ){
7881 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7882 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7883 This->updateStateBlock->textures[counter] = NULL;
7887 break;
7888 case WINED3DRTYPE_VOLUME:
7889 /* TODO: nothing really? */
7890 break;
7891 case WINED3DRTYPE_VERTEXBUFFER:
7892 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7894 int streamNumber;
7895 TRACE("Cleaning up stream pointers\n");
7897 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7898 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7899 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7901 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7902 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7903 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7904 This->updateStateBlock->streamSource[streamNumber] = 0;
7905 /* Set changed flag? */
7908 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) */
7909 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7910 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7911 This->stateBlock->streamSource[streamNumber] = 0;
7914 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7915 else { /* This shouldn't happen */
7916 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7918 #endif
7922 break;
7923 case WINED3DRTYPE_INDEXBUFFER:
7924 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7925 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7926 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7927 This->updateStateBlock->pIndexData = NULL;
7930 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7931 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7932 This->stateBlock->pIndexData = NULL;
7936 break;
7937 default:
7938 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7939 break;
7943 /* Remove the resoruce from the resourceStore */
7944 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7946 TRACE("Resource released\n");
7950 /**********************************************************
7951 * IWineD3DDevice VTbl follows
7952 **********************************************************/
7954 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7956 /*** IUnknown methods ***/
7957 IWineD3DDeviceImpl_QueryInterface,
7958 IWineD3DDeviceImpl_AddRef,
7959 IWineD3DDeviceImpl_Release,
7960 /*** IWineD3DDevice methods ***/
7961 IWineD3DDeviceImpl_GetParent,
7962 /*** Creation methods**/
7963 IWineD3DDeviceImpl_CreateVertexBuffer,
7964 IWineD3DDeviceImpl_CreateIndexBuffer,
7965 IWineD3DDeviceImpl_CreateStateBlock,
7966 IWineD3DDeviceImpl_CreateSurface,
7967 IWineD3DDeviceImpl_CreateTexture,
7968 IWineD3DDeviceImpl_CreateVolumeTexture,
7969 IWineD3DDeviceImpl_CreateVolume,
7970 IWineD3DDeviceImpl_CreateCubeTexture,
7971 IWineD3DDeviceImpl_CreateQuery,
7972 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7973 IWineD3DDeviceImpl_CreateVertexDeclaration,
7974 IWineD3DDeviceImpl_CreateVertexShader,
7975 IWineD3DDeviceImpl_CreatePixelShader,
7976 IWineD3DDeviceImpl_CreatePalette,
7977 /*** Odd functions **/
7978 IWineD3DDeviceImpl_Init3D,
7979 IWineD3DDeviceImpl_Uninit3D,
7980 IWineD3DDeviceImpl_SetFullscreen,
7981 IWineD3DDeviceImpl_EnumDisplayModes,
7982 IWineD3DDeviceImpl_EvictManagedResources,
7983 IWineD3DDeviceImpl_GetAvailableTextureMem,
7984 IWineD3DDeviceImpl_GetBackBuffer,
7985 IWineD3DDeviceImpl_GetCreationParameters,
7986 IWineD3DDeviceImpl_GetDeviceCaps,
7987 IWineD3DDeviceImpl_GetDirect3D,
7988 IWineD3DDeviceImpl_GetDisplayMode,
7989 IWineD3DDeviceImpl_SetDisplayMode,
7990 IWineD3DDeviceImpl_GetHWND,
7991 IWineD3DDeviceImpl_SetHWND,
7992 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7993 IWineD3DDeviceImpl_GetRasterStatus,
7994 IWineD3DDeviceImpl_GetSwapChain,
7995 IWineD3DDeviceImpl_Reset,
7996 IWineD3DDeviceImpl_SetDialogBoxMode,
7997 IWineD3DDeviceImpl_SetCursorProperties,
7998 IWineD3DDeviceImpl_SetCursorPosition,
7999 IWineD3DDeviceImpl_ShowCursor,
8000 IWineD3DDeviceImpl_TestCooperativeLevel,
8001 /*** Getters and setters **/
8002 IWineD3DDeviceImpl_SetClipPlane,
8003 IWineD3DDeviceImpl_GetClipPlane,
8004 IWineD3DDeviceImpl_SetClipStatus,
8005 IWineD3DDeviceImpl_GetClipStatus,
8006 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8007 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8008 IWineD3DDeviceImpl_SetDepthStencilSurface,
8009 IWineD3DDeviceImpl_GetDepthStencilSurface,
8010 IWineD3DDeviceImpl_SetFVF,
8011 IWineD3DDeviceImpl_GetFVF,
8012 IWineD3DDeviceImpl_SetGammaRamp,
8013 IWineD3DDeviceImpl_GetGammaRamp,
8014 IWineD3DDeviceImpl_SetIndices,
8015 IWineD3DDeviceImpl_GetIndices,
8016 IWineD3DDeviceImpl_SetLight,
8017 IWineD3DDeviceImpl_GetLight,
8018 IWineD3DDeviceImpl_SetLightEnable,
8019 IWineD3DDeviceImpl_GetLightEnable,
8020 IWineD3DDeviceImpl_SetMaterial,
8021 IWineD3DDeviceImpl_GetMaterial,
8022 IWineD3DDeviceImpl_SetNPatchMode,
8023 IWineD3DDeviceImpl_GetNPatchMode,
8024 IWineD3DDeviceImpl_SetPaletteEntries,
8025 IWineD3DDeviceImpl_GetPaletteEntries,
8026 IWineD3DDeviceImpl_SetPixelShader,
8027 IWineD3DDeviceImpl_GetPixelShader,
8028 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8029 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8030 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8031 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8032 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8033 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8034 IWineD3DDeviceImpl_SetRenderState,
8035 IWineD3DDeviceImpl_GetRenderState,
8036 IWineD3DDeviceImpl_SetRenderTarget,
8037 IWineD3DDeviceImpl_GetRenderTarget,
8038 IWineD3DDeviceImpl_SetFrontBackBuffers,
8039 IWineD3DDeviceImpl_SetSamplerState,
8040 IWineD3DDeviceImpl_GetSamplerState,
8041 IWineD3DDeviceImpl_SetScissorRect,
8042 IWineD3DDeviceImpl_GetScissorRect,
8043 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8044 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8045 IWineD3DDeviceImpl_SetStreamSource,
8046 IWineD3DDeviceImpl_GetStreamSource,
8047 IWineD3DDeviceImpl_SetStreamSourceFreq,
8048 IWineD3DDeviceImpl_GetStreamSourceFreq,
8049 IWineD3DDeviceImpl_SetTexture,
8050 IWineD3DDeviceImpl_GetTexture,
8051 IWineD3DDeviceImpl_SetTextureStageState,
8052 IWineD3DDeviceImpl_GetTextureStageState,
8053 IWineD3DDeviceImpl_SetTransform,
8054 IWineD3DDeviceImpl_GetTransform,
8055 IWineD3DDeviceImpl_SetVertexDeclaration,
8056 IWineD3DDeviceImpl_GetVertexDeclaration,
8057 IWineD3DDeviceImpl_SetVertexShader,
8058 IWineD3DDeviceImpl_GetVertexShader,
8059 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8060 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8061 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8062 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8063 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8064 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8065 IWineD3DDeviceImpl_SetViewport,
8066 IWineD3DDeviceImpl_GetViewport,
8067 IWineD3DDeviceImpl_MultiplyTransform,
8068 IWineD3DDeviceImpl_ValidateDevice,
8069 IWineD3DDeviceImpl_ProcessVertices,
8070 /*** State block ***/
8071 IWineD3DDeviceImpl_BeginStateBlock,
8072 IWineD3DDeviceImpl_EndStateBlock,
8073 /*** Scene management ***/
8074 IWineD3DDeviceImpl_BeginScene,
8075 IWineD3DDeviceImpl_EndScene,
8076 IWineD3DDeviceImpl_Present,
8077 IWineD3DDeviceImpl_Clear,
8078 /*** Drawing ***/
8079 IWineD3DDeviceImpl_DrawPrimitive,
8080 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8081 IWineD3DDeviceImpl_DrawPrimitiveUP,
8082 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8083 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8084 IWineD3DDeviceImpl_DrawRectPatch,
8085 IWineD3DDeviceImpl_DrawTriPatch,
8086 IWineD3DDeviceImpl_DeletePatch,
8087 IWineD3DDeviceImpl_ColorFill,
8088 IWineD3DDeviceImpl_UpdateTexture,
8089 IWineD3DDeviceImpl_UpdateSurface,
8090 IWineD3DDeviceImpl_CopyRects,
8091 IWineD3DDeviceImpl_StretchRect,
8092 IWineD3DDeviceImpl_GetRenderTargetData,
8093 IWineD3DDeviceImpl_GetFrontBufferData,
8094 /*** Internal use IWineD3DDevice methods ***/
8095 IWineD3DDeviceImpl_SetupTextureStates,
8096 /*** object tracking ***/
8097 IWineD3DDeviceImpl_ResourceReleased
8101 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8102 WINED3DRS_ALPHABLENDENABLE ,
8103 WINED3DRS_ALPHAFUNC ,
8104 WINED3DRS_ALPHAREF ,
8105 WINED3DRS_ALPHATESTENABLE ,
8106 WINED3DRS_BLENDOP ,
8107 WINED3DRS_COLORWRITEENABLE ,
8108 WINED3DRS_DESTBLEND ,
8109 WINED3DRS_DITHERENABLE ,
8110 WINED3DRS_FILLMODE ,
8111 WINED3DRS_FOGDENSITY ,
8112 WINED3DRS_FOGEND ,
8113 WINED3DRS_FOGSTART ,
8114 WINED3DRS_LASTPIXEL ,
8115 WINED3DRS_SHADEMODE ,
8116 WINED3DRS_SRCBLEND ,
8117 WINED3DRS_STENCILENABLE ,
8118 WINED3DRS_STENCILFAIL ,
8119 WINED3DRS_STENCILFUNC ,
8120 WINED3DRS_STENCILMASK ,
8121 WINED3DRS_STENCILPASS ,
8122 WINED3DRS_STENCILREF ,
8123 WINED3DRS_STENCILWRITEMASK ,
8124 WINED3DRS_STENCILZFAIL ,
8125 WINED3DRS_TEXTUREFACTOR ,
8126 WINED3DRS_WRAP0 ,
8127 WINED3DRS_WRAP1 ,
8128 WINED3DRS_WRAP2 ,
8129 WINED3DRS_WRAP3 ,
8130 WINED3DRS_WRAP4 ,
8131 WINED3DRS_WRAP5 ,
8132 WINED3DRS_WRAP6 ,
8133 WINED3DRS_WRAP7 ,
8134 WINED3DRS_ZENABLE ,
8135 WINED3DRS_ZFUNC ,
8136 WINED3DRS_ZWRITEENABLE
8139 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8140 WINED3DTSS_ADDRESSW ,
8141 WINED3DTSS_ALPHAARG0 ,
8142 WINED3DTSS_ALPHAARG1 ,
8143 WINED3DTSS_ALPHAARG2 ,
8144 WINED3DTSS_ALPHAOP ,
8145 WINED3DTSS_BUMPENVLOFFSET ,
8146 WINED3DTSS_BUMPENVLSCALE ,
8147 WINED3DTSS_BUMPENVMAT00 ,
8148 WINED3DTSS_BUMPENVMAT01 ,
8149 WINED3DTSS_BUMPENVMAT10 ,
8150 WINED3DTSS_BUMPENVMAT11 ,
8151 WINED3DTSS_COLORARG0 ,
8152 WINED3DTSS_COLORARG1 ,
8153 WINED3DTSS_COLORARG2 ,
8154 WINED3DTSS_COLOROP ,
8155 WINED3DTSS_RESULTARG ,
8156 WINED3DTSS_TEXCOORDINDEX ,
8157 WINED3DTSS_TEXTURETRANSFORMFLAGS
8160 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8161 WINED3DSAMP_ADDRESSU ,
8162 WINED3DSAMP_ADDRESSV ,
8163 WINED3DSAMP_ADDRESSW ,
8164 WINED3DSAMP_BORDERCOLOR ,
8165 WINED3DSAMP_MAGFILTER ,
8166 WINED3DSAMP_MINFILTER ,
8167 WINED3DSAMP_MIPFILTER ,
8168 WINED3DSAMP_MIPMAPLODBIAS ,
8169 WINED3DSAMP_MAXMIPLEVEL ,
8170 WINED3DSAMP_MAXANISOTROPY ,
8171 WINED3DSAMP_SRGBTEXTURE ,
8172 WINED3DSAMP_ELEMENTINDEX
8175 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8176 WINED3DRS_AMBIENT ,
8177 WINED3DRS_AMBIENTMATERIALSOURCE ,
8178 WINED3DRS_CLIPPING ,
8179 WINED3DRS_CLIPPLANEENABLE ,
8180 WINED3DRS_COLORVERTEX ,
8181 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8182 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8183 WINED3DRS_FOGDENSITY ,
8184 WINED3DRS_FOGEND ,
8185 WINED3DRS_FOGSTART ,
8186 WINED3DRS_FOGTABLEMODE ,
8187 WINED3DRS_FOGVERTEXMODE ,
8188 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8189 WINED3DRS_LIGHTING ,
8190 WINED3DRS_LOCALVIEWER ,
8191 WINED3DRS_MULTISAMPLEANTIALIAS ,
8192 WINED3DRS_MULTISAMPLEMASK ,
8193 WINED3DRS_NORMALIZENORMALS ,
8194 WINED3DRS_PATCHEDGESTYLE ,
8195 WINED3DRS_POINTSCALE_A ,
8196 WINED3DRS_POINTSCALE_B ,
8197 WINED3DRS_POINTSCALE_C ,
8198 WINED3DRS_POINTSCALEENABLE ,
8199 WINED3DRS_POINTSIZE ,
8200 WINED3DRS_POINTSIZE_MAX ,
8201 WINED3DRS_POINTSIZE_MIN ,
8202 WINED3DRS_POINTSPRITEENABLE ,
8203 WINED3DRS_RANGEFOGENABLE ,
8204 WINED3DRS_SPECULARMATERIALSOURCE ,
8205 WINED3DRS_TWEENFACTOR ,
8206 WINED3DRS_VERTEXBLEND
8209 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8210 WINED3DTSS_TEXCOORDINDEX ,
8211 WINED3DTSS_TEXTURETRANSFORMFLAGS
8214 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8215 WINED3DSAMP_DMAPOFFSET