wined3d: Fix light state bugs.
[wine/testsucceed.git] / dlls / wined3d / device.c
blob630d6d4ac6eac25f3bd75c28b6f858462579eec4
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include <stdio.h>
28 #ifdef HAVE_FLOAT_H
29 # include <float.h>
30 #endif
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
87 /* helper macros */
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
96 object->ref = 1; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
117 *pp##type = NULL; \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
126 *pp##type = NULL; \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
152 float quad_att;
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
158 glPushMatrix();
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
161 /* Diffuse: */
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
169 /* Specular */
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
177 /* Ambient */
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
193 } else {
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
202 case D3DLIGHT_POINT:
203 /* Position */
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
208 /* FIXME: Range */
209 break;
211 case D3DLIGHT_SPOT:
212 /* Position */
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
215 /* Direction */
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
222 /* FIXME: Range */
223 break;
225 case D3DLIGHT_DIRECTIONAL:
226 /* Direction */
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
233 break;
235 default:
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
240 glPopMatrix();
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
265 * objects, too.
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 ptr = list_head( &This->glsl_shader_progs );
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->shaderPrgId = curLink->programId;
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);
303 This->stateBlock->shaderPrgId = programId;
305 /* Allocate a new link for the list of programs */
306 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
307 newLink->programId = programId;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
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);
347 return;
350 /** Detach the GLSL pixel or vertex shader object from the shader program */
351 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
355 if (shaderObj != 0 && programId != 0) {
356 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
357 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
358 checkGLcall("glDetachObjectARB");
362 /** Delete a GLSL shader program */
363 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
367 if (obj != 0) {
368 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
369 GL_EXTCALL(glDeleteObjectARB(obj));
370 checkGLcall("glDeleteObjectARB");
374 /** Delete the list of linked programs this shader is associated with.
375 * Also at this point, check to see if there are any objects left attached
376 * to each GLSL program. If not, delete the GLSL program object.
377 * This will be run when a device is released. */
378 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
380 struct list *ptr = NULL;
381 struct glsl_shader_prog_link *curLink = NULL;
382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
384 int numAttached = 0;
385 int i;
386 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
387 (one pixel shader and one vertex shader at most) */
389 ptr = list_head( &This->glsl_shader_progs );
390 while (ptr) {
391 /* First, get the current item,
392 * save the link to the next pointer,
393 * detach and delete shader objects,
394 * then de-allocate the list item's memory */
395 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
396 ptr = list_next( &This->glsl_shader_progs, ptr );
398 /* See if this object is still attached to the program - it may have been detached already */
399 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
400 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
401 for (i = 0; i < numAttached; i++) {
402 detach_glsl_shader(iface, objList[i], curLink->programId);
405 delete_glsl_shader_program(iface, curLink->programId);
407 /* Free the memory for this list item */
408 HeapFree(GetProcessHeap(), 0, curLink);
413 /* Apply the current values to the specified texture stage */
414 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
416 float col[4];
418 union {
419 float f;
420 DWORD d;
421 } tmpvalue;
423 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
424 clamping, MIPLOD, etc. This will work for up to 16 samplers.
427 if (Sampler >= GL_LIMITS(sampler_stages)) {
428 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
429 return;
431 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
432 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
433 ENTER_GL();
434 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
435 checkGLcall("glActiveTextureARB");
436 LEAVE_GL();
437 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
438 } else if (Sampler > 0) {
439 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
440 return;
443 /* TODO: change this to a lookup table
444 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
445 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
446 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
447 especially when there are a number of groups of states. */
449 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
451 /* The list of states not to apply is a big as the list of states to apply, so it makes sense to produce an inclusive list */
452 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
453 /* these are the only two supported states that need to be applied */
454 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
455 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
456 #if 0 /* not supported at the moment */
457 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
458 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
459 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
460 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
461 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
462 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
463 APPLY_STATE(WINED3DTSS_RESULTARG);
464 APPLY_STATE(WINED3DTSS_CONSTANT);
465 #endif
466 /* a quick sanity check in case someone forgot to update this function */
467 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
468 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
470 #undef APPLY_STATE
472 /* apply any sampler states that always need applying */
473 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
474 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
475 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
476 GL_TEXTURE_LOD_BIAS_EXT,
477 tmpvalue.f);
478 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
481 /* Note the D3DRS value applies to all textures, but GL has one
482 * per texture, so apply it now ready to be used!
484 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
485 /* Set the default alpha blend color */
486 if (GL_SUPPORT(ARB_IMAGING)) {
487 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
488 checkGLcall("glBlendColor");
489 } else {
490 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
493 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
494 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
495 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
497 /* TODO: NV_POINT_SPRITE */
498 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
499 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
500 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
501 glDisable(GL_POINT_SMOOTH);
503 /* Centre the texture on the vertex */
504 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
505 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
507 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
508 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
509 checkGLcall("glTexEnvf(...)");
510 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
511 glEnable( GL_POINT_SPRITE_ARB );
512 checkGLcall("glEnable(...)");
513 } else {
514 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
515 glDisable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
520 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
523 /**********************************************************
524 * IUnknown parts follows
525 **********************************************************/
527 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
532 if (IsEqualGUID(riid, &IID_IUnknown)
533 || IsEqualGUID(riid, &IID_IWineD3DBase)
534 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
535 IUnknown_AddRef(iface);
536 *ppobj = This;
537 return S_OK;
539 *ppobj = NULL;
540 return E_NOINTERFACE;
543 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
545 ULONG refCount = InterlockedIncrement(&This->ref);
547 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
548 return refCount;
551 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
553 ULONG refCount = InterlockedDecrement(&This->ref);
555 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
557 if (!refCount) {
558 /* TODO: Clean up all the surfaces and textures! */
559 /* NOTE: You must release the parent if the object was created via a callback
560 ** ***************************/
562 /* Delete any GLSL shader programs that may exist */
563 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
564 wined3d_settings.ps_selected_mode == SHADER_GLSL)
565 delete_glsl_shader_list(iface);
567 /* Release the update stateblock */
568 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
569 if(This->updateStateBlock != This->stateBlock)
570 FIXME("(%p) Something's still holding the Update stateblock\n",This);
572 This->updateStateBlock = NULL;
573 { /* because were not doing proper internal refcounts releasing the primary state block
574 causes recursion with the extra checks in ResourceReleased, to avoid this we have
575 to set this->stateBlock = NULL; first */
576 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
577 This->stateBlock = NULL;
579 /* Release the stateblock */
580 if(IWineD3DStateBlock_Release(stateBlock) > 0){
581 FIXME("(%p) Something's still holding the Update stateblock\n",This);
585 if (This->resources != NULL ) {
586 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
587 dumpResources(This->resources);
591 IWineD3D_Release(This->wineD3D);
592 This->wineD3D = NULL;
593 HeapFree(GetProcessHeap(), 0, This);
594 TRACE("Freed device %p\n", This);
595 This = NULL;
597 return refCount;
600 /**********************************************************
601 * IWineD3DDevice implementation follows
602 **********************************************************/
603 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
605 *pParent = This->parent;
606 IUnknown_AddRef(This->parent);
607 return WINED3D_OK;
610 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
611 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
612 GLenum error, glUsage;
613 DWORD vboUsage = object->resource.usage;
614 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
616 ENTER_GL();
617 /* Make sure that the gl error is cleared. Do not use checkGLcall
618 * here because checkGLcall just prints a fixme and continues. However,
619 * if an error during VBO creation occurs we can fall back to non-vbo operation
620 * with full functionality(but performance loss)
622 while(glGetError() != GL_NO_ERROR);
624 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
625 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
626 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
627 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
628 * to check if the rhw and color values are in the correct format.
631 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
632 error = glGetError();
633 if(object->vbo == 0 || error != GL_NO_ERROR) {
634 WARN("Failed to create a VBO with error %d\n", error);
635 goto error;
638 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
639 error = glGetError();
640 if(error != GL_NO_ERROR) {
641 WARN("Failed to bind the VBO, error %d\n", error);
642 goto error;
645 /* Transformed vertices are horribly inflexible. If the app specifies an
646 * vertex buffer with transformed vertices in default pool without DYNAMIC
647 * usage assume DYNAMIC usage and print a warning. The app will have to update
648 * the vertices regularily for them to be useful
650 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
651 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
652 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
653 vboUsage |= WINED3DUSAGE_DYNAMIC;
656 /* Don't use static, because dx apps tend to update the buffer
657 * quite often even if they specify 0 usage
659 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
660 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
661 TRACE("Gl usage = GL_STREAM_DRAW\n");
662 glUsage = GL_STREAM_DRAW_ARB;
663 break;
664 case D3DUSAGE_WRITEONLY:
665 TRACE("Gl usage = GL_STATIC_DRAW\n");
666 glUsage = GL_DYNAMIC_DRAW_ARB;
667 break;
668 case D3DUSAGE_DYNAMIC:
669 TRACE("Gl usage = GL_STREAM_COPY\n");
670 glUsage = GL_STREAM_COPY_ARB;
671 break;
672 default:
673 TRACE("Gl usage = GL_STATIC_COPY\n");
674 glUsage = GL_DYNAMIC_COPY_ARB;
675 break;
678 /* Reserve memory for the buffer. The amount of data won't change
679 * so we are safe with calling glBufferData once with a NULL ptr and
680 * calling glBufferSubData on updates
682 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
683 error = glGetError();
684 if(error != GL_NO_ERROR) {
685 WARN("glBufferDataARB failed with error %d\n", error);
686 goto error;
689 LEAVE_GL();
691 return;
692 error:
693 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
694 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
695 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
696 object->vbo = 0;
697 LEAVE_GL();
698 return;
701 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
702 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
703 IUnknown *parent) {
704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
705 IWineD3DVertexBufferImpl *object;
706 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
707 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
708 BOOL conv;
709 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
711 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
712 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
714 if(Size == 0) return WINED3DERR_INVALIDCALL;
716 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
717 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
719 object->fvf = FVF;
721 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
722 * drawStridedFast (half-life 2).
724 * Basically converting the vertices in the buffer is quite expensive, and observations
725 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
726 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
728 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
729 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
730 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
731 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
732 * dx7 apps.
733 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
734 * more. In this call we can convert dx7 buffers too.
736 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
737 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
738 (dxVersion > 7 || !conv) ) {
739 CreateVBO(object);
741 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
742 if(dxVersion == 7 && object->vbo) {
743 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
744 object->resource.allocatedMemory = NULL;
748 return WINED3D_OK;
751 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
752 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
753 HANDLE *sharedHandle, IUnknown *parent) {
754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
755 IWineD3DIndexBufferImpl *object;
756 TRACE("(%p) Creating index buffer\n", This);
758 /* Allocate the storage for the device */
759 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
761 /*TODO: use VBO's */
762 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
763 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
766 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
767 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
768 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
770 return WINED3D_OK;
773 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
776 IWineD3DStateBlockImpl *object;
777 int i, j;
779 D3DCREATEOBJECTINSTANCE(object, StateBlock)
780 object->blockType = Type;
782 /* Special case - Used during initialization to produce a placeholder stateblock
783 so other functions called can update a state block */
784 if (Type == WINED3DSBT_INIT) {
785 /* Don't bother increasing the reference count otherwise a device will never
786 be freed due to circular dependencies */
787 return WINED3D_OK;
790 /* Otherwise, might as well set the whole state block to the appropriate values */
791 if ( This->stateBlock != NULL) {
792 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
793 } else {
794 memset(object->streamFreq, 1, sizeof(object->streamFreq));
797 /* Reset the ref and type after kludging it */
798 object->wineD3DDevice = This;
799 object->ref = 1;
800 object->blockType = Type;
802 TRACE("Updating changed flags appropriate for type %d\n", Type);
804 if (Type == WINED3DSBT_ALL) {
806 TRACE("ALL => Pretend everything has changed\n");
807 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
808 } else if (Type == WINED3DSBT_PIXELSTATE) {
810 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
811 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
813 object->changed.pixelShader = TRUE;
815 /* Pixel Shader Constants */
816 for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
817 object->changed.pixelShaderConstantsF[i] = TRUE;
818 object->changed.pixelShaderConstantsB[i] = TRUE;
819 object->changed.pixelShaderConstantsI[i] = TRUE;
821 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
822 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
824 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
825 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
826 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
829 for (j = 0 ; j < 16; j++) {
830 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
832 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
836 } else if (Type == WINED3DSBT_VERTEXSTATE) {
838 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
839 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
841 object->changed.vertexShader = TRUE;
843 /* Vertex Shader Constants */
844 for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
845 object->changed.vertexShaderConstantsF[i] = TRUE;
846 object->changed.vertexShaderConstantsB[i] = TRUE;
847 object->changed.vertexShaderConstantsI[i] = TRUE;
849 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
850 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
852 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
853 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
854 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
857 for (j = 0 ; j < 16; j++){
858 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
859 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
863 /* Duplicate light chain */
865 PLIGHTINFOEL *src = NULL;
866 PLIGHTINFOEL *dst = NULL;
867 PLIGHTINFOEL *newEl = NULL;
868 src = This->stateBlock->lights;
869 object->lights = NULL;
872 while (src) {
873 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
874 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
875 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
876 newEl->prev = dst;
877 newEl->changed = TRUE;
878 newEl->enabledChanged = TRUE;
879 if (dst == NULL) {
880 object->lights = newEl;
881 } else {
882 dst->next = newEl;
884 dst = newEl;
885 src = src->next;
890 } else {
891 FIXME("Unrecognized state block type %d\n", Type);
894 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
895 return WINED3D_OK;
899 /* ************************************
900 MSDN:
901 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
903 Discard
904 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
906 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.
908 ******************************** */
910 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) {
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
913 unsigned int pow2Width, pow2Height;
914 unsigned int Size = 1;
915 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
916 TRACE("(%p) Create surface\n",This);
918 /** FIXME: Check ranges on the inputs are valid
919 * MSDN
920 * MultisampleQuality
921 * [in] Quality level. The valid range is between zero and one less than the level
922 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
923 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
924 * values of paired render targets, depth stencil surfaces, and the MultiSample type
925 * must all match.
926 *******************************/
930 * TODO: Discard MSDN
931 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
933 * If this flag is set, the contents of the depth stencil buffer will be
934 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
935 * with a different depth surface.
937 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
938 ***************************/
940 if(MultisampleQuality < 0) {
941 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
942 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
945 if(MultisampleQuality > 0) {
946 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
947 MultisampleQuality=0;
950 /** FIXME: Check that the format is supported
951 * by the device.
952 *******************************/
954 /* Non-power2 support */
956 /* Find the nearest pow2 match */
957 pow2Width = pow2Height = 1;
958 while (pow2Width < Width) pow2Width <<= 1;
959 while (pow2Height < Height) pow2Height <<= 1;
961 if (pow2Width > Width || pow2Height > Height) {
962 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
963 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
964 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
965 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
966 This, Width, Height);
967 return WINED3DERR_NOTAVAILABLE;
971 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
972 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
973 * space!
974 *********************************/
975 if (WINED3DFMT_UNKNOWN == Format) {
976 Size = 0;
977 } else if (Format == WINED3DFMT_DXT1) {
978 /* DXT1 is half byte per pixel */
979 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
981 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
982 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
983 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
984 } else {
985 Size = (pow2Width * tableEntry->bpp) * pow2Height;
988 /** Create and initialise the surface resource **/
989 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
990 /* "Standalone" surface */
991 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
993 object->currentDesc.Width = Width;
994 object->currentDesc.Height = Height;
995 object->currentDesc.MultiSampleType = MultiSample;
996 object->currentDesc.MultiSampleQuality = MultisampleQuality;
998 /* Setup some glformat defaults */
999 object->glDescription.glFormat = tableEntry->glFormat;
1000 object->glDescription.glFormatInternal = tableEntry->glInternal;
1001 object->glDescription.glType = tableEntry->glType;
1003 object->glDescription.textureName = 0;
1004 object->glDescription.level = Level;
1005 object->glDescription.target = GL_TEXTURE_2D;
1007 /* Internal data */
1008 object->pow2Width = pow2Width;
1009 object->pow2Height = pow2Height;
1011 /* Flags */
1012 object->Flags = 0; /* We start without flags set */
1013 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1014 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1015 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1016 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1019 if (WINED3DFMT_UNKNOWN != Format) {
1020 object->bytesPerPixel = tableEntry->bpp;
1021 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1022 } else {
1023 object->bytesPerPixel = 0;
1024 object->pow2Size = 0;
1027 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1029 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1031 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1032 * this function is too deap to need to care about things like this.
1033 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1034 * ****************************************/
1035 switch(Pool) {
1036 case WINED3DPOOL_SCRATCH:
1037 if(Lockable == FALSE)
1038 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1039 which are mutually exclusive, setting lockable to true\n");
1040 Lockable = TRUE;
1041 break;
1042 case WINED3DPOOL_SYSTEMMEM:
1043 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1044 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1045 case WINED3DPOOL_MANAGED:
1046 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1047 Usage of DYNAMIC which are mutually exclusive, not doing \
1048 anything just telling you.\n");
1049 break;
1050 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1051 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1052 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1053 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1054 break;
1055 default:
1056 FIXME("(%p) Unknown pool %d\n", This, Pool);
1057 break;
1060 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1061 FIXME("Trying to create a render target that isn't in the default pool\n");
1064 /* mark the texture as dirty so that it get's loaded first time around*/
1065 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1066 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1067 This, Width, Height, Format, debug_d3dformat(Format),
1068 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1070 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1071 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1072 This->ddraw_primary = (IWineD3DSurface *) object;
1074 /* Look at the implementation and set the correct Vtable */
1075 switch(Impl) {
1076 case SURFACE_OPENGL:
1077 /* Nothing to do, it's set already */
1078 break;
1080 case SURFACE_GDI:
1081 object->lpVtbl = &IWineGDISurface_Vtbl;
1082 break;
1084 default:
1085 /* To be sure to catch this */
1086 ERR("Unknown requested surface implementation %d!\n", Impl);
1087 IWineD3DSurface_Release((IWineD3DSurface *) object);
1088 return WINED3DERR_INVALIDCALL;
1091 /* Call the private setup routine */
1092 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1096 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1097 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1098 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1099 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1102 IWineD3DTextureImpl *object;
1103 unsigned int i;
1104 UINT tmpW;
1105 UINT tmpH;
1106 HRESULT hr;
1107 unsigned int pow2Width = Width;
1108 unsigned int pow2Height = Height;
1111 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1113 /* TODO: It should only be possible to create textures for formats
1114 that are reported as supported */
1115 if (WINED3DFMT_UNKNOWN >= Format) {
1116 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1117 return WINED3DERR_INVALIDCALL;
1120 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1121 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1122 object->width = Width;
1123 object->height = Height;
1125 /** Non-power2 support **/
1126 /* Find the nearest pow2 match */
1127 pow2Width = pow2Height = 1;
1128 while (pow2Width < Width) pow2Width <<= 1;
1129 while (pow2Height < Height) pow2Height <<= 1;
1131 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1132 /* Precalculated scaling for 'faked' non power of two texture coords */
1133 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1134 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1135 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1137 /* Calculate levels for mip mapping */
1138 if (Levels == 0) {
1139 TRACE("calculating levels %d\n", object->baseTexture.levels);
1140 object->baseTexture.levels++;
1141 tmpW = Width;
1142 tmpH = Height;
1143 while (tmpW > 1 || tmpH > 1) {
1144 tmpW = max(1, tmpW >> 1);
1145 tmpH = max(1, tmpH >> 1);
1146 object->baseTexture.levels++;
1148 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1151 /* Generate all the surfaces */
1152 tmpW = Width;
1153 tmpH = Height;
1154 for (i = 0; i < object->baseTexture.levels; i++)
1156 /* use the callback to create the texture surface */
1157 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1158 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1159 FIXME("Failed to create surface %p\n", object);
1160 /* clean up */
1161 object->surfaces[i] = NULL;
1162 IWineD3DTexture_Release((IWineD3DTexture *)object);
1164 *ppTexture = NULL;
1165 return hr;
1168 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1169 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1170 /* calculate the next mipmap level */
1171 tmpW = max(1, tmpW >> 1);
1172 tmpH = max(1, tmpH >> 1);
1175 TRACE("(%p) : Created texture %p\n", This, object);
1176 return WINED3D_OK;
1179 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1180 UINT Width, UINT Height, UINT Depth,
1181 UINT Levels, DWORD Usage,
1182 WINED3DFORMAT Format, WINED3DPOOL Pool,
1183 IWineD3DVolumeTexture **ppVolumeTexture,
1184 HANDLE *pSharedHandle, IUnknown *parent,
1185 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1188 IWineD3DVolumeTextureImpl *object;
1189 unsigned int i;
1190 UINT tmpW;
1191 UINT tmpH;
1192 UINT tmpD;
1194 /* TODO: It should only be possible to create textures for formats
1195 that are reported as supported */
1196 if (WINED3DFMT_UNKNOWN >= Format) {
1197 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1198 return WINED3DERR_INVALIDCALL;
1201 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1202 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1204 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1205 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1207 object->width = Width;
1208 object->height = Height;
1209 object->depth = Depth;
1211 /* Calculate levels for mip mapping */
1212 if (Levels == 0) {
1213 object->baseTexture.levels++;
1214 tmpW = Width;
1215 tmpH = Height;
1216 tmpD = Depth;
1217 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1218 tmpW = max(1, tmpW >> 1);
1219 tmpH = max(1, tmpH >> 1);
1220 tmpD = max(1, tmpD >> 1);
1221 object->baseTexture.levels++;
1223 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1226 /* Generate all the surfaces */
1227 tmpW = Width;
1228 tmpH = Height;
1229 tmpD = Depth;
1231 for (i = 0; i < object->baseTexture.levels; i++)
1233 /* Create the volume */
1234 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1235 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1237 /* Set it's container to this object */
1238 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1240 /* calcualte the next mipmap level */
1241 tmpW = max(1, tmpW >> 1);
1242 tmpH = max(1, tmpH >> 1);
1243 tmpD = max(1, tmpD >> 1);
1246 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1247 TRACE("(%p) : Created volume texture %p\n", This, object);
1248 return WINED3D_OK;
1251 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1252 UINT Width, UINT Height, UINT Depth,
1253 DWORD Usage,
1254 WINED3DFORMAT Format, WINED3DPOOL Pool,
1255 IWineD3DVolume** ppVolume,
1256 HANDLE* pSharedHandle, IUnknown *parent) {
1258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1259 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1260 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1262 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1264 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1265 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1267 object->currentDesc.Width = Width;
1268 object->currentDesc.Height = Height;
1269 object->currentDesc.Depth = Depth;
1270 object->bytesPerPixel = formatDesc->bpp;
1272 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1273 object->lockable = TRUE;
1274 object->locked = FALSE;
1275 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1276 object->dirty = TRUE;
1278 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1281 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1282 UINT Levels, DWORD Usage,
1283 WINED3DFORMAT Format, WINED3DPOOL Pool,
1284 IWineD3DCubeTexture **ppCubeTexture,
1285 HANDLE *pSharedHandle, IUnknown *parent,
1286 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1289 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1290 unsigned int i, j;
1291 UINT tmpW;
1292 HRESULT hr;
1293 unsigned int pow2EdgeLength = EdgeLength;
1295 /* TODO: It should only be possible to create textures for formats
1296 that are reported as supported */
1297 if (WINED3DFMT_UNKNOWN >= Format) {
1298 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1299 return WINED3DERR_INVALIDCALL;
1302 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1303 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1305 TRACE("(%p) Create Cube Texture\n", This);
1307 /** Non-power2 support **/
1309 /* Find the nearest pow2 match */
1310 pow2EdgeLength = 1;
1311 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1313 object->edgeLength = EdgeLength;
1314 /* TODO: support for native non-power 2 */
1315 /* Precalculated scaling for 'faked' non power of two texture coords */
1316 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1318 /* Calculate levels for mip mapping */
1319 if (Levels == 0) {
1320 object->baseTexture.levels++;
1321 tmpW = EdgeLength;
1322 while (tmpW > 1) {
1323 tmpW = max(1, tmpW >> 1);
1324 object->baseTexture.levels++;
1326 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1329 /* Generate all the surfaces */
1330 tmpW = EdgeLength;
1331 for (i = 0; i < object->baseTexture.levels; i++) {
1333 /* Create the 6 faces */
1334 for (j = 0; j < 6; j++) {
1336 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1337 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1339 if(hr!= WINED3D_OK) {
1340 /* clean up */
1341 int k;
1342 int l;
1343 for (l = 0; l < j; l++) {
1344 IWineD3DSurface_Release(object->surfaces[j][i]);
1346 for (k = 0; k < i; k++) {
1347 for (l = 0; l < 6; l++) {
1348 IWineD3DSurface_Release(object->surfaces[l][j]);
1352 FIXME("(%p) Failed to create surface\n",object);
1353 HeapFree(GetProcessHeap(),0,object);
1354 *ppCubeTexture = NULL;
1355 return hr;
1357 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1358 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1360 tmpW = max(1, tmpW >> 1);
1363 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1364 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1365 return WINED3D_OK;
1368 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1370 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1372 if (NULL == ppQuery) {
1373 /* Just a check to see if we support this type of query */
1374 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1375 switch(Type) {
1376 case WINED3DQUERYTYPE_OCCLUSION:
1377 TRACE("(%p) occlusion query\n", This);
1378 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1379 hr = WINED3D_OK;
1380 else
1381 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1382 break;
1383 case WINED3DQUERYTYPE_VCACHE:
1384 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1385 case WINED3DQUERYTYPE_VERTEXSTATS:
1386 case WINED3DQUERYTYPE_EVENT:
1387 case WINED3DQUERYTYPE_TIMESTAMP:
1388 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1389 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1390 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1391 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1392 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1393 case WINED3DQUERYTYPE_PIXELTIMINGS:
1394 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1395 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1396 default:
1397 FIXME("(%p) Unhandled query type %d\n", This, Type);
1399 return hr;
1402 D3DCREATEOBJECTINSTANCE(object, Query)
1403 object->type = Type;
1404 /* allocated the 'extended' data based on the type of query requested */
1405 switch(Type){
1406 case D3DQUERYTYPE_OCCLUSION:
1407 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1408 TRACE("(%p) Allocating data for an occlusion query\n", This);
1409 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1410 break;
1412 case D3DQUERYTYPE_VCACHE:
1413 case D3DQUERYTYPE_RESOURCEMANAGER:
1414 case D3DQUERYTYPE_VERTEXSTATS:
1415 case D3DQUERYTYPE_EVENT:
1416 case D3DQUERYTYPE_TIMESTAMP:
1417 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1418 case D3DQUERYTYPE_TIMESTAMPFREQ:
1419 case D3DQUERYTYPE_PIPELINETIMINGS:
1420 case D3DQUERYTYPE_INTERFACETIMINGS:
1421 case D3DQUERYTYPE_VERTEXTIMINGS:
1422 case D3DQUERYTYPE_PIXELTIMINGS:
1423 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1424 case D3DQUERYTYPE_CACHEUTILIZATION:
1425 default:
1426 object->extendedData = 0;
1427 FIXME("(%p) Unhandled query type %d\n",This , Type);
1429 TRACE("(%p) : Created Query %p\n", This, object);
1430 return WINED3D_OK;
1433 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1434 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1435 IUnknown* parent,
1436 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1437 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1440 HDC hDc;
1441 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1442 int num;
1443 XVisualInfo template;
1444 GLXContext oldContext;
1445 Drawable oldDrawable;
1446 HRESULT hr = WINED3D_OK;
1448 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1450 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1451 * does a device hold a reference to a swap chain giving them a lifetime of the device
1452 * or does the swap chain notify the device of its destruction.
1453 *******************************/
1455 /* Check the params */
1456 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1457 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1458 return WINED3DERR_INVALIDCALL;
1459 } else if (*pPresentationParameters->BackBufferCount > 1) {
1460 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");
1463 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1465 /*********************
1466 * Lookup the window Handle and the relating X window handle
1467 ********************/
1469 /* Setup hwnd we are using, plus which display this equates to */
1470 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1471 if (!object->win_handle) {
1472 object->win_handle = This->createParms.hFocusWindow;
1475 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1476 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1477 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1478 return WINED3DERR_NOTAVAILABLE;
1480 hDc = GetDC(object->win_handle);
1481 object->display = get_display(hDc);
1482 ReleaseDC(object->win_handle, hDc);
1483 TRACE("Using a display of %p %p\n", object->display, hDc);
1485 if (NULL == object->display || NULL == hDc) {
1486 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1487 return WINED3DERR_NOTAVAILABLE;
1490 if (object->win == 0) {
1491 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1492 return WINED3DERR_NOTAVAILABLE;
1495 * Create an opengl context for the display visual
1496 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1497 * use different properties after that point in time. FIXME: How to handle when requested format
1498 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1499 * it chooses is identical to the one already being used!
1500 **********************************/
1502 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1503 ENTER_GL();
1505 /* Create a new context for this swapchain */
1506 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1507 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1508 (or the best possible if none is requested) */
1509 TRACE("Found x visual ID : %ld\n", template.visualid);
1511 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1512 if (NULL == object->visInfo) {
1513 ERR("cannot really get XVisual\n");
1514 LEAVE_GL();
1515 return WINED3DERR_NOTAVAILABLE;
1516 } else {
1517 int n, value;
1518 /* Write out some debug info about the visual/s */
1519 TRACE("Using x visual ID : %ld\n", template.visualid);
1520 TRACE(" visual info: %p\n", object->visInfo);
1521 TRACE(" num items : %d\n", num);
1522 for (n = 0;n < num; n++) {
1523 TRACE("=====item=====: %d\n", n + 1);
1524 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1525 TRACE(" screen : %d\n", object->visInfo[n].screen);
1526 TRACE(" depth : %u\n", object->visInfo[n].depth);
1527 TRACE(" class : %d\n", object->visInfo[n].class);
1528 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1529 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1530 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1531 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1532 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1533 /* log some extra glx info */
1534 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1535 TRACE(" gl_aux_buffers : %d\n", value);
1536 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1537 TRACE(" gl_buffer_size : %d\n", value);
1538 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1539 TRACE(" gl_red_size : %d\n", value);
1540 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1541 TRACE(" gl_green_size : %d\n", value);
1542 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1543 TRACE(" gl_blue_size : %d\n", value);
1544 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1545 TRACE(" gl_alpha_size : %d\n", value);
1546 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1547 TRACE(" gl_depth_size : %d\n", value);
1548 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1549 TRACE(" gl_stencil_size : %d\n", value);
1551 /* Now choose a simila visual ID*/
1553 #ifdef USE_CONTEXT_MANAGER
1555 /** TODO: use a context mamager **/
1556 #endif
1559 IWineD3DSwapChain *implSwapChain;
1560 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1561 /* The first time around we create the context that is shared with all other swapchains and render targets */
1562 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1563 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1564 } else {
1566 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1567 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1568 /* and create a new context with the implicit swapchains context as the shared context */
1569 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1570 IWineD3DSwapChain_Release(implSwapChain);
1574 /* Cleanup */
1575 XFree(object->visInfo);
1576 object->visInfo = NULL;
1578 LEAVE_GL();
1580 if (!object->glCtx) {
1581 ERR("Failed to create GLX context\n");
1582 return WINED3DERR_NOTAVAILABLE;
1583 } else {
1584 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1585 object->win_handle, object->glCtx, object->win, object->visInfo);
1588 /*********************
1589 * Windowed / Fullscreen
1590 *******************/
1593 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1594 * so we should really check to see if there is a fullscreen swapchain already
1595 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1596 **************************************/
1598 if (!*(pPresentationParameters->Windowed)) {
1600 DEVMODEW devmode;
1601 HDC hdc;
1602 int bpp = 0;
1604 /* Get info on the current display setup */
1605 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1606 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1607 DeleteDC(hdc);
1609 /* Change the display settings */
1610 memset(&devmode, 0, sizeof(DEVMODEW));
1611 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1612 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1613 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1614 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1615 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1616 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1618 /* Make popup window */
1619 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1620 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1621 *(pPresentationParameters->BackBufferWidth),
1622 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1624 /* For GetDisplayMode */
1625 This->ddraw_width = devmode.dmPelsWidth;
1626 This->ddraw_height = devmode.dmPelsHeight;
1627 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1631 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1632 * then the corresponding dimension of the client area of the hDeviceWindow
1633 * (or the focus window, if hDeviceWindow is NULL) is taken.
1634 **********************/
1636 if (*(pPresentationParameters->Windowed) &&
1637 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1638 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1640 RECT Rect;
1641 GetClientRect(object->win_handle, &Rect);
1643 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1644 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1645 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1647 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1648 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1649 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1653 /*********************
1654 * finish off parameter initialization
1655 *******************/
1657 /* Put the correct figures in the presentation parameters */
1658 TRACE("Coppying accross presentaion paraneters\n");
1659 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1660 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1661 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1662 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1663 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1664 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1665 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1666 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1667 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1668 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1669 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1670 object->presentParms.Flags = *(pPresentationParameters->Flags);
1671 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1672 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1675 /*********************
1676 * Create the back, front and stencil buffers
1677 *******************/
1679 TRACE("calling rendertarget CB\n");
1680 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1681 object->presentParms.BackBufferWidth,
1682 object->presentParms.BackBufferHeight,
1683 object->presentParms.BackBufferFormat,
1684 object->presentParms.MultiSampleType,
1685 object->presentParms.MultiSampleQuality,
1686 TRUE /* Lockable */,
1687 &object->frontBuffer,
1688 NULL /* pShared (always null)*/);
1689 if (object->frontBuffer != NULL)
1690 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1692 if(object->presentParms.BackBufferCount > 0) {
1693 int i;
1695 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1696 if(!object->backBuffer) {
1697 ERR("Out of memory\n");
1699 if (object->frontBuffer) {
1700 IUnknown *bufferParent;
1701 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1702 IUnknown_Release(bufferParent); /* once for the get parent */
1703 if (IUnknown_Release(bufferParent) > 0) {
1704 FIXME("(%p) Something's still holding the front buffer\n",This);
1707 HeapFree(GetProcessHeap(), 0, object);
1708 return E_OUTOFMEMORY;
1711 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1712 TRACE("calling rendertarget CB\n");
1713 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1714 object->presentParms.BackBufferWidth,
1715 object->presentParms.BackBufferHeight,
1716 object->presentParms.BackBufferFormat,
1717 object->presentParms.MultiSampleType,
1718 object->presentParms.MultiSampleQuality,
1719 TRUE /* Lockable */,
1720 &object->backBuffer[i],
1721 NULL /* pShared (always null)*/);
1722 if(hr == WINED3D_OK && object->backBuffer[i]) {
1723 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1724 } else {
1725 break;
1728 } else {
1729 object->backBuffer = NULL;
1732 if (object->backBuffer != NULL) {
1733 ENTER_GL();
1734 glDrawBuffer(GL_BACK);
1735 checkGLcall("glDrawBuffer(GL_BACK)");
1736 LEAVE_GL();
1737 } else {
1738 /* Single buffering - draw to front buffer */
1739 ENTER_GL();
1740 glDrawBuffer(GL_FRONT);
1741 checkGLcall("glDrawBuffer(GL_FRONT)");
1742 LEAVE_GL();
1745 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1746 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1747 TRACE("Creating depth stencil buffer\n");
1748 if (This->depthStencilBuffer == NULL ) {
1749 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1750 object->presentParms.BackBufferWidth,
1751 object->presentParms.BackBufferHeight,
1752 object->presentParms.AutoDepthStencilFormat,
1753 object->presentParms.MultiSampleType,
1754 object->presentParms.MultiSampleQuality,
1755 FALSE /* FIXME: Discard */,
1756 &This->depthStencilBuffer,
1757 NULL /* pShared (always null)*/ );
1758 if (This->depthStencilBuffer != NULL)
1759 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1762 /** TODO: A check on width, height and multisample types
1763 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1764 ****************************/
1765 object->wantsDepthStencilBuffer = TRUE;
1766 } else {
1767 object->wantsDepthStencilBuffer = FALSE;
1770 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1773 /*********************
1774 * init the default renderTarget management
1775 *******************/
1776 object->drawable = object->win;
1777 object->render_ctx = object->glCtx;
1779 if (hr == WINED3D_OK) {
1780 /*********************
1781 * Setup some defaults and clear down the buffers
1782 *******************/
1783 ENTER_GL();
1784 /** save current context and drawable **/
1785 oldContext = glXGetCurrentContext();
1786 oldDrawable = glXGetCurrentDrawable();
1788 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1789 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1790 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1792 checkGLcall("glXMakeCurrent");
1794 TRACE("Setting up the screen\n");
1795 /* Clear the screen */
1796 glClearColor(1.0, 0.0, 0.0, 0.0);
1797 checkGLcall("glClearColor");
1798 glClearIndex(0);
1799 glClearDepth(1);
1800 glClearStencil(0xffff);
1802 checkGLcall("glClear");
1804 glColor3f(1.0, 1.0, 1.0);
1805 checkGLcall("glColor3f");
1807 glEnable(GL_LIGHTING);
1808 checkGLcall("glEnable");
1810 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1811 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1813 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1814 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1816 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1817 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1819 /* switch back to the original context (if there was one)*/
1820 if (This->swapchains) {
1821 /** TODO: restore the context and drawable **/
1822 glXMakeCurrent(object->display, oldDrawable, oldContext);
1825 LEAVE_GL();
1827 TRACE("Set swapchain to %p\n", object);
1828 } else { /* something went wrong so clean up */
1829 IUnknown* bufferParent;
1830 if (object->frontBuffer) {
1832 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1833 IUnknown_Release(bufferParent); /* once for the get parent */
1834 if (IUnknown_Release(bufferParent) > 0) {
1835 FIXME("(%p) Something's still holding the front buffer\n",This);
1838 if (object->backBuffer) {
1839 int i;
1840 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1841 if(object->backBuffer[i]) {
1842 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1843 IUnknown_Release(bufferParent); /* once for the get parent */
1844 if (IUnknown_Release(bufferParent) > 0) {
1845 FIXME("(%p) Something's still holding the back buffer\n",This);
1849 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1850 object->backBuffer = NULL;
1852 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1853 /* Clean up the context */
1854 /* check that we are the current context first (we shouldn't be though!) */
1855 if (object->glCtx != 0) {
1856 if(glXGetCurrentContext() == object->glCtx) {
1857 glXMakeCurrent(object->display, None, NULL);
1859 glXDestroyContext(object->display, object->glCtx);
1861 HeapFree(GetProcessHeap(), 0, object);
1865 return hr;
1868 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1869 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1871 TRACE("(%p)\n", This);
1873 return This->NumberOfSwapChains;
1876 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1878 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1880 if(iSwapChain < This->NumberOfSwapChains) {
1881 *pSwapChain = This->swapchains[iSwapChain];
1882 IWineD3DSwapChain_AddRef(*pSwapChain);
1883 TRACE("(%p) returning %p\n", This, *pSwapChain);
1884 return WINED3D_OK;
1885 } else {
1886 TRACE("Swapchain out of range\n");
1887 *pSwapChain = NULL;
1888 return WINED3DERR_INVALIDCALL;
1892 /*****
1893 * Vertex Declaration
1894 *****/
1895 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1897 IWineD3DVertexDeclarationImpl *object = NULL;
1898 HRESULT hr = WINED3D_OK;
1899 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1900 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1901 object->allFVF = 0;
1903 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1905 return hr;
1908 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1909 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1911 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1912 HRESULT hr = WINED3D_OK;
1913 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1914 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1916 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1918 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1919 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1920 if (pDeclaration != NULL) {
1921 IWineD3DVertexDeclaration *vertexDeclaration;
1922 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1923 if (WINED3D_OK == hr) {
1924 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1925 object->vertexDeclaration = vertexDeclaration;
1926 } else {
1927 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1928 IWineD3DVertexShader_Release(*ppVertexShader);
1929 return WINED3DERR_INVALIDCALL;
1933 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1935 if (WINED3D_OK != hr) {
1936 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1937 IWineD3DVertexShader_Release(*ppVertexShader);
1938 return WINED3DERR_INVALIDCALL;
1941 #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. */
1942 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1943 /* Foo */
1944 } else {
1945 /* Bar */
1948 #endif
1950 return WINED3D_OK;
1953 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1955 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1956 HRESULT hr = WINED3D_OK;
1958 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1959 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1960 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1961 if (WINED3D_OK == hr) {
1962 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1963 } else {
1964 WARN("(%p) : Failed to create pixel shader\n", This);
1967 return hr;
1970 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1972 IWineD3DPaletteImpl *object;
1973 HRESULT hr;
1974 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1976 /* Create the new object */
1977 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1978 if(!object) {
1979 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1980 return E_OUTOFMEMORY;
1983 object->lpVtbl = &IWineD3DPalette_Vtbl;
1984 object->ref = 1;
1985 object->Flags = Flags;
1986 object->parent = Parent;
1987 object->wineD3DDevice = This;
1988 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1990 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1992 if(!object->hpal) {
1993 HeapFree( GetProcessHeap(), 0, object);
1994 return E_OUTOFMEMORY;
1997 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1998 if(FAILED(hr)) {
1999 IWineD3DPalette_Release((IWineD3DPalette *) object);
2000 return hr;
2003 *Palette = (IWineD3DPalette *) object;
2005 return WINED3D_OK;
2008 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2010 IWineD3DSwapChainImpl *swapchain;
2012 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2013 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2015 /* TODO: Test if OpenGL is compiled in and loaded */
2017 /* Setup the implicit swapchain */
2018 TRACE("Creating implicit swapchain\n");
2019 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2020 WARN("Failed to create implicit swapchain\n");
2021 return WINED3DERR_INVALIDCALL;
2024 This->NumberOfSwapChains = 1;
2025 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2026 if(!This->swapchains) {
2027 ERR("Out of memory!\n");
2028 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2029 return E_OUTOFMEMORY;
2031 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2033 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2034 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2035 This->renderTarget = swapchain->backBuffer[0];
2037 else {
2038 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2039 This->renderTarget = swapchain->frontBuffer;
2041 IWineD3DSurface_AddRef(This->renderTarget);
2042 /* Depth Stencil support */
2043 This->stencilBufferTarget = This->depthStencilBuffer;
2044 if (NULL != This->stencilBufferTarget) {
2045 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2048 /* Set up some starting GL setup */
2049 ENTER_GL();
2051 * Initialize openGL extension related variables
2052 * with Default values
2055 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( &((IWineD3DImpl *) This->wineD3D)->gl_info, swapchain->display);
2056 /* Setup all the devices defaults */
2057 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2058 #if 0
2059 IWineD3DImpl_CheckGraphicsMemory();
2060 #endif
2061 LEAVE_GL();
2063 /* Initialize our list of GLSL programs */
2064 list_init(&This->glsl_shader_progs);
2066 { /* Set a default viewport */
2067 D3DVIEWPORT9 vp;
2068 vp.X = 0;
2069 vp.Y = 0;
2070 vp.Width = *(pPresentationParameters->BackBufferWidth);
2071 vp.Height = *(pPresentationParameters->BackBufferHeight);
2072 vp.MinZ = 0.0f;
2073 vp.MaxZ = 1.0f;
2074 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2077 /* Initialize the current view state */
2078 This->modelview_valid = 1;
2079 This->proj_valid = 0;
2080 This->view_ident = 1;
2081 This->last_was_rhw = 0;
2082 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2083 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2085 /* Clear the screen */
2086 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2088 This->d3d_initialized = TRUE;
2089 return WINED3D_OK;
2092 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2094 int sampler;
2095 IUnknown* stencilBufferParent;
2096 IUnknown* swapChainParent;
2097 uint i;
2098 TRACE("(%p)\n", This);
2100 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2102 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2103 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2106 /* Release the buffers (with sanity checks)*/
2107 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2108 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2109 if(This->depthStencilBuffer != This->stencilBufferTarget)
2110 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2112 This->stencilBufferTarget = NULL;
2114 TRACE("Releasing the render target at %p\n", This->renderTarget);
2115 if(IWineD3DSurface_Release(This->renderTarget) >0){
2116 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2118 TRACE("Setting rendertarget to NULL\n");
2119 This->renderTarget = NULL;
2121 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2122 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2123 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2124 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2126 This->depthStencilBuffer = NULL;
2128 for(i=0; i < This->NumberOfSwapChains; i++) {
2129 TRACE("Releasing the implicit swapchain %d\n", i);
2130 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2131 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2132 IUnknown_Release(swapChainParent); /* once for the get parent */
2133 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2134 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2138 HeapFree(GetProcessHeap(), 0, This->swapchains);
2139 This->swapchains = NULL;
2140 This->NumberOfSwapChains = 0;
2142 This->d3d_initialized = FALSE;
2143 return WINED3D_OK;
2146 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2149 DEVMODEW DevModeW;
2150 int i;
2151 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2153 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2155 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2156 /* Ignore some modes if a description was passed */
2157 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2158 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2159 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2161 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2163 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2164 return D3D_OK;
2167 return D3D_OK;
2170 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2171 DEVMODEW devmode;
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2173 LONG ret;
2174 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2176 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2178 /* Resize the screen even without a window:
2179 * The app could have unset it with SetCooperativeLevel, but not called
2180 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2181 * but we don't have any hwnd
2184 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2185 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2186 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2187 devmode.dmPelsWidth = pMode->Width;
2188 devmode.dmPelsHeight = pMode->Height;
2190 devmode.dmDisplayFrequency = pMode->RefreshRate;
2191 if (pMode->RefreshRate != 0) {
2192 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2195 /* Only change the mode if necessary */
2196 if( (This->ddraw_width == pMode->Width) &&
2197 (This->ddraw_height == pMode->Height) &&
2198 (This->ddraw_format == pMode->Format) &&
2199 (pMode->RefreshRate == 0) ) {
2200 return D3D_OK;
2203 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2204 if (ret != DISP_CHANGE_SUCCESSFUL) {
2205 if(devmode.dmDisplayFrequency != 0) {
2206 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2207 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2208 devmode.dmDisplayFrequency = 0;
2209 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2211 if(ret != DISP_CHANGE_SUCCESSFUL) {
2212 return DDERR_INVALIDMODE;
2216 /* Store the new values */
2217 This->ddraw_width = pMode->Width;
2218 This->ddraw_height = pMode->Height;
2219 This->ddraw_format = pMode->Format;
2221 /* Only do this with a window of course */
2222 if(This->ddraw_window)
2223 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2225 return WINED3D_OK;
2228 static HRESULT WINAPI IWineD3DDeviceImpl_EnumZBufferFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2230 HRESULT ret;
2231 int i = 0;
2232 WINED3DFORMAT FormatList[] = {
2233 WINED3DFMT_D16,
2234 WINED3DFMT_D32,
2235 WINED3DFMT_D24X4S4,
2236 WINED3DFMT_D24S8,
2237 WINED3DFMT_D24X8,
2238 WINED3DFMT_D15S1,
2239 WINED3DFMT_UNKNOWN /* Terminate the list */
2242 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2244 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2245 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2246 ret = Callback((IUnknown *) This, FormatList[i], Context);
2247 if(ret != DDENUMRET_OK) {
2248 TRACE("Enumeration cancelled by Application\n");
2249 return WINED3D_OK;
2251 i++;
2254 TRACE("End of Enumeration\n");
2256 return WINED3D_OK;
2259 static HRESULT WINAPI IWineD3DDeviceImpl_EnumTextureFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2261 HRESULT ret;
2262 int i = 0;
2264 /* From old ddraw:
2265 * WINED3DFMT_A1R5G5B5 needs to be the first 16 bit format, as some dumb apps depend on this
2267 * Do not enumerate RGBA pixel formats: "some games choose the first 16 bit texture format
2268 * with alpha they find enumerated, others the last one. And both want to have the ARGB one."
2269 * But WineD3D doesn't support RGBA formats anyway...
2272 WINED3DFORMAT FormatList[] = {
2273 /* 32 bit */
2274 WINED3DFMT_A8R8G8B8,
2275 WINED3DFMT_X8R8G8B8,
2276 /* 24 bit */
2277 WINED3DFMT_R8G8B8,
2278 /* 16 Bit */
2279 WINED3DFMT_A1R5G5B5,
2280 WINED3DFMT_A4R4G4B4,
2281 WINED3DFMT_R5G6B5,
2282 WINED3DFMT_X1R5G5B5,
2283 /* 8 Bit */
2284 WINED3DFMT_R3G3B2,
2285 WINED3DFMT_P8,
2286 /* FOURCC codes */
2287 WINED3DFMT_DXT1,
2288 WINED3DFMT_DXT3,
2289 WINED3DFMT_DXT5,
2290 /* Terminate the list */
2291 WINED3DFMT_UNKNOWN
2294 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2296 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2297 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2298 ret = Callback((IUnknown *) This, FormatList[i], Context);
2299 if(ret != DDENUMRET_OK) {
2300 TRACE("Enumeration cancelled by Application\n");
2301 return WINED3D_OK;
2303 i++;
2306 TRACE("End of Enumeration\n");
2308 return WINED3D_OK;
2311 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 *ppD3D= This->wineD3D;
2314 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2315 IWineD3D_AddRef(*ppD3D);
2316 return WINED3D_OK;
2319 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2320 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2321 * Into the video ram as possible and seeing how many fit
2322 * you can also get the correct initial value from via X and ATI's driver
2323 *******************/
2324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2325 static BOOL showfixmes = TRUE;
2326 if (showfixmes) {
2327 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2328 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2329 showfixmes = FALSE;
2331 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2332 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2333 /* videomemory is simulated videomemory + AGP memory left */
2334 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2339 /*****
2340 * Get / Set FVF
2341 *****/
2342 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2344 HRESULT hr = WINED3D_OK;
2346 /* Update the current state block */
2347 This->updateStateBlock->fvf = fvf;
2348 This->updateStateBlock->changed.fvf = TRUE;
2349 This->updateStateBlock->set.fvf = TRUE;
2351 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2352 return hr;
2356 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2358 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2359 *pfvf = This->stateBlock->fvf;
2360 return WINED3D_OK;
2363 /*****
2364 * Get / Set Stream Source
2365 *****/
2366 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 IWineD3DVertexBuffer *oldSrc;
2370 /**TODO: instance and index data, see
2371 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2373 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2374 **************/
2376 /* D3d9 only, but shouldn't hurt d3d8 */
2377 UINT streamFlags;
2379 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2380 if (streamFlags) {
2381 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2382 FIXME("stream index data not supported\n");
2384 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2385 FIXME("stream instance data not supported\n");
2389 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2391 if (StreamNumber >= MAX_STREAMS) {
2392 WARN("Stream out of range %d\n", StreamNumber);
2393 return WINED3DERR_INVALIDCALL;
2396 oldSrc = This->stateBlock->streamSource[StreamNumber];
2397 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2399 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2400 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2401 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2402 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2403 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2404 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2406 /* Handle recording of state blocks */
2407 if (This->isRecordingState) {
2408 TRACE("Recording... not performing anything\n");
2409 return WINED3D_OK;
2412 /* Same stream object: no action */
2413 if (oldSrc == pStreamData)
2414 return WINED3D_OK;
2416 /* Need to do a getParent and pass the reffs up */
2417 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2418 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2419 so for now, just count internally */
2420 if (pStreamData != NULL) {
2421 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2422 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2423 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2425 vbImpl->stream = StreamNumber;
2426 vbImpl->Flags |= VBFLAG_STREAM;
2427 IWineD3DVertexBuffer_AddRef(pStreamData);
2429 if (oldSrc != NULL) {
2430 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2431 IWineD3DVertexBuffer_Release(oldSrc);
2434 return WINED3D_OK;
2437 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2439 UINT streamFlags;
2441 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2442 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2445 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2446 if (streamFlags) {
2447 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2448 FIXME("stream index data not supported\n");
2450 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2451 FIXME("stream instance data not supported\n");
2455 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2457 if (StreamNumber >= MAX_STREAMS) {
2458 WARN("Stream out of range %d\n", StreamNumber);
2459 return WINED3DERR_INVALIDCALL;
2461 *pStream = This->stateBlock->streamSource[StreamNumber];
2462 *pStride = This->stateBlock->streamStride[StreamNumber];
2463 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2465 if (*pStream == NULL) {
2466 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2467 return WINED3DERR_INVALIDCALL;
2470 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2471 return WINED3D_OK;
2474 /*Should be quite easy, just an extension of vertexdata
2475 ref...
2476 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2478 The divider is a bit odd though
2480 VertexOffset = StartVertex / Divider * StreamStride +
2481 VertexIndex / Divider * StreamStride + StreamOffset
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2488 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2490 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2491 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2492 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2494 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2495 FIXME("Stream indexing not fully supported\n");
2498 return WINED3D_OK;
2501 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2505 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2507 TRACE("(%p) : returning %d\n", This, *Divider);
2509 return WINED3D_OK;
2512 /*****
2513 * Get / Set & Multiply Transform
2514 *****/
2515 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 /* Most of this routine, comments included copied from ddraw tree initially: */
2519 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2521 /* Handle recording of state blocks */
2522 if (This->isRecordingState) {
2523 TRACE("Recording... not performing anything\n");
2524 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2525 This->updateStateBlock->set.transform[d3dts] = TRUE;
2526 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2527 return WINED3D_OK;
2531 * If the new matrix is the same as the current one,
2532 * we cut off any further processing. this seems to be a reasonable
2533 * optimization because as was noticed, some apps (warcraft3 for example)
2534 * tend towards setting the same matrix repeatedly for some reason.
2536 * From here on we assume that the new matrix is different, wherever it matters.
2538 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2539 TRACE("The app is setting the same matrix over again\n");
2540 return WINED3D_OK;
2541 } else {
2542 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2546 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2547 where ViewMat = Camera space, WorldMat = world space.
2549 In OpenGL, camera and world space is combined into GL_MODELVIEW
2550 matrix. The Projection matrix stay projection matrix.
2553 /* Capture the times we can just ignore the change for now */
2554 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2555 This->modelview_valid = FALSE;
2556 return WINED3D_OK;
2558 } else if (d3dts == D3DTS_PROJECTION) {
2559 This->proj_valid = FALSE;
2560 return WINED3D_OK;
2562 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2563 /* Indexed Vertex Blending Matrices 256 -> 511 */
2564 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2565 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2566 return WINED3D_OK;
2569 /* Now we really are going to have to change a matrix */
2570 ENTER_GL();
2572 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2573 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2574 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2575 unsigned int k;
2577 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2578 * NOTE: We have to reset the positions even if the light/plane is not currently
2579 * enabled, since the call to enable it will not reset the position.
2580 * NOTE2: Apparently texture transforms do NOT need reapplying
2583 PLIGHTINFOEL *lightChain = NULL;
2584 This->modelview_valid = FALSE;
2585 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2587 glMatrixMode(GL_MODELVIEW);
2588 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2589 glPushMatrix();
2590 glLoadMatrixf((float *)lpmatrix);
2591 checkGLcall("glLoadMatrixf(...)");
2593 /* Reset lights */
2594 lightChain = This->stateBlock->lights;
2595 while (lightChain && lightChain->glIndex != -1) {
2596 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2597 checkGLcall("glLightfv posn");
2598 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2599 checkGLcall("glLightfv dirn");
2600 lightChain = lightChain->next;
2603 /* Reset Clipping Planes if clipping is enabled */
2604 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2605 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2606 checkGLcall("glClipPlane");
2608 glPopMatrix();
2610 } else { /* What was requested!?? */
2611 WARN("invalid matrix specified: %i\n", d3dts);
2614 /* Release lock, all done */
2615 LEAVE_GL();
2616 return WINED3D_OK;
2619 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p) : for Transform State %d\n", This, State);
2622 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2623 return WINED3D_OK;
2626 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2627 D3DMATRIX *mat = NULL;
2628 D3DMATRIX temp;
2630 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2631 * below means it will be recorded in a state block change, but it
2632 * works regardless where it is recorded.
2633 * If this is found to be wrong, change to StateBlock.
2635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2636 TRACE("(%p) : For state %u\n", This, State);
2638 if (State < HIGHEST_TRANSFORMSTATE)
2640 mat = &This->updateStateBlock->transforms[State];
2641 } else {
2642 FIXME("Unhandled transform state!!\n");
2645 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2647 /* Apply change via set transform - will reapply to eg. lights this way */
2648 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2651 /*****
2652 * Get / Set Light
2653 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2654 *****/
2655 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2656 you can reference any indexes you want as long as that number max are enabled at any
2657 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2658 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2659 but when recording, just build a chain pretty much of commands to be replayed. */
2661 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2662 float rho;
2663 PLIGHTINFOEL *object, *temp;
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2668 /* If recording state block, just add to end of lights chain */
2669 if (This->isRecordingState) {
2670 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2671 if (NULL == object) {
2672 return WINED3DERR_OUTOFVIDEOMEMORY;
2674 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2675 object->OriginalIndex = Index;
2676 object->glIndex = -1;
2677 object->changed = TRUE;
2679 /* Add to the END of the chain of lights changes to be replayed */
2680 if (This->updateStateBlock->lights == NULL) {
2681 This->updateStateBlock->lights = object;
2682 } else {
2683 temp = This->updateStateBlock->lights;
2684 while (temp->next != NULL) temp=temp->next;
2685 temp->next = object;
2687 TRACE("Recording... not performing anything more\n");
2688 return WINED3D_OK;
2691 /* Ok, not recording any longer so do real work */
2692 object = This->stateBlock->lights;
2693 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2695 /* If we didn't find it in the list of lights, time to add it */
2696 if (object == NULL) {
2697 PLIGHTINFOEL *insertAt,*prevPos;
2699 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2700 if (NULL == object) {
2701 return WINED3DERR_OUTOFVIDEOMEMORY;
2703 object->OriginalIndex = Index;
2704 object->glIndex = -1;
2706 /* Add it to the front of list with the idea that lights will be changed as needed
2707 BUT after any lights currently assigned GL indexes */
2708 insertAt = This->stateBlock->lights;
2709 prevPos = NULL;
2710 while (insertAt != NULL && insertAt->glIndex != -1) {
2711 prevPos = insertAt;
2712 insertAt = insertAt->next;
2715 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2716 This->stateBlock->lights = object;
2717 } else if (insertAt == NULL) { /* End of list */
2718 prevPos->next = object;
2719 object->prev = prevPos;
2720 } else { /* Middle of chain */
2721 if (prevPos == NULL) {
2722 This->stateBlock->lights = object;
2723 } else {
2724 prevPos->next = object;
2726 object->prev = prevPos;
2727 object->next = insertAt;
2728 insertAt->prev = object;
2732 /* Initialize the object */
2733 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,
2734 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2735 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2736 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2737 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2738 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2739 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2741 /* Save away the information */
2742 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2744 switch (pLight->Type) {
2745 case D3DLIGHT_POINT:
2746 /* Position */
2747 object->lightPosn[0] = pLight->Position.x;
2748 object->lightPosn[1] = pLight->Position.y;
2749 object->lightPosn[2] = pLight->Position.z;
2750 object->lightPosn[3] = 1.0f;
2751 object->cutoff = 180.0f;
2752 /* FIXME: Range */
2753 break;
2755 case D3DLIGHT_DIRECTIONAL:
2756 /* Direction */
2757 object->lightPosn[0] = -pLight->Direction.x;
2758 object->lightPosn[1] = -pLight->Direction.y;
2759 object->lightPosn[2] = -pLight->Direction.z;
2760 object->lightPosn[3] = 0.0;
2761 object->exponent = 0.0f;
2762 object->cutoff = 180.0f;
2763 break;
2765 case D3DLIGHT_SPOT:
2766 /* Position */
2767 object->lightPosn[0] = pLight->Position.x;
2768 object->lightPosn[1] = pLight->Position.y;
2769 object->lightPosn[2] = pLight->Position.z;
2770 object->lightPosn[3] = 1.0;
2772 /* Direction */
2773 object->lightDirn[0] = pLight->Direction.x;
2774 object->lightDirn[1] = pLight->Direction.y;
2775 object->lightDirn[2] = pLight->Direction.z;
2776 object->lightDirn[3] = 1.0;
2779 * opengl-ish and d3d-ish spot lights use too different models for the
2780 * light "intensity" as a function of the angle towards the main light direction,
2781 * so we only can approximate very roughly.
2782 * however spot lights are rather rarely used in games (if ever used at all).
2783 * furthermore if still used, probably nobody pays attention to such details.
2785 if (pLight->Falloff == 0) {
2786 rho = 6.28f;
2787 } else {
2788 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2790 if (rho < 0.0001) rho = 0.0001f;
2791 object->exponent = -0.3/log(cos(rho/2));
2792 object->cutoff = pLight->Phi*90/M_PI;
2794 /* FIXME: Range */
2795 break;
2797 default:
2798 FIXME("Unrecognized light type %d\n", pLight->Type);
2801 /* Update the live definitions if the light is currently assigned a glIndex */
2802 if (object->glIndex != -1) {
2803 setup_light(iface, object->glIndex, object);
2805 return WINED3D_OK;
2808 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2809 PLIGHTINFOEL *lightInfo = NULL;
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2813 /* Locate the light in the live lights */
2814 lightInfo = This->stateBlock->lights;
2815 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2817 if (lightInfo == NULL) {
2818 TRACE("Light information requested but light not defined\n");
2819 return WINED3DERR_INVALIDCALL;
2822 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2823 return WINED3D_OK;
2826 /*****
2827 * Get / Set Light Enable
2828 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2829 *****/
2830 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2831 PLIGHTINFOEL *lightInfo = NULL;
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2835 /* Tests show true = 128...not clear why */
2837 Enable = Enable? 128: 0;
2839 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2840 if (This->isRecordingState) {
2841 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2842 if (NULL == lightInfo) {
2843 return WINED3DERR_OUTOFVIDEOMEMORY;
2845 lightInfo->OriginalIndex = Index;
2846 lightInfo->glIndex = -1;
2847 lightInfo->enabledChanged = TRUE;
2848 lightInfo->lightEnabled = Enable;
2850 /* Add to the END of the chain of lights changes to be replayed */
2851 if (This->updateStateBlock->lights == NULL) {
2852 This->updateStateBlock->lights = lightInfo;
2853 } else {
2854 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2855 while (temp->next != NULL) temp=temp->next;
2856 temp->next = lightInfo;
2858 TRACE("Recording... not performing anything more\n");
2859 return WINED3D_OK;
2862 /* Not recording... So, locate the light in the live lights */
2863 lightInfo = This->stateBlock->lights;
2864 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2866 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2867 if (lightInfo == NULL) {
2869 TRACE("Light enabled requested but light not defined, so defining one!\n");
2870 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2872 /* Search for it again! Should be fairly quick as near head of list */
2873 lightInfo = This->stateBlock->lights;
2874 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2875 if (lightInfo == NULL) {
2876 FIXME("Adding default lights has failed dismally\n");
2877 return WINED3DERR_INVALIDCALL;
2881 /* OK, we now have a light... */
2882 if (Enable == FALSE) {
2884 /* If we are disabling it, check it was enabled, and
2885 still only do something if it has assigned a glIndex (which it should have!) */
2886 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2887 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2888 ENTER_GL();
2889 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2890 checkGLcall("glDisable GL_LIGHT0+Index");
2891 LEAVE_GL();
2892 } else {
2893 TRACE("Nothing to do as light was not enabled\n");
2895 lightInfo->lightEnabled = Enable;
2896 } else {
2898 /* We are enabling it. If it is enabled, it's really simple */
2899 if (lightInfo->lightEnabled) {
2900 /* nop */
2901 TRACE("Nothing to do as light was enabled\n");
2903 /* If it already has a glIndex, it's still simple */
2904 } else if (lightInfo->glIndex != -1) {
2905 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2906 lightInfo->lightEnabled = Enable;
2907 ENTER_GL();
2908 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2909 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2910 LEAVE_GL();
2912 /* Otherwise got to find space - lights are ordered gl indexes first */
2913 } else {
2914 PLIGHTINFOEL *bsf = NULL;
2915 PLIGHTINFOEL *pos = This->stateBlock->lights;
2916 PLIGHTINFOEL *prev = NULL;
2917 int Index= 0;
2918 int glIndex = -1;
2920 /* Try to minimize changes as much as possible */
2921 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2923 /* Try to remember which index can be replaced if necessary */
2924 if (bsf==NULL && pos->lightEnabled == FALSE) {
2925 /* Found a light we can replace, save as best replacement */
2926 bsf = pos;
2929 /* Step to next space */
2930 prev = pos;
2931 pos = pos->next;
2932 Index ++;
2935 /* If we have too many active lights, fail the call */
2936 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2937 FIXME("Program requests too many concurrent lights\n");
2938 return WINED3DERR_INVALIDCALL;
2940 /* If we have allocated all lights, but not all are enabled,
2941 reuse one which is not enabled */
2942 } else if (Index == This->maxConcurrentLights) {
2943 /* use bsf - Simply swap the new light and the BSF one */
2944 PLIGHTINFOEL *bsfNext = bsf->next;
2945 PLIGHTINFOEL *bsfPrev = bsf->prev;
2947 /* Sort out ends */
2948 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2949 if (bsf->prev != NULL) {
2950 bsf->prev->next = lightInfo;
2951 } else {
2952 This->stateBlock->lights = lightInfo;
2955 /* If not side by side, lots of chains to update */
2956 if (bsf->next != lightInfo) {
2957 lightInfo->prev->next = bsf;
2958 bsf->next->prev = lightInfo;
2959 bsf->next = lightInfo->next;
2960 bsf->prev = lightInfo->prev;
2961 lightInfo->next = bsfNext;
2962 lightInfo->prev = bsfPrev;
2964 } else {
2965 /* Simple swaps */
2966 bsf->prev = lightInfo;
2967 bsf->next = lightInfo->next;
2968 lightInfo->next = bsf;
2969 lightInfo->prev = bsfPrev;
2973 /* Update states */
2974 glIndex = bsf->glIndex;
2975 bsf->glIndex = -1;
2976 lightInfo->glIndex = glIndex;
2977 lightInfo->lightEnabled = Enable;
2979 /* Finally set up the light in gl itself */
2980 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2981 ENTER_GL();
2982 setup_light(iface, glIndex, lightInfo);
2983 glEnable(GL_LIGHT0 + glIndex);
2984 checkGLcall("glEnable GL_LIGHT0 new setup");
2985 LEAVE_GL();
2987 /* If we reached the end of the allocated lights, with space in the
2988 gl lights, setup a new light */
2989 } else if (pos->glIndex == -1) {
2991 /* We reached the end of the allocated gl lights, so already
2992 know the index of the next one! */
2993 glIndex = Index;
2994 lightInfo->glIndex = glIndex;
2995 lightInfo->lightEnabled = Enable;
2997 /* In an ideal world, it's already in the right place */
2998 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2999 /* No need to move it */
3000 } else {
3001 /* Remove this light from the list */
3002 lightInfo->prev->next = lightInfo->next;
3003 if (lightInfo->next != NULL) {
3004 lightInfo->next->prev = lightInfo->prev;
3007 /* Add in at appropriate place (inbetween prev and pos) */
3008 lightInfo->prev = prev;
3009 lightInfo->next = pos;
3010 if (prev == NULL) {
3011 This->stateBlock->lights = lightInfo;
3012 } else {
3013 prev->next = lightInfo;
3015 if (pos != NULL) {
3016 pos->prev = lightInfo;
3020 /* Finally set up the light in gl itself */
3021 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
3022 ENTER_GL();
3023 setup_light(iface, glIndex, lightInfo);
3024 glEnable(GL_LIGHT0 + glIndex);
3025 checkGLcall("glEnable GL_LIGHT0 new setup");
3026 LEAVE_GL();
3031 return WINED3D_OK;
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3036 PLIGHTINFOEL *lightInfo = NULL;
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 TRACE("(%p) : for idx(%ld)\n", This, Index);
3040 /* Locate the light in the live lights */
3041 lightInfo = This->stateBlock->lights;
3042 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3044 if (lightInfo == NULL) {
3045 TRACE("Light enabled state requested but light not defined\n");
3046 return WINED3DERR_INVALIDCALL;
3048 *pEnable = lightInfo->lightEnabled;
3049 return WINED3D_OK;
3052 /*****
3053 * Get / Set Clip Planes
3054 *****/
3055 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3059 /* Validate Index */
3060 if (Index >= GL_LIMITS(clipplanes)) {
3061 TRACE("Application has requested clipplane this device doesn't support\n");
3062 return WINED3DERR_INVALIDCALL;
3065 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3066 This->updateStateBlock->set.clipplane[Index] = TRUE;
3067 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3068 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3069 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3070 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3072 /* Handle recording of state blocks */
3073 if (This->isRecordingState) {
3074 TRACE("Recording... not performing anything\n");
3075 return WINED3D_OK;
3078 /* Apply it */
3080 ENTER_GL();
3082 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3083 glMatrixMode(GL_MODELVIEW);
3084 glPushMatrix();
3085 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3087 TRACE("Clipplane [%f,%f,%f,%f]\n",
3088 This->updateStateBlock->clipplane[Index][0],
3089 This->updateStateBlock->clipplane[Index][1],
3090 This->updateStateBlock->clipplane[Index][2],
3091 This->updateStateBlock->clipplane[Index][3]);
3092 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3093 checkGLcall("glClipPlane");
3095 glPopMatrix();
3096 LEAVE_GL();
3098 return WINED3D_OK;
3101 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p) : for idx %ld\n", This, Index);
3105 /* Validate Index */
3106 if (Index >= GL_LIMITS(clipplanes)) {
3107 TRACE("Application has requested clipplane this device doesn't support\n");
3108 return WINED3DERR_INVALIDCALL;
3111 pPlane[0] = This->stateBlock->clipplane[Index][0];
3112 pPlane[1] = This->stateBlock->clipplane[Index][1];
3113 pPlane[2] = This->stateBlock->clipplane[Index][2];
3114 pPlane[3] = This->stateBlock->clipplane[Index][3];
3115 return WINED3D_OK;
3118 /*****
3119 * Get / Set Clip Plane Status
3120 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3121 *****/
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 FIXME("(%p) : stub\n", This);
3125 if (NULL == pClipStatus) {
3126 return WINED3DERR_INVALIDCALL;
3128 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3129 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3130 return WINED3D_OK;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 FIXME("(%p) : stub\n", This);
3136 if (NULL == pClipStatus) {
3137 return WINED3DERR_INVALIDCALL;
3139 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3140 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3141 return WINED3D_OK;
3144 /*****
3145 * Get / Set Material
3146 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3147 *****/
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 This->updateStateBlock->changed.material = TRUE;
3152 This->updateStateBlock->set.material = TRUE;
3153 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3155 /* Handle recording of state blocks */
3156 if (This->isRecordingState) {
3157 TRACE("Recording... not performing anything\n");
3158 return WINED3D_OK;
3161 ENTER_GL();
3162 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3163 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3164 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3165 pMaterial->Ambient.b, pMaterial->Ambient.a);
3166 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3167 pMaterial->Specular.b, pMaterial->Specular.a);
3168 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3169 pMaterial->Emissive.b, pMaterial->Emissive.a);
3170 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3172 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3173 checkGLcall("glMaterialfv(GL_AMBIENT)");
3174 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3175 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3177 /* Only change material color if specular is enabled, otherwise it is set to black */
3178 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3179 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3180 checkGLcall("glMaterialfv(GL_SPECULAR");
3181 } else {
3182 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3183 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3184 checkGLcall("glMaterialfv(GL_SPECULAR");
3186 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3187 checkGLcall("glMaterialfv(GL_EMISSION)");
3188 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3189 checkGLcall("glMaterialf(GL_SHININESS");
3191 LEAVE_GL();
3192 return WINED3D_OK;
3195 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3198 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3199 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3200 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3201 pMaterial->Ambient.b, pMaterial->Ambient.a);
3202 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3203 pMaterial->Specular.b, pMaterial->Specular.a);
3204 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3205 pMaterial->Emissive.b, pMaterial->Emissive.a);
3206 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3208 return WINED3D_OK;
3211 /*****
3212 * Get / Set Indices
3213 *****/
3214 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3215 UINT BaseVertexIndex) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 IWineD3DIndexBuffer *oldIdxs;
3219 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3220 oldIdxs = This->updateStateBlock->pIndexData;
3222 This->updateStateBlock->changed.indices = TRUE;
3223 This->updateStateBlock->set.indices = TRUE;
3224 This->updateStateBlock->pIndexData = pIndexData;
3225 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3227 /* Handle recording of state blocks */
3228 if (This->isRecordingState) {
3229 TRACE("Recording... not performing anything\n");
3230 return WINED3D_OK;
3233 if (NULL != pIndexData) {
3234 IWineD3DIndexBuffer_AddRef(pIndexData);
3236 if (NULL != oldIdxs) {
3237 IWineD3DIndexBuffer_Release(oldIdxs);
3239 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 *ppIndexData = This->stateBlock->pIndexData;
3247 /* up ref count on ppindexdata */
3248 if (*ppIndexData) {
3249 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3250 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3251 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3252 }else{
3253 TRACE("(%p) No index data set\n", This);
3255 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3257 return WINED3D_OK;
3260 /*****
3261 * Get / Set Viewports
3262 *****/
3263 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3266 TRACE("(%p)\n", This);
3267 This->updateStateBlock->changed.viewport = TRUE;
3268 This->updateStateBlock->set.viewport = TRUE;
3269 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3271 /* Handle recording of state blocks */
3272 if (This->isRecordingState) {
3273 TRACE("Recording... not performing anything\n");
3274 return WINED3D_OK;
3276 This->viewport_changed = TRUE;
3278 ENTER_GL();
3280 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3281 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3283 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3284 checkGLcall("glDepthRange");
3285 /* Note: GL requires lower left, DirectX supplies upper left */
3286 /* TODO: replace usage of renderTarget with context management */
3287 glViewport(pViewport->X,
3288 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3289 pViewport->Width, pViewport->Height);
3291 checkGLcall("glViewport");
3293 LEAVE_GL();
3295 return WINED3D_OK;
3299 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 TRACE("(%p)\n", This);
3302 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3303 return WINED3D_OK;
3306 static void renderstate_stencil_twosided(
3307 IWineD3DDeviceImpl *This,
3308 GLint face,
3309 GLint func,
3310 GLint ref,
3311 GLuint mask,
3312 GLint stencilFail,
3313 GLint depthFail,
3314 GLint stencilPass ) {
3315 #if 0 /* Don't use OpenGL 2.0 calls for now */
3316 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3317 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3318 checkGLcall("glStencilFuncSeparate(...)");
3319 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3320 checkGLcall("glStencilOpSeparate(...)");
3322 else
3323 #endif
3324 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3325 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3326 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3327 GL_EXTCALL(glActiveStencilFaceEXT(face));
3328 checkGLcall("glActiveStencilFaceEXT(...)");
3329 glStencilFunc(func, ref, mask);
3330 checkGLcall("glStencilFunc(...)");
3331 glStencilOp(stencilFail, depthFail, stencilPass);
3332 checkGLcall("glStencilOp(...)");
3333 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3334 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3335 checkGLcall("glStencilFuncSeparateATI(...)");
3336 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3337 checkGLcall("glStencilOpSeparateATI(...)");
3338 } else {
3339 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3343 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3344 DWORD onesided_enable = FALSE;
3345 DWORD twosided_enable = FALSE;
3346 GLint func = GL_ALWAYS;
3347 GLint func_ccw = GL_ALWAYS;
3348 GLint ref = 0;
3349 GLuint mask = 0;
3350 GLint stencilFail = GL_KEEP;
3351 GLint depthFail = GL_KEEP;
3352 GLint stencilPass = GL_KEEP;
3353 GLint stencilFail_ccw = GL_KEEP;
3354 GLint depthFail_ccw = GL_KEEP;
3355 GLint stencilPass_ccw = GL_KEEP;
3357 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3358 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3359 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3360 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3361 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3362 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3363 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3364 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3365 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3366 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3367 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3368 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3369 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3370 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3371 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3372 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3373 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3374 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3375 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3376 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3377 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3378 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3379 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3380 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3382 switch(State) {
3383 case WINED3DRS_STENCILENABLE :
3384 onesided_enable = Value;
3385 break;
3386 case WINED3DRS_TWOSIDEDSTENCILMODE :
3387 twosided_enable = Value;
3388 break;
3389 case WINED3DRS_STENCILFUNC :
3390 func = StencilFunc(Value);
3391 break;
3392 case WINED3DRS_CCW_STENCILFUNC :
3393 func_ccw = StencilFunc(Value);
3394 break;
3395 case WINED3DRS_STENCILREF :
3396 ref = Value;
3397 break;
3398 case WINED3DRS_STENCILMASK :
3399 mask = Value;
3400 break;
3401 case WINED3DRS_STENCILFAIL :
3402 stencilFail = StencilOp(Value);
3403 break;
3404 case WINED3DRS_STENCILZFAIL :
3405 depthFail = StencilOp(Value);
3406 break;
3407 case WINED3DRS_STENCILPASS :
3408 stencilPass = StencilOp(Value);
3409 break;
3410 case WINED3DRS_CCW_STENCILFAIL :
3411 stencilFail_ccw = StencilOp(Value);
3412 break;
3413 case WINED3DRS_CCW_STENCILZFAIL :
3414 depthFail_ccw = StencilOp(Value);
3415 break;
3416 case WINED3DRS_CCW_STENCILPASS :
3417 stencilPass_ccw = StencilOp(Value);
3418 break;
3419 default :
3420 ERR("This should not happen!");
3423 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3424 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3425 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3426 onesided_enable, twosided_enable, ref, mask,
3427 func, stencilFail, depthFail, stencilPass,
3428 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3430 if (twosided_enable) {
3431 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3432 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3433 } else {
3434 if (onesided_enable) {
3435 glEnable(GL_STENCIL_TEST);
3436 checkGLcall("glEnable GL_STENCIL_TEST");
3437 glStencilFunc(func, ref, mask);
3438 checkGLcall("glStencilFunc(...)");
3439 glStencilOp(stencilFail, depthFail, stencilPass);
3440 checkGLcall("glStencilOp(...)");
3441 } else {
3442 glDisable(GL_STENCIL_TEST);
3443 checkGLcall("glDisable GL_STENCIL_TEST");
3448 /*****
3449 * Get / Set Render States
3450 * TODO: Verify against dx9 definitions
3451 *****/
3452 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3455 DWORD OldValue = This->stateBlock->renderState[State];
3457 /* Simple way of referring to either a DWORD or a 4 byte float */
3458 union {
3459 DWORD d;
3460 float f;
3461 } tmpvalue;
3463 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3464 This->updateStateBlock->changed.renderState[State] = TRUE;
3465 This->updateStateBlock->set.renderState[State] = TRUE;
3466 This->updateStateBlock->renderState[State] = Value;
3468 /* Handle recording of state blocks */
3469 if (This->isRecordingState) {
3470 TRACE("Recording... not performing anything\n");
3471 return WINED3D_OK;
3474 ENTER_GL();
3476 switch (State) {
3477 case WINED3DRS_FILLMODE :
3478 switch ((D3DFILLMODE) Value) {
3479 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3480 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3481 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3482 default:
3483 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3485 checkGLcall("glPolygonMode (fillmode)");
3486 break;
3488 case WINED3DRS_LIGHTING :
3489 if (Value) {
3490 glEnable(GL_LIGHTING);
3491 checkGLcall("glEnable GL_LIGHTING");
3492 } else {
3493 glDisable(GL_LIGHTING);
3494 checkGLcall("glDisable GL_LIGHTING");
3496 break;
3498 case WINED3DRS_ZENABLE :
3499 switch ((D3DZBUFFERTYPE) Value) {
3500 case D3DZB_FALSE:
3501 glDisable(GL_DEPTH_TEST);
3502 checkGLcall("glDisable GL_DEPTH_TEST");
3503 break;
3504 case D3DZB_TRUE:
3505 glEnable(GL_DEPTH_TEST);
3506 checkGLcall("glEnable GL_DEPTH_TEST");
3507 break;
3508 case D3DZB_USEW:
3509 glEnable(GL_DEPTH_TEST);
3510 checkGLcall("glEnable GL_DEPTH_TEST");
3511 FIXME("W buffer is not well handled\n");
3512 break;
3513 default:
3514 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3516 break;
3518 case WINED3DRS_CULLMODE :
3520 /* If we are culling "back faces with clockwise vertices" then
3521 set front faces to be counter clockwise and enable culling
3522 of back faces */
3523 switch ((D3DCULL) Value) {
3524 case D3DCULL_NONE:
3525 glDisable(GL_CULL_FACE);
3526 checkGLcall("glDisable GL_CULL_FACE");
3527 break;
3528 case D3DCULL_CW:
3529 glEnable(GL_CULL_FACE);
3530 checkGLcall("glEnable GL_CULL_FACE");
3531 if (This->renderUpsideDown) {
3532 glFrontFace(GL_CW);
3533 checkGLcall("glFrontFace GL_CW");
3534 } else {
3535 glFrontFace(GL_CCW);
3536 checkGLcall("glFrontFace GL_CCW");
3538 glCullFace(GL_BACK);
3539 break;
3540 case D3DCULL_CCW:
3541 glEnable(GL_CULL_FACE);
3542 checkGLcall("glEnable GL_CULL_FACE");
3543 if (This->renderUpsideDown) {
3544 glFrontFace(GL_CCW);
3545 checkGLcall("glFrontFace GL_CCW");
3546 } else {
3547 glFrontFace(GL_CW);
3548 checkGLcall("glFrontFace GL_CW");
3550 glCullFace(GL_BACK);
3551 break;
3552 default:
3553 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3555 break;
3557 case WINED3DRS_SHADEMODE :
3558 switch ((D3DSHADEMODE) Value) {
3559 case D3DSHADE_FLAT:
3560 glShadeModel(GL_FLAT);
3561 checkGLcall("glShadeModel");
3562 break;
3563 case D3DSHADE_GOURAUD:
3564 glShadeModel(GL_SMOOTH);
3565 checkGLcall("glShadeModel");
3566 break;
3567 case D3DSHADE_PHONG:
3568 FIXME("D3DSHADE_PHONG isn't supported?\n");
3570 LEAVE_GL();
3571 return WINED3DERR_INVALIDCALL;
3572 default:
3573 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3575 break;
3577 case WINED3DRS_DITHERENABLE :
3578 if (Value) {
3579 glEnable(GL_DITHER);
3580 checkGLcall("glEnable GL_DITHER");
3581 } else {
3582 glDisable(GL_DITHER);
3583 checkGLcall("glDisable GL_DITHER");
3585 break;
3587 case WINED3DRS_ZWRITEENABLE :
3588 if (Value) {
3589 glDepthMask(1);
3590 checkGLcall("glDepthMask");
3591 } else {
3592 glDepthMask(0);
3593 checkGLcall("glDepthMask");
3595 break;
3597 case WINED3DRS_ZFUNC :
3599 int glParm = GL_LESS;
3601 switch ((D3DCMPFUNC) Value) {
3602 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3603 case D3DCMP_LESS: glParm=GL_LESS; break;
3604 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3605 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3606 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3607 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3608 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3609 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3610 default:
3611 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3613 glDepthFunc(glParm);
3614 checkGLcall("glDepthFunc");
3616 break;
3618 case WINED3DRS_AMBIENT :
3620 float col[4];
3621 D3DCOLORTOGLFLOAT4(Value, col);
3622 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3623 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3624 checkGLcall("glLightModel for MODEL_AMBIENT");
3627 break;
3629 case WINED3DRS_ALPHABLENDENABLE :
3630 if (Value) {
3631 glEnable(GL_BLEND);
3632 checkGLcall("glEnable GL_BLEND");
3633 } else {
3634 glDisable(GL_BLEND);
3635 checkGLcall("glDisable GL_BLEND");
3637 break;
3639 case WINED3DRS_SRCBLEND :
3640 case WINED3DRS_DESTBLEND :
3642 int newVal = GL_ZERO;
3643 switch (Value) {
3644 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3645 case D3DBLEND_ONE : newVal = GL_ONE; break;
3646 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3647 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3648 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3649 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3650 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3651 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3652 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3653 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3654 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3656 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3657 This->srcBlend = newVal;
3658 This->dstBlend = newVal;
3659 break;
3661 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3662 This->srcBlend = newVal;
3663 This->dstBlend = newVal;
3664 break;
3665 default:
3666 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3669 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3670 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3671 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3672 glBlendFunc(This->srcBlend, This->dstBlend);
3674 checkGLcall("glBlendFunc");
3676 break;
3678 case WINED3DRS_ALPHATESTENABLE :
3679 case WINED3DRS_ALPHAFUNC :
3680 case WINED3DRS_ALPHAREF :
3681 case WINED3DRS_COLORKEYENABLE :
3683 int glParm = 0.0;
3684 float ref = GL_LESS;
3685 BOOL enable_ckey = FALSE;
3687 IWineD3DSurfaceImpl *surf;
3689 /* Find out if the texture on the first stage has a ckey set */
3690 if(This->stateBlock->textures[0]) {
3691 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3692 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3695 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3696 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3697 glEnable(GL_ALPHA_TEST);
3698 checkGLcall("glEnable GL_ALPHA_TEST");
3699 } else {
3700 glDisable(GL_ALPHA_TEST);
3701 checkGLcall("glDisable GL_ALPHA_TEST");
3702 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3703 * enable call
3705 break;
3708 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3709 glParm = GL_NOTEQUAL;
3710 ref = 0.0;
3711 } else {
3712 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3714 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3715 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3716 case D3DCMP_LESS: glParm = GL_LESS; break;
3717 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3718 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3719 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3720 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3721 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3722 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3723 default:
3724 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3727 This->alphafunc = glParm;
3728 glAlphaFunc(glParm, ref);
3729 checkGLcall("glAlphaFunc");
3731 break;
3733 case WINED3DRS_CLIPPLANEENABLE :
3734 case WINED3DRS_CLIPPING :
3736 /* Ensure we only do the changed clip planes */
3737 DWORD enable = 0xFFFFFFFF;
3738 DWORD disable = 0x00000000;
3740 /* If enabling / disabling all */
3741 if (State == WINED3DRS_CLIPPING) {
3742 if (Value) {
3743 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3744 disable = 0x00;
3745 } else {
3746 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3747 enable = 0x00;
3749 } else {
3750 enable = Value & ~OldValue;
3751 disable = ~Value & OldValue;
3754 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3755 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3756 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3757 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3758 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3759 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3761 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3762 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3763 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3764 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3765 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3766 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3768 /** update clipping status */
3769 if (enable) {
3770 This->stateBlock->clip_status.ClipUnion = 0;
3771 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3772 } else {
3773 This->stateBlock->clip_status.ClipUnion = 0;
3774 This->stateBlock->clip_status.ClipIntersection = 0;
3777 break;
3779 case WINED3DRS_BLENDOP :
3781 int glParm = GL_FUNC_ADD;
3783 switch ((D3DBLENDOP) Value) {
3784 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3785 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3786 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3787 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3788 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3789 default:
3790 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3793 if(GL_SUPPORT(ARB_IMAGING)) {
3794 TRACE("glBlendEquation(%x)\n", glParm);
3795 GL_EXTCALL(glBlendEquation(glParm));
3796 checkGLcall("glBlendEquation");
3797 } else {
3798 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3801 break;
3803 case WINED3DRS_TEXTUREFACTOR :
3805 unsigned int i;
3807 /* Note the texture color applies to all textures whereas
3808 GL_TEXTURE_ENV_COLOR applies to active only */
3809 float col[4];
3810 D3DCOLORTOGLFLOAT4(Value, col);
3811 /* Set the default alpha blend color */
3812 if (GL_SUPPORT(ARB_IMAGING)) {
3813 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3814 checkGLcall("glBlendColor");
3815 } else {
3816 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3819 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3820 /* And now the default texture color as well */
3821 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3822 /* Note the D3DRS value applies to all textures, but GL has one
3823 per texture, so apply it now ready to be used! */
3824 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3825 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3826 checkGLcall("glActiveTextureARB");
3827 } else if (i>0) {
3828 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3831 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3832 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3836 break;
3838 case WINED3DRS_SPECULARENABLE :
3840 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3841 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3842 specular color. This is wrong:
3843 Separate specular color means the specular colour is maintained separately, whereas
3844 single color means it is merged in. However in both cases they are being used to
3845 some extent.
3846 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3847 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3848 running 1.4 yet!
3851 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3852 * Instead, we need to setup the FinalCombiner properly.
3854 * The default setup for the FinalCombiner is:
3856 * <variable> <input> <mapping> <usage>
3857 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3858 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3859 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3860 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3861 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3862 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3863 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3865 * That's pretty much fine as it is, except for variable B, which needs to take
3866 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3867 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3870 if (Value) {
3871 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3872 checkGLcall("glMaterialfv");
3873 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3874 glEnable(GL_COLOR_SUM_EXT);
3875 } else {
3876 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3878 checkGLcall("glEnable(GL_COLOR_SUM)");
3880 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3881 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3882 checkGLcall("glFinalCombinerInputNV()");
3884 } else {
3885 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3887 /* for the case of enabled lighting: */
3888 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3889 checkGLcall("glMaterialfv");
3891 /* for the case of disabled lighting: */
3892 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3893 glDisable(GL_COLOR_SUM_EXT);
3894 } else {
3895 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3897 checkGLcall("glDisable(GL_COLOR_SUM)");
3899 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3900 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3901 checkGLcall("glFinalCombinerInputNV()");
3905 break;
3907 case WINED3DRS_STENCILENABLE :
3908 case WINED3DRS_TWOSIDEDSTENCILMODE :
3909 case WINED3DRS_STENCILFUNC :
3910 case WINED3DRS_CCW_STENCILFUNC :
3911 case WINED3DRS_STENCILREF :
3912 case WINED3DRS_STENCILMASK :
3913 case WINED3DRS_STENCILFAIL :
3914 case WINED3DRS_STENCILZFAIL :
3915 case WINED3DRS_STENCILPASS :
3916 case WINED3DRS_CCW_STENCILFAIL :
3917 case WINED3DRS_CCW_STENCILZFAIL :
3918 case WINED3DRS_CCW_STENCILPASS :
3919 renderstate_stencil(This, State, Value);
3920 break;
3921 case WINED3DRS_STENCILWRITEMASK :
3923 glStencilMask(Value);
3924 TRACE("glStencilMask(%lu)\n", Value);
3925 checkGLcall("glStencilMask");
3927 break;
3929 case WINED3DRS_FOGENABLE :
3931 if (Value) {
3932 glEnable(GL_FOG);
3933 checkGLcall("glEnable GL_FOG");
3934 } else {
3935 glDisable(GL_FOG);
3936 checkGLcall("glDisable GL_FOG");
3939 break;
3941 case WINED3DRS_RANGEFOGENABLE :
3943 if (Value) {
3944 TRACE("Enabled RANGEFOG");
3945 } else {
3946 TRACE("Disabled RANGEFOG");
3949 break;
3951 case WINED3DRS_FOGCOLOR :
3953 float col[4];
3954 D3DCOLORTOGLFLOAT4(Value, col);
3955 /* Set the default alpha blend color */
3956 glFogfv(GL_FOG_COLOR, &col[0]);
3957 checkGLcall("glFog GL_FOG_COLOR");
3959 break;
3961 case WINED3DRS_FOGTABLEMODE :
3962 case WINED3DRS_FOGVERTEXMODE :
3964 /* 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." */
3965 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3966 glHint(GL_FOG_HINT, GL_FASTEST);
3967 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3968 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3969 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3970 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3972 case D3DFOG_EXP: {
3973 if(!This->last_was_rhw) {
3974 glFogi(GL_FOG_MODE, GL_EXP);
3975 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3976 if(GL_SUPPORT(EXT_FOG_COORD)) {
3977 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3978 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3979 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3980 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3982 break;
3985 case D3DFOG_EXP2: {
3986 if(!This->last_was_rhw) {
3987 glFogi(GL_FOG_MODE, GL_EXP2);
3988 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3989 if(GL_SUPPORT(EXT_FOG_COORD)) {
3990 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3991 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3992 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3993 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3995 break;
3998 case D3DFOG_LINEAR: {
3999 if(!This->last_was_rhw) {
4000 glFogi(GL_FOG_MODE, GL_LINEAR);
4001 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4002 if(GL_SUPPORT(EXT_FOG_COORD)) {
4003 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4004 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4005 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4006 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4008 break;
4011 case D3DFOG_NONE: {
4012 /* Both are none? According to msdn the alpha channel of the specular
4013 * color contains a fog factor. Set it in drawStridedSlow.
4014 * Same happens with Vertexfog on transformed vertices
4016 if(GL_SUPPORT(EXT_FOG_COORD)) {
4017 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
4018 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
4019 glFogi(GL_FOG_MODE, GL_LINEAR);
4020 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
4021 glFogf(GL_FOG_START, (float) 0xff);
4022 checkGLcall("glFogfv GL_FOG_START");
4023 glFogf(GL_FOG_END, 0.0);
4024 checkGLcall("glFogfv GL_FOG_END");
4025 } else {
4026 /* Disable GL fog, handle this in software in drawStridedSlow */
4027 glDisable(GL_FOG);
4028 checkGLcall("glDisable(GL_FOG)");
4030 break;
4032 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
4034 } else {
4035 glHint(GL_FOG_HINT, GL_NICEST);
4036 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
4037 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
4038 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
4039 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
4040 if(GL_SUPPORT(EXT_FOG_COORD)) {
4041 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4042 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4043 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4044 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4046 break;
4047 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
4048 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
4049 if(GL_SUPPORT(EXT_FOG_COORD)) {
4050 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4051 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4052 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4053 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4055 break;
4056 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4057 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4058 if(GL_SUPPORT(EXT_FOG_COORD)) {
4059 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4060 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4061 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4062 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4064 break;
4065 case D3DFOG_NONE: /* Won't happen */
4066 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4069 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4070 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4073 break;
4075 case WINED3DRS_FOGSTART :
4077 tmpvalue.d = Value;
4078 glFogfv(GL_FOG_START, &tmpvalue.f);
4079 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4080 TRACE("Fog Start == %f\n", tmpvalue.f);
4082 break;
4084 case WINED3DRS_FOGEND :
4086 tmpvalue.d = Value;
4087 glFogfv(GL_FOG_END, &tmpvalue.f);
4088 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4089 TRACE("Fog End == %f\n", tmpvalue.f);
4091 break;
4093 case WINED3DRS_FOGDENSITY :
4095 tmpvalue.d = Value;
4096 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4097 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4099 break;
4101 case WINED3DRS_VERTEXBLEND :
4103 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4104 TRACE("Vertex Blending state to %ld\n", Value);
4106 break;
4108 case WINED3DRS_TWEENFACTOR :
4110 tmpvalue.d = Value;
4111 This->updateStateBlock->tween_factor = tmpvalue.f;
4112 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4114 break;
4116 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4118 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4120 break;
4122 case WINED3DRS_COLORVERTEX :
4123 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4124 case WINED3DRS_SPECULARMATERIALSOURCE :
4125 case WINED3DRS_AMBIENTMATERIALSOURCE :
4126 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4128 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4130 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4131 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4132 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4133 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4134 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4135 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4137 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4138 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4139 Parm = GL_AMBIENT_AND_DIFFUSE;
4140 } else {
4141 Parm = GL_DIFFUSE;
4143 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4144 Parm = GL_AMBIENT;
4145 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4146 Parm = GL_EMISSION;
4147 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4148 Parm = GL_SPECULAR;
4149 } else {
4150 Parm = -1;
4153 if (Parm == -1) {
4154 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4155 } else {
4156 This->tracking_color = NEEDS_TRACKING;
4157 This->tracking_parm = Parm;
4160 } else {
4161 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4164 break;
4166 case WINED3DRS_LINEPATTERN :
4168 union {
4169 DWORD d;
4170 D3DLINEPATTERN lp;
4171 } tmppattern;
4172 tmppattern.d = Value;
4174 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4176 if (tmppattern.lp.wRepeatFactor) {
4177 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4178 checkGLcall("glLineStipple(repeat, linepattern)");
4179 glEnable(GL_LINE_STIPPLE);
4180 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4181 } else {
4182 glDisable(GL_LINE_STIPPLE);
4183 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4186 break;
4188 case WINED3DRS_ZBIAS : /* D3D8 only */
4190 if (Value) {
4191 tmpvalue.d = Value;
4192 TRACE("ZBias value %f\n", tmpvalue.f);
4193 glPolygonOffset(0, -tmpvalue.f);
4194 checkGLcall("glPolygonOffset(0, -Value)");
4195 glEnable(GL_POLYGON_OFFSET_FILL);
4196 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4197 glEnable(GL_POLYGON_OFFSET_LINE);
4198 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4199 glEnable(GL_POLYGON_OFFSET_POINT);
4200 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4201 } else {
4202 glDisable(GL_POLYGON_OFFSET_FILL);
4203 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4204 glDisable(GL_POLYGON_OFFSET_LINE);
4205 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4206 glDisable(GL_POLYGON_OFFSET_POINT);
4207 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4210 break;
4212 case WINED3DRS_NORMALIZENORMALS :
4213 if (Value) {
4214 glEnable(GL_NORMALIZE);
4215 checkGLcall("glEnable(GL_NORMALIZE);");
4216 } else {
4217 glDisable(GL_NORMALIZE);
4218 checkGLcall("glDisable(GL_NORMALIZE);");
4220 break;
4222 case WINED3DRS_POINTSIZE :
4223 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4224 tmpvalue.d = Value;
4225 TRACE("Set point size to %f\n", tmpvalue.f);
4226 glPointSize(tmpvalue.f);
4227 checkGLcall("glPointSize(...);");
4228 break;
4230 case WINED3DRS_POINTSIZE_MIN :
4231 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4232 tmpvalue.d = Value;
4233 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4234 checkGLcall("glPointParameterfEXT(...);");
4235 } else {
4236 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4238 break;
4240 case WINED3DRS_POINTSIZE_MAX :
4241 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4242 tmpvalue.d = Value;
4243 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4244 checkGLcall("glPointParameterfEXT(...);");
4245 } else {
4246 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4248 break;
4250 case WINED3DRS_POINTSCALE_A :
4251 case WINED3DRS_POINTSCALE_B :
4252 case WINED3DRS_POINTSCALE_C :
4253 case WINED3DRS_POINTSCALEENABLE :
4256 * POINTSCALEENABLE controls how point size value is treated. If set to
4257 * true, the point size is scaled with respect to height of viewport.
4258 * When set to false point size is in pixels.
4260 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4263 /* Default values */
4264 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4267 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4268 * This means that OpenGL will clamp really small point sizes to 1.0f.
4269 * To correct for this we need to multiply by the scale factor when sizes
4270 * are less than 1.0f. scale_factor = 1.0f / point_size.
4272 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4273 if(pointSize > 0.0f) {
4274 GLfloat scaleFactor;
4276 if(pointSize < 1.0f) {
4277 scaleFactor = pointSize * pointSize;
4278 } else {
4279 scaleFactor = 1.0f;
4282 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4283 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4284 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4285 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4286 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4287 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4288 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4292 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4293 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4294 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4296 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4297 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4298 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4299 } else {
4300 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4302 break;
4304 case WINED3DRS_COLORWRITEENABLE :
4306 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4307 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4308 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4309 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4310 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4311 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4312 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4313 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4314 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4315 checkGLcall("glColorMask(...)");
4317 break;
4319 case WINED3DRS_LOCALVIEWER :
4321 GLint state = (Value) ? 1 : 0;
4322 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4323 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4325 break;
4327 case WINED3DRS_LASTPIXEL :
4329 if (Value) {
4330 TRACE("Last Pixel Drawing Enabled\n");
4331 } else {
4332 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4335 break;
4337 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4339 if (Value) {
4340 TRACE("Software Processing Enabled\n");
4341 } else {
4342 TRACE("Software Processing Disabled\n");
4345 break;
4347 /** not supported */
4348 case WINED3DRS_ZVISIBLE :
4350 LEAVE_GL();
4351 return WINED3DERR_INVALIDCALL;
4353 case WINED3DRS_POINTSPRITEENABLE :
4355 /* TODO: NV_POINT_SPRITE */
4356 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4357 TRACE("Point sprites not supported\n");
4358 break;
4362 * Point sprites are always enabled. Value controls texture coordinate
4363 * replacement mode. Must be set true for point sprites to use
4364 * textures.
4366 glEnable(GL_POINT_SPRITE_ARB);
4367 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4369 if (Value) {
4370 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4371 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4372 } else {
4373 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4374 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4376 break;
4378 case WINED3DRS_EDGEANTIALIAS :
4380 if(Value) {
4381 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4382 glEnable(GL_BLEND);
4383 checkGLcall("glEnable(GL_BLEND)");
4384 glEnable(GL_LINE_SMOOTH);
4385 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4386 } else {
4387 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4388 glDisable(GL_BLEND);
4389 checkGLcall("glDisable(GL_BLEND)");
4391 glDisable(GL_LINE_SMOOTH);
4392 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4394 break;
4396 case WINED3DRS_WRAP0 :
4397 case WINED3DRS_WRAP1 :
4398 case WINED3DRS_WRAP2 :
4399 case WINED3DRS_WRAP3 :
4400 case WINED3DRS_WRAP4 :
4401 case WINED3DRS_WRAP5 :
4402 case WINED3DRS_WRAP6 :
4403 case WINED3DRS_WRAP7 :
4404 case WINED3DRS_WRAP8 :
4405 case WINED3DRS_WRAP9 :
4406 case WINED3DRS_WRAP10 :
4407 case WINED3DRS_WRAP11 :
4408 case WINED3DRS_WRAP12 :
4409 case WINED3DRS_WRAP13 :
4410 case WINED3DRS_WRAP14 :
4411 case WINED3DRS_WRAP15 :
4413 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4414 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4415 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4416 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4417 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4419 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4421 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4422 break;
4423 case WINED3DRS_MULTISAMPLEANTIALIAS :
4425 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4426 TRACE("Multisample antialiasing not supported\n");
4427 break;
4430 if(Value) {
4431 glEnable(GL_MULTISAMPLE_ARB);
4432 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4433 } else {
4434 glDisable(GL_MULTISAMPLE_ARB);
4435 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4437 break;
4439 case WINED3DRS_SCISSORTESTENABLE :
4441 if(Value) {
4442 glEnable(GL_SCISSOR_TEST);
4443 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4444 } else {
4445 glDisable(GL_SCISSOR_TEST);
4446 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4448 break;
4450 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4452 if(Value) {
4453 tmpvalue.d = Value;
4454 glEnable(GL_POLYGON_OFFSET_FILL);
4455 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4456 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4457 checkGLcall("glPolygonOffset(...)");
4458 } else {
4459 glDisable(GL_POLYGON_OFFSET_FILL);
4460 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4462 break;
4464 case WINED3DRS_ANTIALIASEDLINEENABLE :
4466 if(Value) {
4467 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4468 glEnable(GL_BLEND);
4469 checkGLcall("glEnable(GL_BLEND)");
4470 glEnable(GL_LINE_SMOOTH);
4471 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4472 } else {
4473 glDisable(GL_BLEND);
4474 checkGLcall("glDisable(GL_BLEND)");
4475 glDisable(GL_LINE_SMOOTH);
4476 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4478 break;
4480 case WINED3DRS_DEPTHBIAS :
4482 if(Value) {
4483 tmpvalue.d = Value;
4484 glEnable(GL_POLYGON_OFFSET_FILL);
4485 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4486 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4487 checkGLcall("glPolygonOffset(...)");
4488 } else {
4489 glDisable(GL_POLYGON_OFFSET_FILL);
4490 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4492 break;
4495 case WINED3DRS_TEXTUREPERSPECTIVE :
4497 if (Value)
4498 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4499 else
4500 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4501 break;
4504 case WINED3DRS_STIPPLEDALPHA :
4506 if (Value)
4507 ERR(" Stippled Alpha not supported yet.\n");
4508 break;
4510 case WINED3DRS_ANTIALIAS :
4512 if (Value)
4513 ERR(" Antialias not supported yet.\n");
4514 break;
4516 default:
4517 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4520 LEAVE_GL();
4522 return WINED3D_OK;
4525 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4528 *pValue = This->stateBlock->renderState[State];
4529 return WINED3D_OK;
4532 /*****
4533 * Get / Set Sampler States
4534 * TODO: Verify against dx9 definitions
4535 *****/
4537 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 * SetSampler is designed to allow for more than the standard up to 8 textures
4541 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4542 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4544 * http://developer.nvidia.com/object/General_FAQ.html#t6
4546 * There are two new settings for GForce
4547 * the sampler one:
4548 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4549 * and the texture one:
4550 * GL_MAX_TEXTURE_COORDS_ARB.
4551 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4552 ******************/
4553 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4554 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4555 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4556 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4557 return WINED3DERR_INVALIDCALL;
4560 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4561 debug_d3dsamplerstate(Type), Type, Value);
4562 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4563 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4564 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4566 /* Handle recording of state blocks */
4567 if (This->isRecordingState) {
4568 TRACE("Recording... not performing anything\n");
4569 return WINED3D_OK;
4572 return WINED3D_OK;
4575 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 /** TODO: check that sampler is in range **/
4578 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4579 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4581 return WINED3D_OK;
4584 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 ENTER_GL();
4588 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4589 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4590 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4591 LEAVE_GL();
4593 return WINED3D_OK;
4596 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 GLint scissorBox[4];
4600 ENTER_GL();
4601 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4602 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4603 pRect->left = scissorBox[0];
4604 pRect->top = scissorBox[1];
4605 pRect->right = scissorBox[0] + scissorBox[2];
4606 pRect->bottom = scissorBox[1] + scissorBox[3];
4607 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4608 LEAVE_GL();
4609 return WINED3D_OK;
4612 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4614 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4616 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4618 This->updateStateBlock->vertexDecl = pDecl;
4619 This->updateStateBlock->changed.vertexDecl = TRUE;
4620 This->updateStateBlock->set.vertexDecl = TRUE;
4622 if (This->isRecordingState) {
4623 TRACE("Recording... not performing anything\n");
4626 if (NULL != pDecl) {
4627 IWineD3DVertexDeclaration_AddRef(pDecl);
4629 if (NULL != oldDecl) {
4630 IWineD3DVertexDeclaration_Release(oldDecl);
4632 return WINED3D_OK;
4635 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4640 *ppDecl = This->stateBlock->vertexDecl;
4641 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4642 return WINED3D_OK;
4645 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4647 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4649 This->updateStateBlock->vertexShader = pShader;
4650 This->updateStateBlock->changed.vertexShader = TRUE;
4651 This->updateStateBlock->set.vertexShader = TRUE;
4653 if (This->isRecordingState) {
4654 TRACE("Recording... not performing anything\n");
4657 if (NULL != pShader) {
4658 IWineD3DVertexShader_AddRef(pShader);
4660 if (NULL != oldShader) {
4661 IWineD3DVertexShader_Release(oldShader);
4664 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4666 * TODO: merge HAL shaders context switching from prototype
4668 return WINED3D_OK;
4671 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4674 if (NULL == ppShader) {
4675 return WINED3DERR_INVALIDCALL;
4677 *ppShader = This->stateBlock->vertexShader;
4678 if( NULL != *ppShader)
4679 IWineD3DVertexShader_AddRef(*ppShader);
4681 TRACE("(%p) : returning %p\n", This, *ppShader);
4682 return WINED3D_OK;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4686 IWineD3DDevice *iface,
4687 UINT start,
4688 CONST BOOL *srcData,
4689 UINT count) {
4691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4692 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4694 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4695 iface, srcData, start, count);
4697 if (srcData == NULL || cnt < 0)
4698 return WINED3DERR_INVALIDCALL;
4700 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4701 for (i = 0; i < cnt; i++)
4702 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4704 for (i = start; i < cnt + start; ++i) {
4705 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4706 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4709 return WINED3D_OK;
4712 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4713 IWineD3DDevice *iface,
4714 UINT start,
4715 BOOL *dstData,
4716 UINT count) {
4718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 int cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4721 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4722 iface, dstData, start, count);
4724 if (dstData == NULL || cnt < 0)
4725 return WINED3DERR_INVALIDCALL;
4727 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4728 return WINED3D_OK;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4732 IWineD3DDevice *iface,
4733 UINT start,
4734 CONST int *srcData,
4735 UINT count) {
4737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4738 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4740 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4741 iface, srcData, start, count);
4743 if (srcData == NULL || cnt < 0)
4744 return WINED3DERR_INVALIDCALL;
4746 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4747 for (i = 0; i < cnt; i++)
4748 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4749 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4751 for (i = start; i < cnt + start; ++i) {
4752 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4753 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4756 return WINED3D_OK;
4759 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4760 IWineD3DDevice *iface,
4761 UINT start,
4762 int *dstData,
4763 UINT count) {
4765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4766 int cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4768 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4769 iface, dstData, start, count);
4771 if (dstData == NULL || cnt < 0)
4772 return WINED3DERR_INVALIDCALL;
4774 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4775 return WINED3D_OK;
4778 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4779 IWineD3DDevice *iface,
4780 UINT start,
4781 CONST float *srcData,
4782 UINT count) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4787 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4788 iface, srcData, start, count);
4790 if (srcData == NULL || cnt < 0)
4791 return WINED3DERR_INVALIDCALL;
4793 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4794 for (i = 0; i < cnt; i++)
4795 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4796 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4798 for (i = start; i < cnt + start; ++i) {
4799 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4800 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4803 return WINED3D_OK;
4806 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4807 IWineD3DDevice *iface,
4808 UINT start,
4809 float *dstData,
4810 UINT count) {
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4813 int cnt = min(count, MAX_VSHADER_CONSTANTS - start);
4815 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4816 iface, dstData, start, count);
4818 if (dstData == NULL || cnt < 0)
4819 return WINED3DERR_INVALIDCALL;
4821 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4822 return WINED3D_OK;
4825 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4827 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4828 This->updateStateBlock->pixelShader = pShader;
4829 This->updateStateBlock->changed.pixelShader = TRUE;
4830 This->updateStateBlock->set.pixelShader = TRUE;
4832 /* Handle recording of state blocks */
4833 if (This->isRecordingState) {
4834 TRACE("Recording... not performing anything\n");
4837 if (NULL != pShader) {
4838 IWineD3DPixelShader_AddRef(pShader);
4840 if (NULL != oldShader) {
4841 IWineD3DPixelShader_Release(oldShader);
4844 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4846 * TODO: merge HAL shaders context switching from prototype
4848 return WINED3D_OK;
4851 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4854 if (NULL == ppShader) {
4855 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4856 return WINED3DERR_INVALIDCALL;
4859 *ppShader = This->stateBlock->pixelShader;
4860 if (NULL != *ppShader) {
4861 IWineD3DPixelShader_AddRef(*ppShader);
4863 TRACE("(%p) : returning %p\n", This, *ppShader);
4864 return WINED3D_OK;
4867 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4868 IWineD3DDevice *iface,
4869 UINT start,
4870 CONST BOOL *srcData,
4871 UINT count) {
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4874 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4876 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4877 iface, srcData, start, count);
4879 if (srcData == NULL || cnt < 0)
4880 return WINED3DERR_INVALIDCALL;
4882 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4883 for (i = 0; i < cnt; i++)
4884 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4886 for (i = start; i < cnt + start; ++i) {
4887 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4888 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4891 return WINED3D_OK;
4894 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4895 IWineD3DDevice *iface,
4896 UINT start,
4897 BOOL *dstData,
4898 UINT count) {
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 int cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4903 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4904 iface, dstData, start, count);
4906 if (dstData == NULL || cnt < 0)
4907 return WINED3DERR_INVALIDCALL;
4909 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4910 return WINED3D_OK;
4913 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4914 IWineD3DDevice *iface,
4915 UINT start,
4916 CONST int *srcData,
4917 UINT count) {
4919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4920 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4922 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4923 iface, srcData, start, count);
4925 if (srcData == NULL || cnt < 0)
4926 return WINED3DERR_INVALIDCALL;
4928 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4929 for (i = 0; i < cnt; i++)
4930 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4931 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4933 for (i = start; i < cnt + start; ++i) {
4934 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4935 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4938 return WINED3D_OK;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4942 IWineD3DDevice *iface,
4943 UINT start,
4944 int *dstData,
4945 UINT count) {
4947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4948 int cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4950 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4951 iface, dstData, start, count);
4953 if (dstData == NULL || cnt < 0)
4954 return WINED3DERR_INVALIDCALL;
4956 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4957 return WINED3D_OK;
4960 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4961 IWineD3DDevice *iface,
4962 UINT start,
4963 CONST float *srcData,
4964 UINT count) {
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4969 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4970 iface, srcData, start, count);
4972 if (srcData == NULL || cnt < 0)
4973 return WINED3DERR_INVALIDCALL;
4975 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4976 for (i = 0; i < cnt; i++)
4977 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4978 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4980 for (i = start; i < cnt + start; ++i) {
4981 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4982 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4985 return WINED3D_OK;
4988 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4989 IWineD3DDevice *iface,
4990 UINT start,
4991 float *dstData,
4992 UINT count) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 int cnt = min(count, MAX_PSHADER_CONSTANTS - start);
4997 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4998 iface, dstData, start, count);
5000 if (dstData == NULL || cnt < 0)
5001 return WINED3DERR_INVALIDCALL;
5003 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5004 return WINED3D_OK;
5007 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5008 static HRESULT
5009 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5010 char *dest_ptr, *dest_conv = NULL;
5011 unsigned int i;
5012 DWORD DestFVF = dest->fvf;
5013 D3DVIEWPORT9 vp;
5014 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5015 BOOL doClip;
5016 int numTextures;
5018 if (SrcFVF & D3DFVF_NORMAL) {
5019 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5022 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5023 ERR("Source has no position mask\n");
5024 return WINED3DERR_INVALIDCALL;
5027 /* We might access VBOs from this code, so hold the lock */
5028 ENTER_GL();
5030 if (dest->resource.allocatedMemory == NULL) {
5031 /* This may happen if we do direct locking into a vbo. Unlikely,
5032 * but theoretically possible(ddraw processvertices test)
5034 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5035 if(!dest->resource.allocatedMemory) {
5036 LEAVE_GL();
5037 ERR("Out of memory\n");
5038 return E_OUTOFMEMORY;
5040 if(dest->vbo) {
5041 void *src;
5042 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5043 checkGLcall("glBindBufferARB");
5044 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5045 if(src) {
5046 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5048 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5049 checkGLcall("glUnmapBufferARB");
5053 /* Get a pointer into the destination vbo(create one if none exists) and
5054 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5056 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5057 CreateVBO(dest);
5060 if(dest->vbo) {
5061 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5062 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5063 if(!dest_conv) {
5064 ERR("glMapBuffer failed\n");
5065 /* Continue without storing converted vertices */
5069 /* Should I clip?
5070 * a) D3DRS_CLIPPING is enabled
5071 * b) WINED3DVOP_CLIP is passed
5073 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5074 static BOOL warned = FALSE;
5076 * The clipping code is not quite correct. Some things need
5077 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5078 * so disable clipping for now.
5079 * (The graphics in Half-Life are broken, and my processvertices
5080 * test crashes with IDirect3DDevice3)
5081 doClip = TRUE;
5083 doClip = FALSE;
5084 if(!warned) {
5085 warned = TRUE;
5086 FIXME("Clipping is broken and disabled for now\n");
5088 } else doClip = FALSE;
5089 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5090 if(dest_conv) {
5091 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5094 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5095 D3DTS_VIEW,
5096 &view_mat);
5097 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5098 D3DTS_PROJECTION,
5099 &proj_mat);
5100 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5101 D3DTS_WORLDMATRIX(0),
5102 &world_mat);
5104 TRACE("View mat:\n");
5105 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); \
5106 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); \
5107 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); \
5108 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); \
5110 TRACE("Proj mat:\n");
5111 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); \
5112 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); \
5113 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); \
5114 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); \
5116 TRACE("World mat:\n");
5117 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); \
5118 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); \
5119 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); \
5120 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); \
5122 /* Get the viewport */
5123 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5124 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5125 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5127 multiply_matrix(&mat,&view_mat,&world_mat);
5128 multiply_matrix(&mat,&proj_mat,&mat);
5130 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5132 for (i = 0; i < dwCount; i+= 1) {
5133 unsigned int tex_index;
5135 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5136 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5137 /* The position first */
5138 float *p =
5139 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5140 float x, y, z, rhw;
5141 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5143 /* Multiplication with world, view and projection matrix */
5144 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);
5145 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);
5146 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);
5147 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);
5149 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5151 /* WARNING: The following things are taken from d3d7 and were not yet checked
5152 * against d3d8 or d3d9!
5155 /* Clipping conditions: From
5156 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5158 * A vertex is clipped if it does not match the following requirements
5159 * -rhw < x <= rhw
5160 * -rhw < y <= rhw
5161 * 0 < z <= rhw
5162 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5164 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5165 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5169 if( doClip == FALSE ||
5170 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5171 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5172 ( rhw > eps ) ) ) {
5174 /* "Normal" viewport transformation (not clipped)
5175 * 1) The values are divided by rhw
5176 * 2) The y axis is negative, so multiply it with -1
5177 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5178 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5179 * 4) Multiply x with Width/2 and add Width/2
5180 * 5) The same for the height
5181 * 6) Add the viewpoint X and Y to the 2D coordinates and
5182 * The minimum Z value to z
5183 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5185 * Well, basically it's simply a linear transformation into viewport
5186 * coordinates
5189 x /= rhw;
5190 y /= rhw;
5191 z /= rhw;
5193 y *= -1;
5195 x *= vp.Width / 2;
5196 y *= vp.Height / 2;
5197 z *= vp.MaxZ - vp.MinZ;
5199 x += vp.Width / 2 + vp.X;
5200 y += vp.Height / 2 + vp.Y;
5201 z += vp.MinZ;
5203 rhw = 1 / rhw;
5204 } else {
5205 /* That vertex got clipped
5206 * Contrary to OpenGL it is not dropped completely, it just
5207 * undergoes a different calculation.
5209 TRACE("Vertex got clipped\n");
5210 x += rhw;
5211 y += rhw;
5213 x /= 2;
5214 y /= 2;
5216 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5217 * outside of the main vertex buffer memory. That needs some more
5218 * investigation...
5222 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5225 ( (float *) dest_ptr)[0] = x;
5226 ( (float *) dest_ptr)[1] = y;
5227 ( (float *) dest_ptr)[2] = z;
5228 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5230 dest_ptr += 3 * sizeof(float);
5232 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5233 dest_ptr += sizeof(float);
5236 if(dest_conv) {
5237 float w = 1 / rhw;
5238 ( (float *) dest_conv)[0] = x * w;
5239 ( (float *) dest_conv)[1] = y * w;
5240 ( (float *) dest_conv)[2] = z * w;
5241 ( (float *) dest_conv)[3] = w;
5243 dest_conv += 3 * sizeof(float);
5245 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5246 dest_conv += sizeof(float);
5250 if (DestFVF & D3DFVF_PSIZE) {
5251 dest_ptr += sizeof(DWORD);
5252 if(dest_conv) dest_conv += sizeof(DWORD);
5254 if (DestFVF & D3DFVF_NORMAL) {
5255 float *normal =
5256 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5257 /* AFAIK this should go into the lighting information */
5258 FIXME("Didn't expect the destination to have a normal\n");
5259 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5260 if(dest_conv) {
5261 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5265 if (DestFVF & D3DFVF_DIFFUSE) {
5266 DWORD *color_d =
5267 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5268 if(!color_d) {
5269 static BOOL warned = FALSE;
5271 if(warned == FALSE) {
5272 ERR("No diffuse color in source, but destination has one\n");
5273 warned = TRUE;
5276 *( (DWORD *) dest_ptr) = 0xffffffff;
5277 dest_ptr += sizeof(DWORD);
5279 if(dest_conv) {
5280 *( (DWORD *) dest_conv) = 0xffffffff;
5281 dest_conv += sizeof(DWORD);
5284 else {
5285 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5286 if(dest_conv) {
5287 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5288 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5289 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5290 dest_conv += sizeof(DWORD);
5295 if (DestFVF & D3DFVF_SPECULAR) {
5296 /* What's the color value in the feedback buffer? */
5297 DWORD *color_s =
5298 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5299 if(!color_s) {
5300 static BOOL warned = FALSE;
5302 if(warned == FALSE) {
5303 ERR("No specular color in source, but destination has one\n");
5304 warned = TRUE;
5307 *( (DWORD *) dest_ptr) = 0xFF000000;
5308 dest_ptr += sizeof(DWORD);
5310 if(dest_conv) {
5311 *( (DWORD *) dest_conv) = 0xFF000000;
5312 dest_conv += sizeof(DWORD);
5315 else {
5316 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5317 if(dest_conv) {
5318 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5319 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5320 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5321 dest_conv += sizeof(DWORD);
5326 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5327 float *tex_coord =
5328 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5329 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5330 if(!tex_coord) {
5331 ERR("No source texture, but destination requests one\n");
5332 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5333 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5335 else {
5336 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5337 if(dest_conv) {
5338 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5344 if(dest_conv) {
5345 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5346 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5349 LEAVE_GL();
5351 return WINED3D_OK;
5353 #undef copy_and_next
5355 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5358 WineDirect3DVertexStridedData strided;
5359 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5361 /* We don't need the source vbo because this buffer is only used as
5362 * a source for ProcessVertices. Avoid wasting resources by converting the
5363 * buffer and loading the VBO
5365 if(SrcImpl->vbo) {
5366 TRACE("Releaseing the source vbo, it won't be needed\n");
5368 if(!SrcImpl->resource.allocatedMemory) {
5369 /* Rescue the data from the buffer */
5370 void *src;
5371 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5372 if(!SrcImpl->resource.allocatedMemory) {
5373 ERR("Out of memory\n");
5374 return E_OUTOFMEMORY;
5377 ENTER_GL();
5378 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5379 checkGLcall("glBindBufferARB");
5381 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5382 if(src) {
5383 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5386 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5387 checkGLcall("glUnmapBufferARB");
5388 } else {
5389 ENTER_GL();
5392 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5393 checkGLcall("glBindBufferARB");
5394 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5395 checkGLcall("glDeleteBuffersARB");
5396 LEAVE_GL();
5398 SrcImpl->vbo = 0;
5401 memset(&strided, 0, sizeof(strided));
5402 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5404 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5407 /*****
5408 * Apply / Get / Set Texture Stage States
5409 * TODO: Verify against dx9 definitions
5410 *****/
5412 /* 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 */
5413 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5415 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5416 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5418 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5420 /* Check that the stage is within limits */
5421 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5422 TRACE("Attempt to access invalid texture rejected\n");
5423 return;
5426 ENTER_GL();
5428 switch (Type) {
5429 case WINED3DTSS_ALPHAOP :
5430 case WINED3DTSS_COLOROP :
5431 /* nothing to do as moved to drawprim for now */
5432 break;
5433 case WINED3DTSS_ADDRESSW :
5434 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5435 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5436 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5438 } else {
5439 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5440 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5441 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5442 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5444 #endif
5445 case WINED3DTSS_TEXCOORDINDEX :
5447 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5449 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5450 one flag, you can still specify an index value, which the system uses to
5451 determine the texture wrapping mode.
5452 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5453 means use the vertex position (camera-space) as the input texture coordinates
5454 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5455 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5456 to the TEXCOORDINDEX value */
5459 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5461 switch (Value & 0xFFFF0000) {
5462 case D3DTSS_TCI_PASSTHRU:
5463 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5464 glDisable(GL_TEXTURE_GEN_S);
5465 glDisable(GL_TEXTURE_GEN_T);
5466 glDisable(GL_TEXTURE_GEN_R);
5467 glDisable(GL_TEXTURE_GEN_Q);
5468 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5469 break;
5471 case D3DTSS_TCI_CAMERASPACEPOSITION:
5472 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5473 as the input texture coordinates for this stage's texture transformation. This
5474 equates roughly to EYE_LINEAR */
5476 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5477 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5478 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5479 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5480 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5482 glMatrixMode(GL_MODELVIEW);
5483 glPushMatrix();
5484 glLoadIdentity();
5485 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5486 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5487 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5488 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5489 glPopMatrix();
5491 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5492 glEnable(GL_TEXTURE_GEN_S);
5493 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5494 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5495 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5496 glEnable(GL_TEXTURE_GEN_T);
5497 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5498 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5499 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5500 glEnable(GL_TEXTURE_GEN_R);
5501 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5502 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5503 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5505 break;
5507 case D3DTSS_TCI_CAMERASPACENORMAL:
5509 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5510 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5511 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5512 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5513 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5514 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5516 glMatrixMode(GL_MODELVIEW);
5517 glPushMatrix();
5518 glLoadIdentity();
5519 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5520 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5521 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5522 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5523 glPopMatrix();
5525 glEnable(GL_TEXTURE_GEN_S);
5526 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5527 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5528 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5529 glEnable(GL_TEXTURE_GEN_T);
5530 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5531 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5532 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5533 glEnable(GL_TEXTURE_GEN_R);
5534 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5535 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5536 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5539 break;
5541 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5543 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5544 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5545 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5546 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5547 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5548 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5550 glMatrixMode(GL_MODELVIEW);
5551 glPushMatrix();
5552 glLoadIdentity();
5553 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5554 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5555 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5556 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5557 glPopMatrix();
5559 glEnable(GL_TEXTURE_GEN_S);
5560 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5561 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5562 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5563 glEnable(GL_TEXTURE_GEN_T);
5564 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5565 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5566 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5567 glEnable(GL_TEXTURE_GEN_R);
5568 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5569 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5570 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5573 break;
5575 /* Unhandled types: */
5576 default:
5577 /* Todo: */
5578 /* ? disable GL_TEXTURE_GEN_n ? */
5579 glDisable(GL_TEXTURE_GEN_S);
5580 glDisable(GL_TEXTURE_GEN_T);
5581 glDisable(GL_TEXTURE_GEN_R);
5582 glDisable(GL_TEXTURE_GEN_Q);
5583 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5584 break;
5587 break;
5589 /* Unhandled */
5590 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5591 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5592 break;
5594 case WINED3DTSS_BUMPENVMAT00 :
5595 case WINED3DTSS_BUMPENVMAT01 :
5596 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5597 break;
5598 case WINED3DTSS_BUMPENVMAT10 :
5599 case WINED3DTSS_BUMPENVMAT11 :
5600 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5601 break;
5603 case WINED3DTSS_BUMPENVLSCALE :
5604 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5605 break;
5607 case WINED3DTSS_BUMPENVLOFFSET :
5608 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5609 break;
5611 case WINED3DTSS_RESULTARG :
5612 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5613 break;
5615 default:
5616 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5617 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5620 LEAVE_GL();
5622 return;
5625 /*****
5626 * Get / Set Texture Stage States
5627 * TODO: Verify against dx9 definitions
5628 *****/
5629 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5634 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5636 /* Reject invalid texture units */
5637 if (Stage >= GL_LIMITS(texture_stages)) {
5638 TRACE("Attempt to access invalid texture rejected\n");
5639 return WINED3DERR_INVALIDCALL;
5642 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5643 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5644 This->updateStateBlock->textureState[Stage][Type] = Value;
5646 return WINED3D_OK;
5649 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5651 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5652 *pValue = This->updateStateBlock->textureState[Stage][Type];
5653 return WINED3D_OK;
5656 /*****
5657 * Get / Set Texture
5658 *****/
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 IWineD3DBaseTexture *oldTexture;
5664 oldTexture = This->updateStateBlock->textures[Stage];
5665 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5667 #if 0 /* TODO: check so vertex textures */
5668 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5669 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5670 return WINED3D_OK;
5672 #endif
5674 /* Reject invalid texture units */
5675 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5676 WARN("Attempt to access invalid texture rejected\n");
5677 return WINED3DERR_INVALIDCALL;
5680 if(pTexture != NULL) {
5681 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5683 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5684 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5685 return WINED3DERR_INVALIDCALL;
5689 oldTexture = This->updateStateBlock->textures[Stage];
5690 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5691 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5693 This->updateStateBlock->set.textures[Stage] = TRUE;
5694 This->updateStateBlock->changed.textures[Stage] = TRUE;
5695 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5696 This->updateStateBlock->textures[Stage] = pTexture;
5698 /* Handle recording of state blocks */
5699 if (This->isRecordingState) {
5700 TRACE("Recording... not performing anything\n");
5701 return WINED3D_OK;
5704 /** NOTE: MSDN says that setTexture increases the reference count,
5705 * and the the application nust set the texture back to null (or have a leaky application),
5706 * This means we should pass the refcount up to the parent
5707 *******************************/
5708 if (NULL != This->updateStateBlock->textures[Stage]) {
5709 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5712 if (NULL != oldTexture) {
5713 IWineD3DBaseTexture_Release(oldTexture);
5716 /* Reset color keying */
5717 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5718 BOOL enable_ckey = FALSE;
5720 if(pTexture) {
5721 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5722 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5725 if(enable_ckey) {
5726 glAlphaFunc(GL_NOTEQUAL, 0.0);
5727 checkGLcall("glAlphaFunc");
5731 return WINED3D_OK;
5734 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5736 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5738 /* Reject invalid texture units */
5739 if (Stage >= GL_LIMITS(sampler_stages)) {
5740 TRACE("Attempt to access invalid texture rejected\n");
5741 return WINED3DERR_INVALIDCALL;
5743 *ppTexture=This->updateStateBlock->textures[Stage];
5744 if (*ppTexture)
5745 IWineD3DBaseTexture_AddRef(*ppTexture);
5746 else
5747 return WINED3DERR_INVALIDCALL;
5748 return WINED3D_OK;
5751 /*****
5752 * Get Back Buffer
5753 *****/
5754 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5755 IWineD3DSurface **ppBackBuffer) {
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 IWineD3DSwapChain *swapChain;
5758 HRESULT hr;
5760 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5762 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5763 if (hr == WINED3D_OK) {
5764 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5765 IWineD3DSwapChain_Release(swapChain);
5766 } else {
5767 *ppBackBuffer = NULL;
5769 return hr;
5772 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 WARN("(%p) : stub, calling idirect3d for now\n", This);
5775 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5778 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5780 IWineD3DSwapChain *swapChain;
5781 HRESULT hr;
5783 if(iSwapChain > 0) {
5784 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5785 if (hr == WINED3D_OK) {
5786 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5787 IWineD3DSwapChain_Release(swapChain);
5788 } else {
5789 FIXME("(%p) Error getting display mode\n", This);
5791 } else {
5792 /* Don't read the real display mode,
5793 but return the stored mode instead. X11 can't change the color
5794 depth, and some apps are pretty angry if they SetDisplayMode from
5795 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5797 Also don't relay to the swapchain because with ddraw it's possible
5798 that there isn't a swapchain at all */
5799 pMode->Width = This->ddraw_width;
5800 pMode->Height = This->ddraw_height;
5801 pMode->Format = This->ddraw_format;
5802 pMode->RefreshRate = 0;
5803 hr = WINED3D_OK;
5806 return hr;
5809 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5811 TRACE("(%p)->(%p)\n", This, hWnd);
5813 This->ddraw_window = hWnd;
5814 return WINED3D_OK;
5817 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5819 TRACE("(%p)->(%p)\n", This, hWnd);
5821 *hWnd = This->ddraw_window;
5822 return WINED3D_OK;
5825 /*****
5826 * Stateblock related functions
5827 *****/
5829 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5831 IWineD3DStateBlockImpl *object;
5832 TRACE("(%p)", This);
5834 if (This->isRecordingState) {
5835 return WINED3DERR_INVALIDCALL;
5838 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5839 if (NULL == object ) {
5840 FIXME("(%p)Error allocating memory for stateblock\n", This);
5841 return E_OUTOFMEMORY;
5843 TRACE("(%p) creted object %p\n", This, object);
5844 object->wineD3DDevice= This;
5845 /** FIXME: object->parent = parent; **/
5846 object->parent = NULL;
5847 object->blockType = WINED3DSBT_ALL;
5848 object->ref = 1;
5849 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5851 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5852 This->updateStateBlock = object;
5853 This->isRecordingState = TRUE;
5855 TRACE("(%p) recording stateblock %p\n",This , object);
5856 return WINED3D_OK;
5859 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5862 if (!This->isRecordingState) {
5863 FIXME("(%p) not recording! returning error\n", This);
5864 *ppStateBlock = NULL;
5865 return WINED3DERR_INVALIDCALL;
5868 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5869 This->isRecordingState = FALSE;
5870 This->updateStateBlock = This->stateBlock;
5871 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5872 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5873 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5874 return WINED3D_OK;
5877 /*****
5878 * Scene related functions
5879 *****/
5880 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5881 /* At the moment we have no need for any functionality at the beginning
5882 of a scene */
5883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5884 TRACE("(%p) : stub\n", This);
5885 return WINED3D_OK;
5888 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5890 TRACE("(%p)\n", This);
5891 ENTER_GL();
5892 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5893 glFlush();
5894 checkGLcall("glFlush");
5896 TRACE("End Scene\n");
5897 if(This->renderTarget != NULL) {
5899 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5900 IUnknown *targetContainer = NULL;
5901 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5902 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5903 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5904 /** always dirtify for now. we must find a better way to see that surface have been modified
5905 (Modifications should will only occur via draw-primitive, but we do need better locking
5906 switching to render-to-texture should remove the overhead though.
5908 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5909 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5910 IWineD3DSurface_PreLoad(This->renderTarget);
5911 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5912 IUnknown_Release(targetContainer);
5915 This->sceneEnded = TRUE;
5916 LEAVE_GL();
5917 return WINED3D_OK;
5920 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5921 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5922 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5924 IWineD3DSwapChain *swapChain = NULL;
5925 int i;
5926 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5928 TRACE("(%p) Presenting the frame\n", This);
5930 for(i = 0 ; i < swapchains ; i ++) {
5932 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5933 TRACE("presentinng chain %d, %p\n", i, swapChain);
5934 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5935 IWineD3DSwapChain_Release(swapChain);
5938 return WINED3D_OK;
5941 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5942 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5945 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5946 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5947 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5948 GLbitfield glMask = 0;
5949 GLboolean old_ztest;
5950 GLfloat old_z_clear_value;
5951 GLint old_stencil_clear_value;
5952 GLfloat old_color_clear_value[4];
5953 unsigned int i;
5954 CONST D3DRECT* curRect;
5956 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5957 Count, pRects, Flags, Z, Stencil);
5959 ENTER_GL();
5961 glEnable(GL_SCISSOR_TEST);
5962 checkGLcall("glEnable GL_SCISSOR_TEST");
5964 if (Count > 0 && pRects) {
5965 curRect = pRects;
5966 } else {
5967 curRect = NULL;
5970 /* Only set the values up once, as they are not changing */
5971 if (Flags & D3DCLEAR_STENCIL) {
5972 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5973 glClearStencil(Stencil);
5974 checkGLcall("glClearStencil");
5975 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5976 glStencilMask(0xFFFFFFFF);
5979 if (Flags & D3DCLEAR_ZBUFFER) {
5980 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5981 glDepthMask(GL_TRUE);
5982 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5983 glClearDepth(Z);
5984 checkGLcall("glClearDepth");
5985 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5988 if (Flags & D3DCLEAR_TARGET) {
5989 TRACE("Clearing screen with glClear to color %lx\n", Color);
5990 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5991 glClearColor(D3DCOLOR_R(Color),
5992 D3DCOLOR_G(Color),
5993 D3DCOLOR_B(Color),
5994 D3DCOLOR_A(Color));
5995 checkGLcall("glClearColor");
5997 /* Clear ALL colors! */
5998 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5999 glMask = glMask | GL_COLOR_BUFFER_BIT;
6002 /* Now process each rect in turn */
6003 for (i = 0; i < Count || i == 0; i++) {
6005 if (curRect) {
6006 /* Note gl uses lower left, width/height */
6007 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
6008 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6009 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6010 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6011 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6012 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6013 checkGLcall("glScissor");
6014 } else {
6015 glScissor(This->stateBlock->viewport.X,
6016 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6017 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6018 This->stateBlock->viewport.Width,
6019 This->stateBlock->viewport.Height);
6020 checkGLcall("glScissor");
6023 /* Clear the selected rectangle (or full screen) */
6024 glClear(glMask);
6025 checkGLcall("glClear");
6027 /* Step to the next rectangle */
6028 if (curRect) curRect = curRect + sizeof(D3DRECT);
6031 /* Restore the old values (why..?) */
6032 if (Flags & D3DCLEAR_STENCIL) {
6033 glClearStencil(old_stencil_clear_value);
6034 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6036 if (Flags & D3DCLEAR_ZBUFFER) {
6037 glDepthMask(old_ztest);
6038 glClearDepth(old_z_clear_value);
6040 if (Flags & D3DCLEAR_TARGET) {
6041 glClearColor(old_color_clear_value[0],
6042 old_color_clear_value[1],
6043 old_color_clear_value[2],
6044 old_color_clear_value[3]);
6045 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6046 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6047 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6048 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6051 glDisable(GL_SCISSOR_TEST);
6052 checkGLcall("glDisable");
6053 LEAVE_GL();
6055 return WINED3D_OK;
6058 /*****
6059 * Drawing functions
6060 *****/
6061 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6062 UINT PrimitiveCount) {
6064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6065 This->stateBlock->streamIsUP = FALSE;
6067 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6068 debug_d3dprimitivetype(PrimitiveType),
6069 StartVertex, PrimitiveCount);
6070 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6071 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6074 return WINED3D_OK;
6077 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6078 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6079 D3DPRIMITIVETYPE PrimitiveType,
6080 INT baseVIndex, UINT minIndex,
6081 UINT NumVertices, UINT startIndex, UINT primCount) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 UINT idxStride = 2;
6085 IWineD3DIndexBuffer *pIB;
6086 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6088 pIB = This->stateBlock->pIndexData;
6089 This->stateBlock->streamIsUP = FALSE;
6091 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6092 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6093 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6095 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6096 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6097 idxStride = 2;
6098 } else {
6099 idxStride = 4;
6102 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6103 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6105 return WINED3D_OK;
6108 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6109 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6110 UINT VertexStreamZeroStride) {
6111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6113 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6114 debug_d3dprimitivetype(PrimitiveType),
6115 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6117 /* release the stream source */
6118 if (This->stateBlock->streamSource[0] != NULL) {
6119 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6122 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6123 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6124 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6125 This->stateBlock->streamIsUP = TRUE;
6127 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6128 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6130 /* MSDN specifies stream zero settings must be set to NULL */
6131 This->stateBlock->streamStride[0] = 0;
6132 This->stateBlock->streamSource[0] = NULL;
6134 /*stream zero settings set to null at end, as per the msdn */
6135 return WINED3D_OK;
6138 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6139 UINT MinVertexIndex, UINT NumVertices,
6140 UINT PrimitiveCount, CONST void* pIndexData,
6141 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6142 UINT VertexStreamZeroStride) {
6143 int idxStride;
6144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6146 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6147 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6148 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6149 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6151 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6152 idxStride = 2;
6153 } else {
6154 idxStride = 4;
6157 /* release the stream and index data */
6158 if (This->stateBlock->streamSource[0] != NULL) {
6159 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6161 if (This->stateBlock->pIndexData) {
6162 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6165 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6166 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6167 This->stateBlock->streamIsUP = TRUE;
6168 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6170 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6172 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6173 This->stateBlock->streamSource[0] = NULL;
6174 This->stateBlock->streamStride[0] = 0;
6175 This->stateBlock->pIndexData = NULL;
6177 return WINED3D_OK;
6180 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6182 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6183 return WINED3D_OK;
6185 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6186 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6188 HRESULT hr = WINED3D_OK;
6189 WINED3DRESOURCETYPE sourceType;
6190 WINED3DRESOURCETYPE destinationType;
6191 int i ,levels;
6193 /* TODO: think about moving the code into IWineD3DBaseTexture */
6195 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6197 /* verify that the source and destination textures aren't NULL */
6198 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6199 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6200 This, pSourceTexture, pDestinationTexture);
6201 hr = WINED3DERR_INVALIDCALL;
6204 if (pSourceTexture == pDestinationTexture) {
6205 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6206 This, pSourceTexture, pDestinationTexture);
6207 hr = WINED3DERR_INVALIDCALL;
6209 /* Verify that the source and destination textures are the same type */
6210 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6211 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6213 if (sourceType != destinationType) {
6214 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6215 This);
6216 hr = WINED3DERR_INVALIDCALL;
6219 /* check that both textures have the identical numbers of levels */
6220 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6221 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6222 hr = WINED3DERR_INVALIDCALL;
6225 if (WINED3D_OK == hr) {
6227 /* Make sure that the destination texture is loaded */
6228 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6230 /* Update every surface level of the texture */
6231 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6233 switch (sourceType) {
6234 case WINED3DRTYPE_TEXTURE:
6236 IWineD3DSurface *srcSurface;
6237 IWineD3DSurface *destSurface;
6239 for (i = 0 ; i < levels ; ++i) {
6240 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6241 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6242 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6243 IWineD3DSurface_Release(srcSurface);
6244 IWineD3DSurface_Release(destSurface);
6245 if (WINED3D_OK != hr) {
6246 WARN("(%p) : Call to update surface failed\n", This);
6247 return hr;
6251 break;
6252 case WINED3DRTYPE_CUBETEXTURE:
6254 IWineD3DSurface *srcSurface;
6255 IWineD3DSurface *destSurface;
6256 WINED3DCUBEMAP_FACES faceType;
6258 for (i = 0 ; i < levels ; ++i) {
6259 /* Update each cube face */
6260 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6261 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6262 if (WINED3D_OK != hr) {
6263 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6264 } else {
6265 TRACE("Got srcSurface %p\n", srcSurface);
6267 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6268 if (WINED3D_OK != hr) {
6269 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6270 } else {
6271 TRACE("Got desrSurface %p\n", destSurface);
6273 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6274 IWineD3DSurface_Release(srcSurface);
6275 IWineD3DSurface_Release(destSurface);
6276 if (WINED3D_OK != hr) {
6277 WARN("(%p) : Call to update surface failed\n", This);
6278 return hr;
6283 break;
6284 #if 0 /* TODO: Add support for volume textures */
6285 case WINED3DRTYPE_VOLUMETEXTURE:
6287 IWineD3DVolume srcVolume = NULL;
6288 IWineD3DSurface destVolume = NULL;
6290 for (i = 0 ; i < levels ; ++i) {
6291 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6292 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6293 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6294 IWineD3DVolume_Release(srcSurface);
6295 IWineD3DVolume_Release(destSurface);
6296 if (WINED3D_OK != hr) {
6297 WARN("(%p) : Call to update volume failed\n", This);
6298 return hr;
6302 break;
6303 #endif
6304 default:
6305 FIXME("(%p) : Unsupported source and destination type\n", This);
6306 hr = WINED3DERR_INVALIDCALL;
6310 return hr;
6313 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6314 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6315 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6318 TRACE("(%p) : stub\n", This);
6319 return WINED3D_OK;
6321 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6323 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6324 * NOTE It may be best to move the code into surface to occomplish this
6325 ****************************************/
6327 WINED3DSURFACE_DESC surfaceDesc;
6328 unsigned int surfaceWidth, surfaceHeight;
6329 glDescriptor *targetGlDescription = NULL;
6330 glDescriptor *surfaceGlDescription = NULL;
6331 IWineD3DSwapChainImpl *container = NULL;
6333 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6334 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6335 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6337 surfaceDesc.Width = &surfaceWidth;
6338 surfaceDesc.Height = &surfaceHeight;
6339 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6340 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6342 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6343 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6344 ENTER_GL();
6345 /* TODO: opengl Context switching for swapchains etc... */
6346 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6347 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6348 glReadBuffer(GL_BACK);
6349 vcheckGLcall("glReadBuffer(GL_BACK)");
6350 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6351 glReadBuffer(GL_FRONT);
6352 vcheckGLcall("glReadBuffer(GL_FRONT)");
6353 } else if (pRenderTarget == This->depthStencilBuffer) {
6354 FIXME("Reading of depthstencil not yet supported\n");
6357 glReadPixels(surfaceGlDescription->target,
6358 surfaceGlDescription->level,
6359 surfaceWidth,
6360 surfaceHeight,
6361 surfaceGlDescription->glFormat,
6362 surfaceGlDescription->glType,
6363 (void *)IWineD3DSurface_GetData(pSurface));
6364 vcheckGLcall("glReadPixels(...)");
6365 if(NULL != container ){
6366 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6368 } else {
6369 IWineD3DBaseTexture *container;
6370 GLenum textureDimensions = GL_TEXTURE_2D;
6372 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6373 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6374 IWineD3DBaseTexture_Release(container);
6376 /* TODO: 2D -> Cube surface coppies etc.. */
6377 if (surfaceGlDescription->target != textureDimensions) {
6378 FIXME("(%p) : Texture dimension mismatch\n", This);
6380 glEnable(textureDimensions);
6381 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6382 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6383 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6384 vcheckGLcall("glBindTexture");
6385 glGetTexImage(surfaceGlDescription->target,
6386 surfaceGlDescription->level,
6387 surfaceGlDescription->glFormat,
6388 surfaceGlDescription->glType,
6389 (void *)IWineD3DSurface_GetData(pSurface));
6390 glDisable(textureDimensions);
6391 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6394 LEAVE_GL();
6395 return WINED3D_OK;
6398 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6399 IWineD3DSwapChain *swapChain;
6400 HRESULT hr;
6401 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6402 if(hr == WINED3D_OK) {
6403 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6404 IWineD3DSwapChain_Release(swapChain);
6406 return hr;
6409 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6411 /* return a sensible default */
6412 *pNumPasses = 1;
6413 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6414 FIXME("(%p) : stub\n", This);
6415 return WINED3D_OK;
6418 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 int j;
6421 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6422 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6423 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6424 return WINED3DERR_INVALIDCALL;
6426 for (j = 0; j < 256; ++j) {
6427 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6428 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6429 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6430 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6432 TRACE("(%p) : returning\n", This);
6433 return WINED3D_OK;
6436 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6438 int j;
6439 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6440 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6441 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6442 return WINED3DERR_INVALIDCALL;
6444 for (j = 0; j < 256; ++j) {
6445 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6446 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6447 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6448 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6450 TRACE("(%p) : returning\n", This);
6451 return WINED3D_OK;
6454 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6456 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6457 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6458 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6459 return WINED3DERR_INVALIDCALL;
6461 /*TODO: stateblocks */
6462 This->currentPalette = PaletteNumber;
6463 TRACE("(%p) : returning\n", This);
6464 return WINED3D_OK;
6467 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6469 if (PaletteNumber == NULL) {
6470 WARN("(%p) : returning Invalid Call\n", This);
6471 return WINED3DERR_INVALIDCALL;
6473 /*TODO: stateblocks */
6474 *PaletteNumber = This->currentPalette;
6475 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6476 return WINED3D_OK;
6479 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 static BOOL showFixmes = TRUE;
6482 if (showFixmes) {
6483 FIXME("(%p) : stub\n", This);
6484 showFixmes = FALSE;
6487 This->softwareVertexProcessing = bSoftware;
6488 return WINED3D_OK;
6492 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6494 static BOOL showFixmes = TRUE;
6495 if (showFixmes) {
6496 FIXME("(%p) : stub\n", This);
6497 showFixmes = FALSE;
6499 return This->softwareVertexProcessing;
6503 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 IWineD3DSwapChain *swapChain;
6506 HRESULT hr;
6508 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6510 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6511 if(hr == WINED3D_OK){
6512 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6513 IWineD3DSwapChain_Release(swapChain);
6514 }else{
6515 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6517 return hr;
6521 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6523 static BOOL showfixmes = TRUE;
6524 if(nSegments != 0.0f) {
6525 if( showfixmes) {
6526 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6527 showfixmes = FALSE;
6530 return WINED3D_OK;
6533 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6535 static BOOL showfixmes = TRUE;
6536 if( showfixmes) {
6537 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6538 showfixmes = FALSE;
6540 return 0.0f;
6543 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6545 /** TODO: remove casts to IWineD3DSurfaceImpl
6546 * NOTE: move code to surface to accomplish this
6547 ****************************************/
6548 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6549 int srcWidth, srcHeight;
6550 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6551 WINED3DFORMAT destFormat, srcFormat;
6552 UINT destSize;
6553 int destLeft, destTop;
6554 WINED3DPOOL srcPool, destPool;
6555 int offset = 0;
6556 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6557 glDescriptor *glDescription = NULL;
6558 GLenum textureDimensions = GL_TEXTURE_2D;
6559 IWineD3DBaseTexture *baseTexture;
6561 WINED3DSURFACE_DESC winedesc;
6563 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6564 memset(&winedesc, 0, sizeof(winedesc));
6565 winedesc.Width = &srcSurfaceWidth;
6566 winedesc.Height = &srcSurfaceHeight;
6567 winedesc.Pool = &srcPool;
6568 winedesc.Format = &srcFormat;
6570 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6572 winedesc.Width = &destSurfaceWidth;
6573 winedesc.Height = &destSurfaceHeight;
6574 winedesc.Pool = &destPool;
6575 winedesc.Format = &destFormat;
6576 winedesc.Size = &destSize;
6578 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6580 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6581 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6582 return WINED3DERR_INVALIDCALL;
6585 if (destFormat == WINED3DFMT_UNKNOWN) {
6586 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6587 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6589 /* Get the update surface description */
6590 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6593 /* Make sure the surface is loaded and up to date */
6594 IWineD3DSurface_PreLoad(pDestinationSurface);
6596 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6598 ENTER_GL();
6600 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6601 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6602 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6603 destLeft = pDestPoint ? pDestPoint->x : 0;
6604 destTop = pDestPoint ? pDestPoint->y : 0;
6607 /* This function doesn't support compressed textures
6608 the pitch is just bytesPerPixel * width */
6609 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6610 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6611 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6612 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6614 /* TODO DXT formats */
6616 if(pSourceRect != NULL && pSourceRect->top != 0){
6617 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6619 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6620 ,This
6621 ,glDescription->level
6622 ,destLeft
6623 ,destTop
6624 ,srcWidth
6625 ,srcHeight
6626 ,glDescription->glFormat
6627 ,glDescription->glType
6628 ,IWineD3DSurface_GetData(pSourceSurface)
6631 /* Sanity check */
6632 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6634 /* need to lock the surface to get the data */
6635 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6638 /* TODO: Cube and volume support */
6639 if(rowoffset != 0){
6640 /* not a whole row so we have to do it a line at a time */
6641 int j;
6643 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6644 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6646 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6648 glTexSubImage2D(glDescription->target
6649 ,glDescription->level
6650 ,destLeft
6652 ,srcWidth
6654 ,glDescription->glFormat
6655 ,glDescription->glType
6656 ,data /* could be quicker using */
6658 data += rowoffset;
6661 } else { /* Full width, so just write out the whole texture */
6663 if (WINED3DFMT_DXT1 == destFormat ||
6664 WINED3DFMT_DXT2 == destFormat ||
6665 WINED3DFMT_DXT3 == destFormat ||
6666 WINED3DFMT_DXT4 == destFormat ||
6667 WINED3DFMT_DXT5 == destFormat) {
6668 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6669 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6670 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6671 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6672 } if (destFormat != srcFormat) {
6673 FIXME("Updating mixed format compressed texture is not curretly support\n");
6674 } else {
6675 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6676 glDescription->level,
6677 glDescription->glFormatInternal,
6678 srcWidth,
6679 srcHeight,
6681 destSize,
6682 IWineD3DSurface_GetData(pSourceSurface));
6684 } else {
6685 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6689 } else {
6690 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6692 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6693 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6694 data returned by GetData non-power2 width/height with hardware non-power2
6695 pow2Width/height are set to surface width height, repacking isn't needed so it
6696 doesn't matter which function gets called. */
6697 glTexSubImage2D(glDescription->target
6698 ,glDescription->level
6699 ,destLeft
6700 ,destTop
6701 ,srcWidth
6702 ,srcHeight
6703 ,glDescription->glFormat
6704 ,glDescription->glType
6705 ,IWineD3DSurface_GetData(pSourceSurface)
6707 } else {
6709 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6710 glTexSubImage2D(glDescription->target
6711 ,glDescription->level
6712 ,destLeft
6713 ,destTop
6714 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6715 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6716 ,glDescription->glFormat
6717 ,glDescription->glType
6718 ,IWineD3DSurface_GetData(pSourceSurface)
6724 checkGLcall("glTexSubImage2D");
6726 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6727 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6728 * surface bigger than it needs to be hmm.. */
6729 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6730 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6731 IWineD3DBaseTexture_Release(baseTexture);
6734 glDisable(textureDimensions); /* This needs to be managed better.... */
6735 LEAVE_GL();
6737 return WINED3D_OK;
6740 /* Used by DirectX 8 */
6741 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6742 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6743 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6746 HRESULT hr = WINED3D_OK;
6747 WINED3DFORMAT srcFormat, destFormat;
6748 UINT srcWidth, destWidth;
6749 UINT srcHeight, destHeight;
6750 UINT srcSize;
6751 WINED3DSURFACE_DESC winedesc;
6753 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6754 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6757 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6758 memset(&winedesc, 0, sizeof(winedesc));
6760 winedesc.Format = &srcFormat;
6761 winedesc.Width = &srcWidth;
6762 winedesc.Height = &srcHeight;
6763 winedesc.Size = &srcSize;
6764 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6766 winedesc.Format = &destFormat;
6767 winedesc.Width = &destWidth;
6768 winedesc.Height = &destHeight;
6769 winedesc.Size = NULL;
6770 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6772 /* Check that the source and destination formats match */
6773 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6774 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6775 return WINED3DERR_INVALIDCALL;
6776 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6777 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6778 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6779 destFormat = srcFormat;
6782 /* Quick if complete copy ... */
6783 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6785 if (srcWidth == destWidth && srcHeight == destHeight) {
6786 WINED3DLOCKED_RECT lrSrc;
6787 WINED3DLOCKED_RECT lrDst;
6788 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6789 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6790 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6792 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6794 IWineD3DSurface_UnlockRect(pSourceSurface);
6795 IWineD3DSurface_UnlockRect(pDestinationSurface);
6796 TRACE("Unlocked src and dst\n");
6798 } else {
6800 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6801 hr = WINED3DERR_INVALIDCALL;
6804 } else {
6806 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6808 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6809 unsigned int i;
6811 /* Copy rect by rect */
6812 for (i = 0; i < cRects; ++i) {
6813 CONST RECT* r = &pSourceRectsArray[i];
6814 CONST POINT* p = &pDestPointsArray[i];
6815 int copyperline;
6816 int j;
6817 WINED3DLOCKED_RECT lrSrc;
6818 WINED3DLOCKED_RECT lrDst;
6819 RECT dest_rect;
6821 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6822 if (srcFormat == WINED3DFMT_DXT1) {
6823 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6824 } else {
6825 copyperline = ((r->right - r->left) * bytesPerPixel);
6828 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6829 dest_rect.left = p->x;
6830 dest_rect.top = p->y;
6831 dest_rect.right = p->x + (r->right - r->left);
6832 dest_rect.bottom= p->y + (r->bottom - r->top);
6833 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6834 TRACE("Locked src and dst\n");
6836 /* Find where to start */
6837 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6838 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6840 IWineD3DSurface_UnlockRect(pSourceSurface);
6841 IWineD3DSurface_UnlockRect(pDestinationSurface);
6842 TRACE("Unlocked src and dst\n");
6844 } else {
6845 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6846 hr = WINED3DERR_INVALIDCALL;
6850 return hr;
6853 /* Implementation details at http://developer.nvidia.com/attach/6494
6855 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6856 hmm.. no longer supported use
6857 OpenGL evaluators or tessellate surfaces within your application.
6860 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6861 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6863 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6864 FIXME("(%p) : Stub\n", This);
6865 return WINED3D_OK;
6869 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6870 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6872 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6873 FIXME("(%p) : Stub\n", This);
6874 return WINED3D_OK;
6877 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6879 TRACE("(%p) Handle(%d)\n", This, Handle);
6880 FIXME("(%p) : Stub\n", This);
6881 return WINED3D_OK;
6884 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6885 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6886 fill a surface with a block of color! */
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6888 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6889 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6890 IWineD3DSwapChainImpl *container = NULL;
6891 BOOL isRenderTarget = FALSE;
6892 unsigned int width, height;
6893 unsigned int top, left;
6894 unsigned int u, v;
6895 DWORD *data;
6896 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6898 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6899 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6900 return WINED3DERR_INVALIDCALL;
6903 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6904 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6905 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6906 /* TODO: make sure we set everything back to the way it was, and context management!
6907 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6908 vcheckGLcall("glIntegerv");
6909 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6910 vcheckGLcall("glIntegerv");
6912 TRACE("Color fill to render targets may cause some graphics issues\n");
6913 if (pSurface == container->frontBuffer) {
6914 glDrawBuffer(GL_FRONT);
6915 } else {
6916 glDrawBuffer(GL_BACK);
6918 } else {
6919 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6920 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6921 } else {
6922 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6924 if (container != NULL) {
6925 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6927 /* we can use GL_STENCIL_INDEX etc...*/
6928 return WINED3D_OK;
6930 if (container != NULL) {
6931 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6933 isRenderTarget = TRUE;
6935 /* TODO: drawing to GL_FRONT and GL_BACK */
6936 /* TODO: see if things can be speeded up by using the correct
6937 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6938 if (pRect == NULL) {
6939 top = 0;
6940 left = 0;
6941 width = surface->currentDesc.Width;
6942 height = surface->currentDesc.Height;
6943 } else {
6944 left = pRect->x1;
6945 top = pRect->y1;
6946 width = pRect->x2 - left;
6947 height = pRect->y2 - top;
6950 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6951 /* Create a 'line' of color color, in the correct format for the surface */
6952 for (u = 0 ; u < width ; u ++) {
6953 data[u] = color;
6956 ENTER_GL();
6957 if (isRenderTarget == FALSE) {
6958 glDescriptor *glDesc;
6959 IWineD3DSurface_PreLoad(pSurface);
6961 /* draw a block of the coloured line on the sufrace */
6962 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6963 for (v = 0 ; v< height;v++) {
6964 glTexSubImage2D(glDesc->target
6965 ,glDesc->level /* level */
6966 ,left
6967 ,top + v
6968 ,width
6969 ,1 /* height */
6970 ,GL_RGBA
6971 ,GL_UNSIGNED_BYTE
6972 ,data
6975 checkGLcall("glTexSubImage2D");
6976 /* clean up */
6977 glDisable(glDesc->target);
6978 } else {
6979 /** FIXME: Using GLClear may be faster **/
6980 glRasterPos2i(left, top);
6981 glPixelZoom((float)width ,(float)height);
6982 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6983 checkGLcall("glDrawPixels");
6985 HeapFree(GetProcessHeap(), 0, data);
6986 LEAVE_GL();
6987 return WINED3D_OK;
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 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7290 * the functionality needs splitting up so that we don't do more than we should do.
7291 * this only seems to impact performance a little.
7292 ******************************/
7293 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7294 IWineD3DSurface *RenderSurface) {
7295 HRESULT ret = WINED3DERR_INVALIDCALL;
7298 * Currently only active for GLX >= 1.3
7299 * for others versions we'll have to use GLXPixmaps
7301 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7302 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7303 * so only check OpenGL version
7304 * ..........................
7305 * I don't believe that it is a problem with NVidia headers,
7306 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7307 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7308 * ATI Note:
7309 * Your application will report GLX version 1.2 on glXQueryVersion.
7310 * However, it is safe to call the GLX 1.3 functions as described below.
7312 #if defined(GL_VERSION_1_3)
7314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7315 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7316 IWineD3DSurface *tmp;
7317 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7318 GLXFBConfig* cfgs = NULL;
7319 int nCfgs = 0;
7320 int attribs[256];
7321 int nAttribs = 0;
7322 IWineD3DSwapChain *currentSwapchain;
7323 IWineD3DSwapChainImpl *swapchain;
7324 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7325 * but switch them off if the StencilSurface is set to NULL
7326 ** *********************************************************/
7327 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7328 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7330 /**TODO:
7331 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7332 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7335 #define PUSH1(att) attribs[nAttribs++] = (att);
7336 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7338 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7340 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7341 IWineD3DSwapChainImpl *impSwapChain;
7342 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7343 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7344 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7347 ENTER_GL();
7349 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7350 PUSH2(GLX_X_RENDERABLE, TRUE);
7351 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7352 TRACE("calling makeglcfg\n");
7353 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7354 PUSH1(None);
7356 TRACE("calling chooseFGConfig\n");
7357 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7358 attribs, &nCfgs);
7360 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7361 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7362 why we failed and only show this message once! */
7363 MESSAGE("Failed to find exact match, finding alternative but you may suffer performance issues, try changing xfree's depth to match the requested depth\n"); /**/
7364 nAttribs = 0;
7365 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7366 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7367 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7368 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7369 TRACE("calling makeglcfg\n");
7370 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7371 PUSH1(None);
7372 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7373 attribs, &nCfgs);
7376 if (NULL != cfgs) {
7377 #ifdef EXTRA_TRACES
7378 int i;
7379 for (i = 0; i < nCfgs; ++i) {
7380 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7381 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7382 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7385 if (NULL != This->renderTarget) {
7386 glFlush();
7387 vcheckGLcall("glFlush");
7388 /** This is only useful if the old render target was a swapchain,
7389 * we need to supercede this with a function that displays
7390 * the current buffer on the screen. This is easy to do in glx1.3 but
7391 * we need to do copy-write pixels in glx 1.2.
7392 ************************************************/
7393 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7395 printf("Hit Enter to get next frame ...\n");
7396 getchar();
7398 #endif
7401 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7402 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7403 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7407 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7408 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7409 **********************************************************************/
7410 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7411 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7412 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7413 TRACE("making swapchain active\n");
7414 if (RenderSurface != This->renderTarget) {
7415 BOOL backbuf = FALSE;
7416 int i;
7418 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7419 if(RenderSurface == swapchain->backBuffer[i]) {
7420 backbuf = TRUE;
7421 break;
7425 if (backbuf) {
7426 } else {
7427 /* This could be flagged so that some operations work directly with the front buffer */
7428 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7430 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7431 == False) {
7432 TRACE("Error in setting current context: context %p drawable %ld !\n",
7433 impSwapChain->glCtx, impSwapChain->win);
7436 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7438 checkGLcall("glXMakeContextCurrent");
7440 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7442 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7444 /** ********************************************************************
7445 * This is a quickly hacked out implementation of offscreen textures.
7446 * It will work in most cases but there may be problems if the client
7447 * modifies the texture directly, or expects the contents of the rendertarget
7448 * to be persistent.
7450 * There are some real speed vs compatibility issues here:
7451 * we should really use a new context for every texture, but that eats ram.
7452 * we should also be restoring the texture to the pbuffer but that eats CPU
7453 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7454 * but if this means reusing the display backbuffer then we need to make sure that
7455 * states are correctly preserved.
7456 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7457 * and gain a good performance increase at the cost of compatibility.
7458 * I would suggest that, when this is the case, a user configurable flag be made
7459 * available, allowing the user to choose the best emulated experience for them.
7460 *********************************************************************/
7462 XVisualInfo *visinfo;
7463 glContext *newContext;
7465 /* Here were using a shared context model */
7466 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7467 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7470 /* If the context doesn't exist then create a new one */
7471 /* TODO: This should really be part of findGlContext */
7472 if (NULL == newContext->context) {
7474 TRACE("making new buffer\n");
7475 nAttribs = 0;
7476 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7477 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7478 PUSH1(None);
7480 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7482 /** ****************************************
7483 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7484 *they note:
7485 * In future releases, we may provide the calls glXCreateNewContext,
7486 * glXQueryDrawable and glXMakeContextCurrent.
7487 * so until then we have to use glXGetVisualFromFBConfig &co..
7488 ********************************************/
7491 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7492 if (!visinfo) {
7493 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7494 } else {
7495 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7496 XFree(visinfo);
7499 if (NULL == newContext || NULL == newContext->context) {
7500 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7501 } else {
7502 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7503 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7504 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7507 /* Clean up the old context */
7508 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7509 /* Set the current context of the swapchain to the new context */
7510 impSwapChain->drawable = newContext->drawable;
7511 impSwapChain->render_ctx = newContext->context;
7515 #if 1 /* Apply the stateblock to the new context
7516 FIXME: This is a bit of a hack, each context should know it's own state,
7517 the directX current directX state should then be applied to the context */
7519 BOOL oldRecording;
7520 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7521 oldUpdateStateBlock = This->updateStateBlock;
7522 oldRecording= This->isRecordingState;
7523 This->isRecordingState = FALSE;
7524 This->updateStateBlock = This->stateBlock;
7525 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7527 This->isRecordingState = oldRecording;
7528 This->updateStateBlock = oldUpdateStateBlock;
7530 #endif
7533 /* clean up the current rendertargets swapchain (if it belonged to one) */
7534 if (currentSwapchain != NULL) {
7535 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7538 /* Were done with the opengl context management, setup the rendertargets */
7540 tmp = This->renderTarget;
7541 This->renderTarget = RenderSurface;
7542 IWineD3DSurface_AddRef(This->renderTarget);
7543 IWineD3DSurface_Release(tmp);
7548 DWORD value;
7549 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7550 /* Check that the container is not a swapchain member */
7552 IWineD3DSwapChain *tmpSwapChain;
7553 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7554 This->renderUpsideDown = TRUE;
7555 }else{
7556 This->renderUpsideDown = FALSE;
7557 IWineD3DSwapChain_Release(tmpSwapChain);
7559 /* Force updating the cull mode */
7560 TRACE("setting render state\n");
7561 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7562 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7564 /* Force updating projection matrix */
7565 This->last_was_rhw = FALSE;
7566 This->proj_valid = FALSE;
7569 ret = WINED3D_OK;
7571 if (cfgs != NULL) {
7572 XFree(cfgs);
7573 } else {
7574 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7575 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7578 #undef PUSH1
7579 #undef PUSH2
7580 if ( NULL != impSwapChain) {
7581 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7583 LEAVE_GL();
7585 #endif
7586 return ret;
7589 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7590 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7592 /* TODO: the use of Impl is deprecated. */
7593 /* some basic validation checks */
7594 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7596 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7598 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7599 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7600 return WINED3DERR_INVALIDCALL;
7602 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7603 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7604 return WINED3DERR_INVALIDCALL;
7606 /* TODO: make the cursor 'real' */
7608 This->xHotSpot = XHotSpot;
7609 This->yHotSpot = YHotSpot;
7611 return WINED3D_OK;
7614 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7616 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7618 This->xScreenSpace = XScreenSpace;
7619 This->yScreenSpace = YScreenSpace;
7621 return;
7625 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7627 TRACE("(%p) : visible(%d)\n", This, bShow);
7629 This->bCursorVisible = bShow;
7631 return WINED3D_OK;
7634 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7636 TRACE("(%p) : state (%lu)\n", This, This->state);
7637 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7638 switch (This->state) {
7639 case WINED3D_OK:
7640 return WINED3D_OK;
7641 case WINED3DERR_DEVICELOST:
7643 ResourceList *resourceList = This->resources;
7644 while (NULL != resourceList) {
7645 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7646 return WINED3DERR_DEVICENOTRESET;
7647 resourceList = resourceList->next;
7649 return WINED3DERR_DEVICELOST;
7651 case WINED3DERR_DRIVERINTERNALERROR:
7652 return WINED3DERR_DRIVERINTERNALERROR;
7655 /* Unknown state */
7656 return WINED3DERR_DRIVERINTERNALERROR;
7660 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7662 /** FIXME: Resource tracking needs to be done,
7663 * The closes we can do to this is set the priorities of all managed textures low
7664 * and then reset them.
7665 ***********************************************************/
7666 FIXME("(%p) : stub\n", This);
7667 return WINED3D_OK;
7670 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7672 /** FIXME: Resource trascking needs to be done.
7673 * in effect this pulls all non only default
7674 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7675 * and should clear down the context and set it up according to pPresentationParameters
7676 ***********************************************************/
7677 FIXME("(%p) : stub\n", This);
7678 return WINED3D_OK;
7681 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7683 /** FIXME: always true at the moment **/
7684 if(bEnableDialogs == FALSE) {
7685 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7687 return WINED3D_OK;
7691 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7693 TRACE("(%p) : pParameters %p\n", This, pParameters);
7695 *pParameters = This->createParms;
7696 return WINED3D_OK;
7699 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7700 IWineD3DSwapChain *swapchain;
7701 HRESULT hrc = WINED3D_OK;
7703 TRACE("Relaying to swapchain\n");
7705 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7706 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7707 IWineD3DSwapChain_Release(swapchain);
7709 return;
7712 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7713 IWineD3DSwapChain *swapchain;
7714 HRESULT hrc = WINED3D_OK;
7716 TRACE("Relaying to swapchain\n");
7718 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7719 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7720 IWineD3DSwapChain_Release(swapchain);
7722 return;
7726 /** ********************************************************
7727 * Notification functions
7728 ** ********************************************************/
7729 /** This function must be called in the release of a resource when ref == 0,
7730 * the contents of resource must still be correct,
7731 * any handels to other resource held by the caller must be closed
7732 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7733 *****************************************************/
7734 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7736 ResourceList* resourceList;
7738 TRACE("(%p) : resource %p\n", This, resource);
7739 #if 0
7740 EnterCriticalSection(&resourceStoreCriticalSection);
7741 #endif
7742 /* add a new texture to the frot of the linked list */
7743 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7744 resourceList->resource = resource;
7746 /* Get the old head */
7747 resourceList->next = This->resources;
7749 This->resources = resourceList;
7750 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7752 #if 0
7753 LeaveCriticalSection(&resourceStoreCriticalSection);
7754 #endif
7755 return;
7758 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7760 ResourceList* resourceList = NULL;
7761 ResourceList* previousResourceList = NULL;
7763 TRACE("(%p) : resource %p\n", This, resource);
7765 #if 0
7766 EnterCriticalSection(&resourceStoreCriticalSection);
7767 #endif
7768 resourceList = This->resources;
7770 while (resourceList != NULL) {
7771 if(resourceList->resource == resource) break;
7772 previousResourceList = resourceList;
7773 resourceList = resourceList->next;
7776 if (resourceList == NULL) {
7777 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7778 #if 0
7779 LeaveCriticalSection(&resourceStoreCriticalSection);
7780 #endif
7781 return;
7782 } else {
7783 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7785 /* make sure we don't leave a hole in the list */
7786 if (previousResourceList != NULL) {
7787 previousResourceList->next = resourceList->next;
7788 } else {
7789 This->resources = resourceList->next;
7792 #if 0
7793 LeaveCriticalSection(&resourceStoreCriticalSection);
7794 #endif
7795 return;
7799 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7801 int counter;
7803 TRACE("(%p) : resource %p\n", This, resource);
7804 switch(IWineD3DResource_GetType(resource)){
7805 case WINED3DRTYPE_SURFACE:
7806 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7807 break;
7808 case WINED3DRTYPE_TEXTURE:
7809 case WINED3DRTYPE_CUBETEXTURE:
7810 case WINED3DRTYPE_VOLUMETEXTURE:
7811 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7812 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7813 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7814 This->stateBlock->textures[counter] = NULL;
7816 if (This->updateStateBlock != This->stateBlock ){
7817 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7818 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7819 This->updateStateBlock->textures[counter] = NULL;
7823 break;
7824 case WINED3DRTYPE_VOLUME:
7825 /* TODO: nothing really? */
7826 break;
7827 case WINED3DRTYPE_VERTEXBUFFER:
7828 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7830 int streamNumber;
7831 TRACE("Cleaning up stream pointers\n");
7833 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7834 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7835 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7837 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7838 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7839 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7840 This->updateStateBlock->streamSource[streamNumber] = 0;
7841 /* Set changed flag? */
7844 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) */
7845 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7846 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7847 This->stateBlock->streamSource[streamNumber] = 0;
7850 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7851 else { /* This shouldn't happen */
7852 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7854 #endif
7858 break;
7859 case WINED3DRTYPE_INDEXBUFFER:
7860 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7861 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7862 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7863 This->updateStateBlock->pIndexData = NULL;
7866 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7867 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7868 This->stateBlock->pIndexData = NULL;
7872 break;
7873 default:
7874 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7875 break;
7879 /* Remove the resoruce from the resourceStore */
7880 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7882 TRACE("Resource released\n");
7886 /**********************************************************
7887 * IWineD3DDevice VTbl follows
7888 **********************************************************/
7890 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7892 /*** IUnknown methods ***/
7893 IWineD3DDeviceImpl_QueryInterface,
7894 IWineD3DDeviceImpl_AddRef,
7895 IWineD3DDeviceImpl_Release,
7896 /*** IWineD3DDevice methods ***/
7897 IWineD3DDeviceImpl_GetParent,
7898 /*** Creation methods**/
7899 IWineD3DDeviceImpl_CreateVertexBuffer,
7900 IWineD3DDeviceImpl_CreateIndexBuffer,
7901 IWineD3DDeviceImpl_CreateStateBlock,
7902 IWineD3DDeviceImpl_CreateSurface,
7903 IWineD3DDeviceImpl_CreateTexture,
7904 IWineD3DDeviceImpl_CreateVolumeTexture,
7905 IWineD3DDeviceImpl_CreateVolume,
7906 IWineD3DDeviceImpl_CreateCubeTexture,
7907 IWineD3DDeviceImpl_CreateQuery,
7908 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7909 IWineD3DDeviceImpl_CreateVertexDeclaration,
7910 IWineD3DDeviceImpl_CreateVertexShader,
7911 IWineD3DDeviceImpl_CreatePixelShader,
7912 IWineD3DDeviceImpl_CreatePalette,
7913 /*** Odd functions **/
7914 IWineD3DDeviceImpl_Init3D,
7915 IWineD3DDeviceImpl_Uninit3D,
7916 IWineD3DDeviceImpl_EnumDisplayModes,
7917 IWineD3DDeviceImpl_EvictManagedResources,
7918 IWineD3DDeviceImpl_GetAvailableTextureMem,
7919 IWineD3DDeviceImpl_GetBackBuffer,
7920 IWineD3DDeviceImpl_GetCreationParameters,
7921 IWineD3DDeviceImpl_GetDeviceCaps,
7922 IWineD3DDeviceImpl_GetDirect3D,
7923 IWineD3DDeviceImpl_GetDisplayMode,
7924 IWineD3DDeviceImpl_SetDisplayMode,
7925 IWineD3DDeviceImpl_GetHWND,
7926 IWineD3DDeviceImpl_SetHWND,
7927 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7928 IWineD3DDeviceImpl_GetRasterStatus,
7929 IWineD3DDeviceImpl_GetSwapChain,
7930 IWineD3DDeviceImpl_Reset,
7931 IWineD3DDeviceImpl_SetDialogBoxMode,
7932 IWineD3DDeviceImpl_SetCursorProperties,
7933 IWineD3DDeviceImpl_SetCursorPosition,
7934 IWineD3DDeviceImpl_ShowCursor,
7935 IWineD3DDeviceImpl_TestCooperativeLevel,
7936 IWineD3DDeviceImpl_EnumZBufferFormats,
7937 IWineD3DDeviceImpl_EnumTextureFormats,
7938 /*** Getters and setters **/
7939 IWineD3DDeviceImpl_SetClipPlane,
7940 IWineD3DDeviceImpl_GetClipPlane,
7941 IWineD3DDeviceImpl_SetClipStatus,
7942 IWineD3DDeviceImpl_GetClipStatus,
7943 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7944 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7945 IWineD3DDeviceImpl_SetDepthStencilSurface,
7946 IWineD3DDeviceImpl_GetDepthStencilSurface,
7947 IWineD3DDeviceImpl_SetFVF,
7948 IWineD3DDeviceImpl_GetFVF,
7949 IWineD3DDeviceImpl_SetGammaRamp,
7950 IWineD3DDeviceImpl_GetGammaRamp,
7951 IWineD3DDeviceImpl_SetIndices,
7952 IWineD3DDeviceImpl_GetIndices,
7953 IWineD3DDeviceImpl_SetLight,
7954 IWineD3DDeviceImpl_GetLight,
7955 IWineD3DDeviceImpl_SetLightEnable,
7956 IWineD3DDeviceImpl_GetLightEnable,
7957 IWineD3DDeviceImpl_SetMaterial,
7958 IWineD3DDeviceImpl_GetMaterial,
7959 IWineD3DDeviceImpl_SetNPatchMode,
7960 IWineD3DDeviceImpl_GetNPatchMode,
7961 IWineD3DDeviceImpl_SetPaletteEntries,
7962 IWineD3DDeviceImpl_GetPaletteEntries,
7963 IWineD3DDeviceImpl_SetPixelShader,
7964 IWineD3DDeviceImpl_GetPixelShader,
7965 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7966 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7967 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7968 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7969 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7970 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7971 IWineD3DDeviceImpl_SetRenderState,
7972 IWineD3DDeviceImpl_GetRenderState,
7973 IWineD3DDeviceImpl_SetRenderTarget,
7974 IWineD3DDeviceImpl_GetRenderTarget,
7975 IWineD3DDeviceImpl_SetFrontBackBuffers,
7976 IWineD3DDeviceImpl_SetSamplerState,
7977 IWineD3DDeviceImpl_GetSamplerState,
7978 IWineD3DDeviceImpl_SetScissorRect,
7979 IWineD3DDeviceImpl_GetScissorRect,
7980 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7981 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7982 IWineD3DDeviceImpl_SetStreamSource,
7983 IWineD3DDeviceImpl_GetStreamSource,
7984 IWineD3DDeviceImpl_SetStreamSourceFreq,
7985 IWineD3DDeviceImpl_GetStreamSourceFreq,
7986 IWineD3DDeviceImpl_SetTexture,
7987 IWineD3DDeviceImpl_GetTexture,
7988 IWineD3DDeviceImpl_SetTextureStageState,
7989 IWineD3DDeviceImpl_GetTextureStageState,
7990 IWineD3DDeviceImpl_SetTransform,
7991 IWineD3DDeviceImpl_GetTransform,
7992 IWineD3DDeviceImpl_SetVertexDeclaration,
7993 IWineD3DDeviceImpl_GetVertexDeclaration,
7994 IWineD3DDeviceImpl_SetVertexShader,
7995 IWineD3DDeviceImpl_GetVertexShader,
7996 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7997 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7998 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7999 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8000 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8001 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8002 IWineD3DDeviceImpl_SetViewport,
8003 IWineD3DDeviceImpl_GetViewport,
8004 IWineD3DDeviceImpl_MultiplyTransform,
8005 IWineD3DDeviceImpl_ValidateDevice,
8006 IWineD3DDeviceImpl_ProcessVertices,
8007 /*** State block ***/
8008 IWineD3DDeviceImpl_BeginStateBlock,
8009 IWineD3DDeviceImpl_EndStateBlock,
8010 /*** Scene management ***/
8011 IWineD3DDeviceImpl_BeginScene,
8012 IWineD3DDeviceImpl_EndScene,
8013 IWineD3DDeviceImpl_Present,
8014 IWineD3DDeviceImpl_Clear,
8015 /*** Drawing ***/
8016 IWineD3DDeviceImpl_DrawPrimitive,
8017 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8018 IWineD3DDeviceImpl_DrawPrimitiveUP,
8019 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8020 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8021 IWineD3DDeviceImpl_DrawRectPatch,
8022 IWineD3DDeviceImpl_DrawTriPatch,
8023 IWineD3DDeviceImpl_DeletePatch,
8024 IWineD3DDeviceImpl_ColorFill,
8025 IWineD3DDeviceImpl_UpdateTexture,
8026 IWineD3DDeviceImpl_UpdateSurface,
8027 IWineD3DDeviceImpl_CopyRects,
8028 IWineD3DDeviceImpl_StretchRect,
8029 IWineD3DDeviceImpl_GetRenderTargetData,
8030 IWineD3DDeviceImpl_GetFrontBufferData,
8031 /*** Internal use IWineD3DDevice methods ***/
8032 IWineD3DDeviceImpl_SetupTextureStates,
8033 /*** object tracking ***/
8034 IWineD3DDeviceImpl_ResourceReleased
8038 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8039 WINED3DRS_ALPHABLENDENABLE ,
8040 WINED3DRS_ALPHAFUNC ,
8041 WINED3DRS_ALPHAREF ,
8042 WINED3DRS_ALPHATESTENABLE ,
8043 WINED3DRS_BLENDOP ,
8044 WINED3DRS_COLORWRITEENABLE ,
8045 WINED3DRS_DESTBLEND ,
8046 WINED3DRS_DITHERENABLE ,
8047 WINED3DRS_FILLMODE ,
8048 WINED3DRS_FOGDENSITY ,
8049 WINED3DRS_FOGEND ,
8050 WINED3DRS_FOGSTART ,
8051 WINED3DRS_LASTPIXEL ,
8052 WINED3DRS_SHADEMODE ,
8053 WINED3DRS_SRCBLEND ,
8054 WINED3DRS_STENCILENABLE ,
8055 WINED3DRS_STENCILFAIL ,
8056 WINED3DRS_STENCILFUNC ,
8057 WINED3DRS_STENCILMASK ,
8058 WINED3DRS_STENCILPASS ,
8059 WINED3DRS_STENCILREF ,
8060 WINED3DRS_STENCILWRITEMASK ,
8061 WINED3DRS_STENCILZFAIL ,
8062 WINED3DRS_TEXTUREFACTOR ,
8063 WINED3DRS_WRAP0 ,
8064 WINED3DRS_WRAP1 ,
8065 WINED3DRS_WRAP2 ,
8066 WINED3DRS_WRAP3 ,
8067 WINED3DRS_WRAP4 ,
8068 WINED3DRS_WRAP5 ,
8069 WINED3DRS_WRAP6 ,
8070 WINED3DRS_WRAP7 ,
8071 WINED3DRS_ZENABLE ,
8072 WINED3DRS_ZFUNC ,
8073 WINED3DRS_ZWRITEENABLE
8076 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8077 WINED3DTSS_ADDRESSW ,
8078 WINED3DTSS_ALPHAARG0 ,
8079 WINED3DTSS_ALPHAARG1 ,
8080 WINED3DTSS_ALPHAARG2 ,
8081 WINED3DTSS_ALPHAOP ,
8082 WINED3DTSS_BUMPENVLOFFSET ,
8083 WINED3DTSS_BUMPENVLSCALE ,
8084 WINED3DTSS_BUMPENVMAT00 ,
8085 WINED3DTSS_BUMPENVMAT01 ,
8086 WINED3DTSS_BUMPENVMAT10 ,
8087 WINED3DTSS_BUMPENVMAT11 ,
8088 WINED3DTSS_COLORARG0 ,
8089 WINED3DTSS_COLORARG1 ,
8090 WINED3DTSS_COLORARG2 ,
8091 WINED3DTSS_COLOROP ,
8092 WINED3DTSS_RESULTARG ,
8093 WINED3DTSS_TEXCOORDINDEX ,
8094 WINED3DTSS_TEXTURETRANSFORMFLAGS
8097 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8098 WINED3DSAMP_ADDRESSU ,
8099 WINED3DSAMP_ADDRESSV ,
8100 WINED3DSAMP_ADDRESSW ,
8101 WINED3DSAMP_BORDERCOLOR ,
8102 WINED3DSAMP_MAGFILTER ,
8103 WINED3DSAMP_MINFILTER ,
8104 WINED3DSAMP_MIPFILTER ,
8105 WINED3DSAMP_MIPMAPLODBIAS ,
8106 WINED3DSAMP_MAXMIPLEVEL ,
8107 WINED3DSAMP_MAXANISOTROPY ,
8108 WINED3DSAMP_SRGBTEXTURE ,
8109 WINED3DSAMP_ELEMENTINDEX
8112 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8113 WINED3DRS_AMBIENT ,
8114 WINED3DRS_AMBIENTMATERIALSOURCE ,
8115 WINED3DRS_CLIPPING ,
8116 WINED3DRS_CLIPPLANEENABLE ,
8117 WINED3DRS_COLORVERTEX ,
8118 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8119 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8120 WINED3DRS_FOGDENSITY ,
8121 WINED3DRS_FOGEND ,
8122 WINED3DRS_FOGSTART ,
8123 WINED3DRS_FOGTABLEMODE ,
8124 WINED3DRS_FOGVERTEXMODE ,
8125 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8126 WINED3DRS_LIGHTING ,
8127 WINED3DRS_LOCALVIEWER ,
8128 WINED3DRS_MULTISAMPLEANTIALIAS ,
8129 WINED3DRS_MULTISAMPLEMASK ,
8130 WINED3DRS_NORMALIZENORMALS ,
8131 WINED3DRS_PATCHEDGESTYLE ,
8132 WINED3DRS_POINTSCALE_A ,
8133 WINED3DRS_POINTSCALE_B ,
8134 WINED3DRS_POINTSCALE_C ,
8135 WINED3DRS_POINTSCALEENABLE ,
8136 WINED3DRS_POINTSIZE ,
8137 WINED3DRS_POINTSIZE_MAX ,
8138 WINED3DRS_POINTSIZE_MIN ,
8139 WINED3DRS_POINTSPRITEENABLE ,
8140 WINED3DRS_RANGEFOGENABLE ,
8141 WINED3DRS_SPECULARMATERIALSOURCE ,
8142 WINED3DRS_TWEENFACTOR ,
8143 WINED3DRS_VERTEXBLEND
8146 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8147 WINED3DTSS_TEXCOORDINDEX ,
8148 WINED3DTSS_TEXTURETRANSFORMFLAGS
8151 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8152 WINED3DSAMP_DMAPOFFSET