wined3d: Respect EnableAutoDepthStencil parameter.
[wine.git] / dlls / wined3d / device.c
blob53c4986f111fb066c9210bb8a7dced8b074a0caf
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;
778 HRESULT temp_result;
780 D3DCREATEOBJECTINSTANCE(object, StateBlock)
781 object->blockType = Type;
783 /* Special case - Used during initialization to produce a placeholder stateblock
784 so other functions called can update a state block */
785 if (Type == WINED3DSBT_INIT) {
786 /* Don't bother increasing the reference count otherwise a device will never
787 be freed due to circular dependencies */
788 return WINED3D_OK;
791 temp_result = allocate_shader_constants(object);
792 if (WINED3D_OK != temp_result)
793 return temp_result;
795 /* Otherwise, might as well set the whole state block to the appropriate values */
796 if ( This->stateBlock != NULL) {
797 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
798 } else {
799 memset(object->streamFreq, 1, sizeof(object->streamFreq));
802 /* Reset the ref and type after kludging it */
803 object->wineD3DDevice = This;
804 object->ref = 1;
805 object->blockType = Type;
807 TRACE("Updating changed flags appropriate for type %d\n", Type);
809 if (Type == WINED3DSBT_ALL) {
811 TRACE("ALL => Pretend everything has changed\n");
812 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
813 } else if (Type == WINED3DSBT_PIXELSTATE) {
815 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
816 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
818 object->changed.pixelShader = TRUE;
820 /* Pixel Shader Constants */
821 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
822 object->changed.pixelShaderConstantsF[i] = TRUE;
823 for (i = 0; i < MAX_CONST_B; ++i)
824 object->changed.pixelShaderConstantsB[i] = TRUE;
825 for (i = 0; i < MAX_CONST_I; ++i)
826 object->changed.pixelShaderConstantsI[i] = TRUE;
828 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
829 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
831 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
832 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
833 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
836 for (j = 0 ; j < 16; j++) {
837 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
839 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
843 } else if (Type == WINED3DSBT_VERTEXSTATE) {
845 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
846 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
848 object->changed.vertexShader = TRUE;
850 /* Vertex Shader Constants */
851 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
852 object->changed.vertexShaderConstantsF[i] = TRUE;
853 for (i = 0; i < MAX_CONST_B; ++i)
854 object->changed.vertexShaderConstantsB[i] = TRUE;
855 for (i = 0; i < MAX_CONST_I; ++i)
856 object->changed.vertexShaderConstantsI[i] = TRUE;
858 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
859 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
861 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
862 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
863 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
866 for (j = 0 ; j < 16; j++){
867 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
868 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
872 /* Duplicate light chain */
874 PLIGHTINFOEL *src = NULL;
875 PLIGHTINFOEL *dst = NULL;
876 PLIGHTINFOEL *newEl = NULL;
877 src = This->stateBlock->lights;
878 object->lights = NULL;
881 while (src) {
882 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
883 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
884 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
885 newEl->prev = dst;
886 newEl->changed = TRUE;
887 newEl->enabledChanged = TRUE;
888 if (dst == NULL) {
889 object->lights = newEl;
890 } else {
891 dst->next = newEl;
893 dst = newEl;
894 src = src->next;
899 } else {
900 FIXME("Unrecognized state block type %d\n", Type);
903 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
904 return WINED3D_OK;
908 /* ************************************
909 MSDN:
910 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
912 Discard
913 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
915 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.
917 ******************************** */
919 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) {
920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
921 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
922 unsigned int pow2Width, pow2Height;
923 unsigned int Size = 1;
924 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
925 TRACE("(%p) Create surface\n",This);
927 /** FIXME: Check ranges on the inputs are valid
928 * MSDN
929 * MultisampleQuality
930 * [in] Quality level. The valid range is between zero and one less than the level
931 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
932 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
933 * values of paired render targets, depth stencil surfaces, and the MultiSample type
934 * must all match.
935 *******************************/
939 * TODO: Discard MSDN
940 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
942 * If this flag is set, the contents of the depth stencil buffer will be
943 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
944 * with a different depth surface.
946 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
947 ***************************/
949 if(MultisampleQuality < 0) {
950 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
951 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
954 if(MultisampleQuality > 0) {
955 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
956 MultisampleQuality=0;
959 /** FIXME: Check that the format is supported
960 * by the device.
961 *******************************/
963 /* Non-power2 support */
965 /* Find the nearest pow2 match */
966 pow2Width = pow2Height = 1;
967 while (pow2Width < Width) pow2Width <<= 1;
968 while (pow2Height < Height) pow2Height <<= 1;
970 if (pow2Width > Width || pow2Height > Height) {
971 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
972 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
973 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
974 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
975 This, Width, Height);
976 return WINED3DERR_NOTAVAILABLE;
980 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
981 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
982 * space!
983 *********************************/
984 if (WINED3DFMT_UNKNOWN == Format) {
985 Size = 0;
986 } else if (Format == WINED3DFMT_DXT1) {
987 /* DXT1 is half byte per pixel */
988 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
990 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
991 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
992 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
993 } else {
994 Size = (pow2Width * tableEntry->bpp) * pow2Height;
997 /** Create and initialise the surface resource **/
998 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
999 /* "Standalone" surface */
1000 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1002 object->currentDesc.Width = Width;
1003 object->currentDesc.Height = Height;
1004 object->currentDesc.MultiSampleType = MultiSample;
1005 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1007 /* Setup some glformat defaults */
1008 object->glDescription.glFormat = tableEntry->glFormat;
1009 object->glDescription.glFormatInternal = tableEntry->glInternal;
1010 object->glDescription.glType = tableEntry->glType;
1012 object->glDescription.textureName = 0;
1013 object->glDescription.level = Level;
1014 object->glDescription.target = GL_TEXTURE_2D;
1016 /* Internal data */
1017 object->pow2Width = pow2Width;
1018 object->pow2Height = pow2Height;
1020 /* Flags */
1021 object->Flags = 0; /* We start without flags set */
1022 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1023 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1024 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1025 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1028 if (WINED3DFMT_UNKNOWN != Format) {
1029 object->bytesPerPixel = tableEntry->bpp;
1030 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1031 } else {
1032 object->bytesPerPixel = 0;
1033 object->pow2Size = 0;
1036 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1038 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1040 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1041 * this function is too deap to need to care about things like this.
1042 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1043 * ****************************************/
1044 switch(Pool) {
1045 case WINED3DPOOL_SCRATCH:
1046 if(Lockable == FALSE)
1047 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1048 which are mutually exclusive, setting lockable to true\n");
1049 Lockable = TRUE;
1050 break;
1051 case WINED3DPOOL_SYSTEMMEM:
1052 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1053 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1054 case WINED3DPOOL_MANAGED:
1055 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1056 Usage of DYNAMIC which are mutually exclusive, not doing \
1057 anything just telling you.\n");
1058 break;
1059 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1060 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1061 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1062 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1063 break;
1064 default:
1065 FIXME("(%p) Unknown pool %d\n", This, Pool);
1066 break;
1069 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1070 FIXME("Trying to create a render target that isn't in the default pool\n");
1073 /* mark the texture as dirty so that it get's loaded first time around*/
1074 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1075 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1076 This, Width, Height, Format, debug_d3dformat(Format),
1077 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1079 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1080 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1081 This->ddraw_primary = (IWineD3DSurface *) object;
1083 /* Look at the implementation and set the correct Vtable */
1084 switch(Impl) {
1085 case SURFACE_OPENGL:
1086 /* Nothing to do, it's set already */
1087 break;
1089 case SURFACE_GDI:
1090 object->lpVtbl = &IWineGDISurface_Vtbl;
1091 break;
1093 default:
1094 /* To be sure to catch this */
1095 ERR("Unknown requested surface implementation %d!\n", Impl);
1096 IWineD3DSurface_Release((IWineD3DSurface *) object);
1097 return WINED3DERR_INVALIDCALL;
1100 /* Call the private setup routine */
1101 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1105 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1106 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1107 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1108 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1111 IWineD3DTextureImpl *object;
1112 unsigned int i;
1113 UINT tmpW;
1114 UINT tmpH;
1115 HRESULT hr;
1116 unsigned int pow2Width = Width;
1117 unsigned int pow2Height = Height;
1120 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1122 /* TODO: It should only be possible to create textures for formats
1123 that are reported as supported */
1124 if (WINED3DFMT_UNKNOWN >= Format) {
1125 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1126 return WINED3DERR_INVALIDCALL;
1129 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1130 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1131 object->width = Width;
1132 object->height = Height;
1134 /** Non-power2 support **/
1135 /* Find the nearest pow2 match */
1136 pow2Width = pow2Height = 1;
1137 while (pow2Width < Width) pow2Width <<= 1;
1138 while (pow2Height < Height) pow2Height <<= 1;
1140 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1141 /* Precalculated scaling for 'faked' non power of two texture coords */
1142 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1143 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1144 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1146 /* Calculate levels for mip mapping */
1147 if (Levels == 0) {
1148 TRACE("calculating levels %d\n", object->baseTexture.levels);
1149 object->baseTexture.levels++;
1150 tmpW = Width;
1151 tmpH = Height;
1152 while (tmpW > 1 || tmpH > 1) {
1153 tmpW = max(1, tmpW >> 1);
1154 tmpH = max(1, tmpH >> 1);
1155 object->baseTexture.levels++;
1157 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1160 /* Generate all the surfaces */
1161 tmpW = Width;
1162 tmpH = Height;
1163 for (i = 0; i < object->baseTexture.levels; i++)
1165 /* use the callback to create the texture surface */
1166 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1167 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1168 FIXME("Failed to create surface %p\n", object);
1169 /* clean up */
1170 object->surfaces[i] = NULL;
1171 IWineD3DTexture_Release((IWineD3DTexture *)object);
1173 *ppTexture = NULL;
1174 return hr;
1177 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1178 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1179 /* calculate the next mipmap level */
1180 tmpW = max(1, tmpW >> 1);
1181 tmpH = max(1, tmpH >> 1);
1184 TRACE("(%p) : Created texture %p\n", This, object);
1185 return WINED3D_OK;
1188 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1189 UINT Width, UINT Height, UINT Depth,
1190 UINT Levels, DWORD Usage,
1191 WINED3DFORMAT Format, WINED3DPOOL Pool,
1192 IWineD3DVolumeTexture **ppVolumeTexture,
1193 HANDLE *pSharedHandle, IUnknown *parent,
1194 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1197 IWineD3DVolumeTextureImpl *object;
1198 unsigned int i;
1199 UINT tmpW;
1200 UINT tmpH;
1201 UINT tmpD;
1203 /* TODO: It should only be possible to create textures for formats
1204 that are reported as supported */
1205 if (WINED3DFMT_UNKNOWN >= Format) {
1206 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1207 return WINED3DERR_INVALIDCALL;
1210 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1211 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1213 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1214 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1216 object->width = Width;
1217 object->height = Height;
1218 object->depth = Depth;
1220 /* Calculate levels for mip mapping */
1221 if (Levels == 0) {
1222 object->baseTexture.levels++;
1223 tmpW = Width;
1224 tmpH = Height;
1225 tmpD = Depth;
1226 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1227 tmpW = max(1, tmpW >> 1);
1228 tmpH = max(1, tmpH >> 1);
1229 tmpD = max(1, tmpD >> 1);
1230 object->baseTexture.levels++;
1232 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1235 /* Generate all the surfaces */
1236 tmpW = Width;
1237 tmpH = Height;
1238 tmpD = Depth;
1240 for (i = 0; i < object->baseTexture.levels; i++)
1242 /* Create the volume */
1243 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1244 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1246 /* Set it's container to this object */
1247 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1249 /* calcualte the next mipmap level */
1250 tmpW = max(1, tmpW >> 1);
1251 tmpH = max(1, tmpH >> 1);
1252 tmpD = max(1, tmpD >> 1);
1255 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1256 TRACE("(%p) : Created volume texture %p\n", This, object);
1257 return WINED3D_OK;
1260 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1261 UINT Width, UINT Height, UINT Depth,
1262 DWORD Usage,
1263 WINED3DFORMAT Format, WINED3DPOOL Pool,
1264 IWineD3DVolume** ppVolume,
1265 HANDLE* pSharedHandle, IUnknown *parent) {
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1268 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1269 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1271 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1273 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1274 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1276 object->currentDesc.Width = Width;
1277 object->currentDesc.Height = Height;
1278 object->currentDesc.Depth = Depth;
1279 object->bytesPerPixel = formatDesc->bpp;
1281 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1282 object->lockable = TRUE;
1283 object->locked = FALSE;
1284 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1285 object->dirty = TRUE;
1287 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1290 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1291 UINT Levels, DWORD Usage,
1292 WINED3DFORMAT Format, WINED3DPOOL Pool,
1293 IWineD3DCubeTexture **ppCubeTexture,
1294 HANDLE *pSharedHandle, IUnknown *parent,
1295 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1299 unsigned int i, j;
1300 UINT tmpW;
1301 HRESULT hr;
1302 unsigned int pow2EdgeLength = EdgeLength;
1304 /* TODO: It should only be possible to create textures for formats
1305 that are reported as supported */
1306 if (WINED3DFMT_UNKNOWN >= Format) {
1307 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1308 return WINED3DERR_INVALIDCALL;
1311 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1312 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1314 TRACE("(%p) Create Cube Texture\n", This);
1316 /** Non-power2 support **/
1318 /* Find the nearest pow2 match */
1319 pow2EdgeLength = 1;
1320 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1322 object->edgeLength = EdgeLength;
1323 /* TODO: support for native non-power 2 */
1324 /* Precalculated scaling for 'faked' non power of two texture coords */
1325 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1327 /* Calculate levels for mip mapping */
1328 if (Levels == 0) {
1329 object->baseTexture.levels++;
1330 tmpW = EdgeLength;
1331 while (tmpW > 1) {
1332 tmpW = max(1, tmpW >> 1);
1333 object->baseTexture.levels++;
1335 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1338 /* Generate all the surfaces */
1339 tmpW = EdgeLength;
1340 for (i = 0; i < object->baseTexture.levels; i++) {
1342 /* Create the 6 faces */
1343 for (j = 0; j < 6; j++) {
1345 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1346 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1348 if(hr!= WINED3D_OK) {
1349 /* clean up */
1350 int k;
1351 int l;
1352 for (l = 0; l < j; l++) {
1353 IWineD3DSurface_Release(object->surfaces[j][i]);
1355 for (k = 0; k < i; k++) {
1356 for (l = 0; l < 6; l++) {
1357 IWineD3DSurface_Release(object->surfaces[l][j]);
1361 FIXME("(%p) Failed to create surface\n",object);
1362 HeapFree(GetProcessHeap(),0,object);
1363 *ppCubeTexture = NULL;
1364 return hr;
1366 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1367 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1369 tmpW = max(1, tmpW >> 1);
1372 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1373 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1374 return WINED3D_OK;
1377 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1381 if (NULL == ppQuery) {
1382 /* Just a check to see if we support this type of query */
1383 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1384 switch(Type) {
1385 case WINED3DQUERYTYPE_OCCLUSION:
1386 TRACE("(%p) occlusion query\n", This);
1387 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1388 hr = WINED3D_OK;
1389 else
1390 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1391 break;
1392 case WINED3DQUERYTYPE_VCACHE:
1393 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1394 case WINED3DQUERYTYPE_VERTEXSTATS:
1395 case WINED3DQUERYTYPE_EVENT:
1396 case WINED3DQUERYTYPE_TIMESTAMP:
1397 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1398 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1399 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1400 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1401 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1402 case WINED3DQUERYTYPE_PIXELTIMINGS:
1403 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1404 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1405 default:
1406 FIXME("(%p) Unhandled query type %d\n", This, Type);
1408 return hr;
1411 D3DCREATEOBJECTINSTANCE(object, Query)
1412 object->type = Type;
1413 /* allocated the 'extended' data based on the type of query requested */
1414 switch(Type){
1415 case D3DQUERYTYPE_OCCLUSION:
1416 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1417 TRACE("(%p) Allocating data for an occlusion query\n", This);
1418 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1419 break;
1421 case D3DQUERYTYPE_VCACHE:
1422 case D3DQUERYTYPE_RESOURCEMANAGER:
1423 case D3DQUERYTYPE_VERTEXSTATS:
1424 case D3DQUERYTYPE_EVENT:
1425 case D3DQUERYTYPE_TIMESTAMP:
1426 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1427 case D3DQUERYTYPE_TIMESTAMPFREQ:
1428 case D3DQUERYTYPE_PIPELINETIMINGS:
1429 case D3DQUERYTYPE_INTERFACETIMINGS:
1430 case D3DQUERYTYPE_VERTEXTIMINGS:
1431 case D3DQUERYTYPE_PIXELTIMINGS:
1432 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1433 case D3DQUERYTYPE_CACHEUTILIZATION:
1434 default:
1435 object->extendedData = 0;
1436 FIXME("(%p) Unhandled query type %d\n",This , Type);
1438 TRACE("(%p) : Created Query %p\n", This, object);
1439 return WINED3D_OK;
1442 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1443 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1444 IUnknown* parent,
1445 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1446 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1449 HDC hDc;
1450 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1451 int num;
1452 XVisualInfo template;
1453 GLXContext oldContext;
1454 Drawable oldDrawable;
1455 HRESULT hr = WINED3D_OK;
1457 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1459 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1460 * does a device hold a reference to a swap chain giving them a lifetime of the device
1461 * or does the swap chain notify the device of its destruction.
1462 *******************************/
1464 /* Check the params */
1465 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1466 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1467 return WINED3DERR_INVALIDCALL;
1468 } else if (*pPresentationParameters->BackBufferCount > 1) {
1469 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");
1472 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1474 /*********************
1475 * Lookup the window Handle and the relating X window handle
1476 ********************/
1478 /* Setup hwnd we are using, plus which display this equates to */
1479 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1480 if (!object->win_handle) {
1481 object->win_handle = This->createParms.hFocusWindow;
1484 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1485 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1486 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1487 return WINED3DERR_NOTAVAILABLE;
1489 hDc = GetDC(object->win_handle);
1490 object->display = get_display(hDc);
1491 ReleaseDC(object->win_handle, hDc);
1492 TRACE("Using a display of %p %p\n", object->display, hDc);
1494 if (NULL == object->display || NULL == hDc) {
1495 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1496 return WINED3DERR_NOTAVAILABLE;
1499 if (object->win == 0) {
1500 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1501 return WINED3DERR_NOTAVAILABLE;
1504 * Create an opengl context for the display visual
1505 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1506 * use different properties after that point in time. FIXME: How to handle when requested format
1507 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1508 * it chooses is identical to the one already being used!
1509 **********************************/
1511 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1512 ENTER_GL();
1514 /* Create a new context for this swapchain */
1515 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1516 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1517 (or the best possible if none is requested) */
1518 TRACE("Found x visual ID : %ld\n", template.visualid);
1520 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1521 if (NULL == object->visInfo) {
1522 ERR("cannot really get XVisual\n");
1523 LEAVE_GL();
1524 return WINED3DERR_NOTAVAILABLE;
1525 } else {
1526 int n, value;
1527 /* Write out some debug info about the visual/s */
1528 TRACE("Using x visual ID : %ld\n", template.visualid);
1529 TRACE(" visual info: %p\n", object->visInfo);
1530 TRACE(" num items : %d\n", num);
1531 for (n = 0;n < num; n++) {
1532 TRACE("=====item=====: %d\n", n + 1);
1533 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1534 TRACE(" screen : %d\n", object->visInfo[n].screen);
1535 TRACE(" depth : %u\n", object->visInfo[n].depth);
1536 TRACE(" class : %d\n", object->visInfo[n].class);
1537 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1538 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1539 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1540 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1541 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1542 /* log some extra glx info */
1543 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1544 TRACE(" gl_aux_buffers : %d\n", value);
1545 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1546 TRACE(" gl_buffer_size : %d\n", value);
1547 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1548 TRACE(" gl_red_size : %d\n", value);
1549 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1550 TRACE(" gl_green_size : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1552 TRACE(" gl_blue_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1554 TRACE(" gl_alpha_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1556 TRACE(" gl_depth_size : %d\n", value);
1557 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1558 TRACE(" gl_stencil_size : %d\n", value);
1560 /* Now choose a simila visual ID*/
1562 #ifdef USE_CONTEXT_MANAGER
1564 /** TODO: use a context mamager **/
1565 #endif
1568 IWineD3DSwapChain *implSwapChain;
1569 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1570 /* The first time around we create the context that is shared with all other swapchains and render targets */
1571 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1572 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1573 } else {
1575 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1576 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1577 /* and create a new context with the implicit swapchains context as the shared context */
1578 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1579 IWineD3DSwapChain_Release(implSwapChain);
1583 /* Cleanup */
1584 XFree(object->visInfo);
1585 object->visInfo = NULL;
1587 LEAVE_GL();
1589 if (!object->glCtx) {
1590 ERR("Failed to create GLX context\n");
1591 return WINED3DERR_NOTAVAILABLE;
1592 } else {
1593 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1594 object->win_handle, object->glCtx, object->win, object->visInfo);
1597 /*********************
1598 * Windowed / Fullscreen
1599 *******************/
1602 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1603 * so we should really check to see if there is a fullscreen swapchain already
1604 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1605 **************************************/
1607 if (!*(pPresentationParameters->Windowed)) {
1609 DEVMODEW devmode;
1610 HDC hdc;
1611 int bpp = 0;
1613 /* Get info on the current display setup */
1614 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1615 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1616 DeleteDC(hdc);
1618 /* Change the display settings */
1619 memset(&devmode, 0, sizeof(DEVMODEW));
1620 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1621 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1622 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1623 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1624 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1625 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1627 /* Make popup window */
1628 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1629 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1630 *(pPresentationParameters->BackBufferWidth),
1631 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1633 /* For GetDisplayMode */
1634 This->ddraw_width = devmode.dmPelsWidth;
1635 This->ddraw_height = devmode.dmPelsHeight;
1636 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1640 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1641 * then the corresponding dimension of the client area of the hDeviceWindow
1642 * (or the focus window, if hDeviceWindow is NULL) is taken.
1643 **********************/
1645 if (*(pPresentationParameters->Windowed) &&
1646 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1647 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1649 RECT Rect;
1650 GetClientRect(object->win_handle, &Rect);
1652 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1653 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1654 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1656 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1657 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1658 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1662 /*********************
1663 * finish off parameter initialization
1664 *******************/
1666 /* Put the correct figures in the presentation parameters */
1667 TRACE("Coppying accross presentaion paraneters\n");
1668 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1669 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1670 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1671 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1672 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1673 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1674 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1675 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1676 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1677 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1678 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1679 object->presentParms.Flags = *(pPresentationParameters->Flags);
1680 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1681 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1684 /*********************
1685 * Create the back, front and stencil buffers
1686 *******************/
1688 TRACE("calling rendertarget CB\n");
1689 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1690 object->presentParms.BackBufferWidth,
1691 object->presentParms.BackBufferHeight,
1692 object->presentParms.BackBufferFormat,
1693 object->presentParms.MultiSampleType,
1694 object->presentParms.MultiSampleQuality,
1695 TRUE /* Lockable */,
1696 &object->frontBuffer,
1697 NULL /* pShared (always null)*/);
1698 if (object->frontBuffer != NULL)
1699 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1701 if(object->presentParms.BackBufferCount > 0) {
1702 int i;
1704 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1705 if(!object->backBuffer) {
1706 ERR("Out of memory\n");
1708 if (object->frontBuffer) {
1709 IUnknown *bufferParent;
1710 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1711 IUnknown_Release(bufferParent); /* once for the get parent */
1712 if (IUnknown_Release(bufferParent) > 0) {
1713 FIXME("(%p) Something's still holding the front buffer\n",This);
1716 HeapFree(GetProcessHeap(), 0, object);
1717 return E_OUTOFMEMORY;
1720 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1721 TRACE("calling rendertarget CB\n");
1722 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1723 object->presentParms.BackBufferWidth,
1724 object->presentParms.BackBufferHeight,
1725 object->presentParms.BackBufferFormat,
1726 object->presentParms.MultiSampleType,
1727 object->presentParms.MultiSampleQuality,
1728 TRUE /* Lockable */,
1729 &object->backBuffer[i],
1730 NULL /* pShared (always null)*/);
1731 if(hr == WINED3D_OK && object->backBuffer[i]) {
1732 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1733 } else {
1734 break;
1737 } else {
1738 object->backBuffer = NULL;
1741 if (object->backBuffer != NULL) {
1742 ENTER_GL();
1743 glDrawBuffer(GL_BACK);
1744 checkGLcall("glDrawBuffer(GL_BACK)");
1745 LEAVE_GL();
1746 } else {
1747 /* Single buffering - draw to front buffer */
1748 ENTER_GL();
1749 glDrawBuffer(GL_FRONT);
1750 checkGLcall("glDrawBuffer(GL_FRONT)");
1751 LEAVE_GL();
1754 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1755 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1756 TRACE("Creating depth stencil buffer\n");
1757 if (This->depthStencilBuffer == NULL ) {
1758 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1759 object->presentParms.BackBufferWidth,
1760 object->presentParms.BackBufferHeight,
1761 object->presentParms.AutoDepthStencilFormat,
1762 object->presentParms.MultiSampleType,
1763 object->presentParms.MultiSampleQuality,
1764 FALSE /* FIXME: Discard */,
1765 &This->depthStencilBuffer,
1766 NULL /* pShared (always null)*/ );
1767 if (This->depthStencilBuffer != NULL)
1768 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1771 /** TODO: A check on width, height and multisample types
1772 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1773 ****************************/
1774 object->wantsDepthStencilBuffer = TRUE;
1775 } else {
1776 object->wantsDepthStencilBuffer = FALSE;
1779 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1782 /*********************
1783 * init the default renderTarget management
1784 *******************/
1785 object->drawable = object->win;
1786 object->render_ctx = object->glCtx;
1788 if (hr == WINED3D_OK) {
1789 /*********************
1790 * Setup some defaults and clear down the buffers
1791 *******************/
1792 ENTER_GL();
1793 /** save current context and drawable **/
1794 oldContext = glXGetCurrentContext();
1795 oldDrawable = glXGetCurrentDrawable();
1797 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1798 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1799 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1801 checkGLcall("glXMakeCurrent");
1803 TRACE("Setting up the screen\n");
1804 /* Clear the screen */
1805 glClearColor(1.0, 0.0, 0.0, 0.0);
1806 checkGLcall("glClearColor");
1807 glClearIndex(0);
1808 glClearDepth(1);
1809 glClearStencil(0xffff);
1811 checkGLcall("glClear");
1813 glColor3f(1.0, 1.0, 1.0);
1814 checkGLcall("glColor3f");
1816 glEnable(GL_LIGHTING);
1817 checkGLcall("glEnable");
1819 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1820 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1822 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1823 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1825 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1826 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1828 /* switch back to the original context (if there was one)*/
1829 if (This->swapchains) {
1830 /** TODO: restore the context and drawable **/
1831 glXMakeCurrent(object->display, oldDrawable, oldContext);
1834 LEAVE_GL();
1836 TRACE("Set swapchain to %p\n", object);
1837 } else { /* something went wrong so clean up */
1838 IUnknown* bufferParent;
1839 if (object->frontBuffer) {
1841 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1842 IUnknown_Release(bufferParent); /* once for the get parent */
1843 if (IUnknown_Release(bufferParent) > 0) {
1844 FIXME("(%p) Something's still holding the front buffer\n",This);
1847 if (object->backBuffer) {
1848 int i;
1849 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1850 if(object->backBuffer[i]) {
1851 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1852 IUnknown_Release(bufferParent); /* once for the get parent */
1853 if (IUnknown_Release(bufferParent) > 0) {
1854 FIXME("(%p) Something's still holding the back buffer\n",This);
1858 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1859 object->backBuffer = NULL;
1861 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1862 /* Clean up the context */
1863 /* check that we are the current context first (we shouldn't be though!) */
1864 if (object->glCtx != 0) {
1865 if(glXGetCurrentContext() == object->glCtx) {
1866 glXMakeCurrent(object->display, None, NULL);
1868 glXDestroyContext(object->display, object->glCtx);
1870 HeapFree(GetProcessHeap(), 0, object);
1874 return hr;
1877 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1878 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 TRACE("(%p)\n", This);
1882 return This->NumberOfSwapChains;
1885 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1889 if(iSwapChain < This->NumberOfSwapChains) {
1890 *pSwapChain = This->swapchains[iSwapChain];
1891 IWineD3DSwapChain_AddRef(*pSwapChain);
1892 TRACE("(%p) returning %p\n", This, *pSwapChain);
1893 return WINED3D_OK;
1894 } else {
1895 TRACE("Swapchain out of range\n");
1896 *pSwapChain = NULL;
1897 return WINED3DERR_INVALIDCALL;
1901 /*****
1902 * Vertex Declaration
1903 *****/
1904 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1906 IWineD3DVertexDeclarationImpl *object = NULL;
1907 HRESULT hr = WINED3D_OK;
1908 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1909 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1910 object->allFVF = 0;
1912 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1914 return hr;
1917 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1920 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1921 HRESULT hr = WINED3D_OK;
1922 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1923 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1925 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1927 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1928 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1929 if (pDeclaration != NULL) {
1930 IWineD3DVertexDeclaration *vertexDeclaration;
1931 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1932 if (WINED3D_OK == hr) {
1933 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1934 object->vertexDeclaration = vertexDeclaration;
1935 } else {
1936 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1937 IWineD3DVertexShader_Release(*ppVertexShader);
1938 return WINED3DERR_INVALIDCALL;
1942 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1944 if (WINED3D_OK != hr) {
1945 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1946 IWineD3DVertexShader_Release(*ppVertexShader);
1947 return WINED3DERR_INVALIDCALL;
1950 #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. */
1951 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1952 /* Foo */
1953 } else {
1954 /* Bar */
1957 #endif
1959 return WINED3D_OK;
1962 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1964 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1965 HRESULT hr = WINED3D_OK;
1967 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1968 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1969 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1970 if (WINED3D_OK == hr) {
1971 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1972 } else {
1973 WARN("(%p) : Failed to create pixel shader\n", This);
1976 return hr;
1979 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1981 IWineD3DPaletteImpl *object;
1982 HRESULT hr;
1983 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1985 /* Create the new object */
1986 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1987 if(!object) {
1988 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1989 return E_OUTOFMEMORY;
1992 object->lpVtbl = &IWineD3DPalette_Vtbl;
1993 object->ref = 1;
1994 object->Flags = Flags;
1995 object->parent = Parent;
1996 object->wineD3DDevice = This;
1997 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1999 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2001 if(!object->hpal) {
2002 HeapFree( GetProcessHeap(), 0, object);
2003 return E_OUTOFMEMORY;
2006 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2007 if(FAILED(hr)) {
2008 IWineD3DPalette_Release((IWineD3DPalette *) object);
2009 return hr;
2012 *Palette = (IWineD3DPalette *) object;
2014 return WINED3D_OK;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2019 IWineD3DSwapChainImpl *swapchain;
2021 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2022 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 /* TODO: Test if OpenGL is compiled in and loaded */
2026 /* Setup the implicit swapchain */
2027 TRACE("Creating implicit swapchain\n");
2028 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2029 WARN("Failed to create implicit swapchain\n");
2030 return WINED3DERR_INVALIDCALL;
2033 This->NumberOfSwapChains = 1;
2034 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2035 if(!This->swapchains) {
2036 ERR("Out of memory!\n");
2037 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2038 return E_OUTOFMEMORY;
2040 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2042 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2043 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2044 This->renderTarget = swapchain->backBuffer[0];
2046 else {
2047 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2048 This->renderTarget = swapchain->frontBuffer;
2050 IWineD3DSurface_AddRef(This->renderTarget);
2051 /* Depth Stencil support */
2052 This->stencilBufferTarget = This->depthStencilBuffer;
2053 if (NULL != This->stencilBufferTarget) {
2054 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2057 /* Set up some starting GL setup */
2058 ENTER_GL();
2060 * Initialize openGL extension related variables
2061 * with Default values
2064 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2065 /* Setup all the devices defaults */
2066 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2067 #if 0
2068 IWineD3DImpl_CheckGraphicsMemory();
2069 #endif
2070 LEAVE_GL();
2072 /* Initialize our list of GLSL programs */
2073 list_init(&This->glsl_shader_progs);
2075 { /* Set a default viewport */
2076 D3DVIEWPORT9 vp;
2077 vp.X = 0;
2078 vp.Y = 0;
2079 vp.Width = *(pPresentationParameters->BackBufferWidth);
2080 vp.Height = *(pPresentationParameters->BackBufferHeight);
2081 vp.MinZ = 0.0f;
2082 vp.MaxZ = 1.0f;
2083 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2086 /* Initialize the current view state */
2087 This->modelview_valid = 1;
2088 This->proj_valid = 0;
2089 This->view_ident = 1;
2090 This->last_was_rhw = 0;
2091 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2092 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2094 /* Clear the screen */
2095 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2097 This->d3d_initialized = TRUE;
2098 return WINED3D_OK;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2103 int sampler;
2104 IUnknown* stencilBufferParent;
2105 IUnknown* swapChainParent;
2106 uint i;
2107 TRACE("(%p)\n", This);
2109 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2111 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2112 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2115 /* Release the buffers (with sanity checks)*/
2116 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2117 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2118 if(This->depthStencilBuffer != This->stencilBufferTarget)
2119 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2121 This->stencilBufferTarget = NULL;
2123 TRACE("Releasing the render target at %p\n", This->renderTarget);
2124 if(IWineD3DSurface_Release(This->renderTarget) >0){
2125 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2127 TRACE("Setting rendertarget to NULL\n");
2128 This->renderTarget = NULL;
2130 if (This->depthStencilBuffer) {
2131 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2132 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2133 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2134 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2136 This->depthStencilBuffer = NULL;
2139 for(i=0; i < This->NumberOfSwapChains; i++) {
2140 TRACE("Releasing the implicit swapchain %d\n", i);
2141 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2142 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2143 IUnknown_Release(swapChainParent); /* once for the get parent */
2144 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2145 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2149 HeapFree(GetProcessHeap(), 0, This->swapchains);
2150 This->swapchains = NULL;
2151 This->NumberOfSwapChains = 0;
2153 This->d3d_initialized = FALSE;
2154 return WINED3D_OK;
2157 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2160 DEVMODEW DevModeW;
2161 int i;
2162 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2164 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2166 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2167 /* Ignore some modes if a description was passed */
2168 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2169 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2170 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2172 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2174 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2175 return D3D_OK;
2178 return D3D_OK;
2181 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2182 DEVMODEW devmode;
2183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2184 LONG ret;
2185 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2187 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2189 /* Resize the screen even without a window:
2190 * The app could have unset it with SetCooperativeLevel, but not called
2191 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2192 * but we don't have any hwnd
2195 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2196 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2197 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2198 devmode.dmPelsWidth = pMode->Width;
2199 devmode.dmPelsHeight = pMode->Height;
2201 devmode.dmDisplayFrequency = pMode->RefreshRate;
2202 if (pMode->RefreshRate != 0) {
2203 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2206 /* Only change the mode if necessary */
2207 if( (This->ddraw_width == pMode->Width) &&
2208 (This->ddraw_height == pMode->Height) &&
2209 (This->ddraw_format == pMode->Format) &&
2210 (pMode->RefreshRate == 0) ) {
2211 return D3D_OK;
2214 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2215 if (ret != DISP_CHANGE_SUCCESSFUL) {
2216 if(devmode.dmDisplayFrequency != 0) {
2217 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2218 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2219 devmode.dmDisplayFrequency = 0;
2220 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2222 if(ret != DISP_CHANGE_SUCCESSFUL) {
2223 return DDERR_INVALIDMODE;
2227 /* Store the new values */
2228 This->ddraw_width = pMode->Width;
2229 This->ddraw_height = pMode->Height;
2230 This->ddraw_format = pMode->Format;
2232 /* Only do this with a window of course */
2233 if(This->ddraw_window)
2234 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2236 return WINED3D_OK;
2239 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 *ppD3D= This->wineD3D;
2242 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2243 IWineD3D_AddRef(*ppD3D);
2244 return WINED3D_OK;
2247 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2248 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2249 * Into the video ram as possible and seeing how many fit
2250 * you can also get the correct initial value from via X and ATI's driver
2251 *******************/
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 static BOOL showfixmes = TRUE;
2254 if (showfixmes) {
2255 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2256 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2257 showfixmes = FALSE;
2259 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2260 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2261 /* videomemory is simulated videomemory + AGP memory left */
2262 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2267 /*****
2268 * Get / Set FVF
2269 *****/
2270 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2272 HRESULT hr = WINED3D_OK;
2274 /* Update the current state block */
2275 This->updateStateBlock->fvf = fvf;
2276 This->updateStateBlock->changed.fvf = TRUE;
2277 This->updateStateBlock->set.fvf = TRUE;
2279 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2280 return hr;
2284 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2286 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2287 *pfvf = This->stateBlock->fvf;
2288 return WINED3D_OK;
2291 /*****
2292 * Get / Set Stream Source
2293 *****/
2294 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2296 IWineD3DVertexBuffer *oldSrc;
2298 /**TODO: instance and index data, see
2299 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2301 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2302 **************/
2304 /* D3d9 only, but shouldn't hurt d3d8 */
2305 UINT streamFlags;
2307 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2308 if (streamFlags) {
2309 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2310 FIXME("stream index data not supported\n");
2312 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2313 FIXME("stream instance data not supported\n");
2317 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2319 if (StreamNumber >= MAX_STREAMS) {
2320 WARN("Stream out of range %d\n", StreamNumber);
2321 return WINED3DERR_INVALIDCALL;
2324 oldSrc = This->stateBlock->streamSource[StreamNumber];
2325 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2327 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2328 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2329 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2330 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2331 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2332 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2334 /* Handle recording of state blocks */
2335 if (This->isRecordingState) {
2336 TRACE("Recording... not performing anything\n");
2337 return WINED3D_OK;
2340 /* Same stream object: no action */
2341 if (oldSrc == pStreamData)
2342 return WINED3D_OK;
2344 /* Need to do a getParent and pass the reffs up */
2345 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2346 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2347 so for now, just count internally */
2348 if (pStreamData != NULL) {
2349 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2350 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2351 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2353 vbImpl->stream = StreamNumber;
2354 vbImpl->Flags |= VBFLAG_STREAM;
2355 IWineD3DVertexBuffer_AddRef(pStreamData);
2357 if (oldSrc != NULL) {
2358 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2359 IWineD3DVertexBuffer_Release(oldSrc);
2362 return WINED3D_OK;
2365 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 UINT streamFlags;
2369 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2370 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2373 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2374 if (streamFlags) {
2375 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2376 FIXME("stream index data not supported\n");
2378 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2379 FIXME("stream instance data not supported\n");
2383 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2385 if (StreamNumber >= MAX_STREAMS) {
2386 WARN("Stream out of range %d\n", StreamNumber);
2387 return WINED3DERR_INVALIDCALL;
2389 *pStream = This->stateBlock->streamSource[StreamNumber];
2390 *pStride = This->stateBlock->streamStride[StreamNumber];
2391 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2393 if (*pStream == NULL) {
2394 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2395 return WINED3DERR_INVALIDCALL;
2398 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2399 return WINED3D_OK;
2402 /*Should be quite easy, just an extension of vertexdata
2403 ref...
2404 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2406 The divider is a bit odd though
2408 VertexOffset = StartVertex / Divider * StreamStride +
2409 VertexIndex / Divider * StreamStride + StreamOffset
2412 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2415 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2416 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2418 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2419 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2420 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2422 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2423 FIXME("Stream indexing not fully supported\n");
2426 return WINED3D_OK;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2432 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2433 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2435 TRACE("(%p) : returning %d\n", This, *Divider);
2437 return WINED3D_OK;
2440 /*****
2441 * Get / Set & Multiply Transform
2442 *****/
2443 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2446 /* Most of this routine, comments included copied from ddraw tree initially: */
2447 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2449 /* Handle recording of state blocks */
2450 if (This->isRecordingState) {
2451 TRACE("Recording... not performing anything\n");
2452 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2453 This->updateStateBlock->set.transform[d3dts] = TRUE;
2454 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2455 return WINED3D_OK;
2459 * If the new matrix is the same as the current one,
2460 * we cut off any further processing. this seems to be a reasonable
2461 * optimization because as was noticed, some apps (warcraft3 for example)
2462 * tend towards setting the same matrix repeatedly for some reason.
2464 * From here on we assume that the new matrix is different, wherever it matters.
2466 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2467 TRACE("The app is setting the same matrix over again\n");
2468 return WINED3D_OK;
2469 } else {
2470 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2474 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2475 where ViewMat = Camera space, WorldMat = world space.
2477 In OpenGL, camera and world space is combined into GL_MODELVIEW
2478 matrix. The Projection matrix stay projection matrix.
2481 /* Capture the times we can just ignore the change for now */
2482 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2483 This->modelview_valid = FALSE;
2484 return WINED3D_OK;
2486 } else if (d3dts == D3DTS_PROJECTION) {
2487 This->proj_valid = FALSE;
2488 return WINED3D_OK;
2490 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2491 /* Indexed Vertex Blending Matrices 256 -> 511 */
2492 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2493 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2494 return WINED3D_OK;
2497 /* Now we really are going to have to change a matrix */
2498 ENTER_GL();
2500 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2501 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2502 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2503 unsigned int k;
2505 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2506 * NOTE: We have to reset the positions even if the light/plane is not currently
2507 * enabled, since the call to enable it will not reset the position.
2508 * NOTE2: Apparently texture transforms do NOT need reapplying
2511 PLIGHTINFOEL *lightChain = NULL;
2512 This->modelview_valid = FALSE;
2513 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2515 glMatrixMode(GL_MODELVIEW);
2516 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2517 glPushMatrix();
2518 glLoadMatrixf((float *)lpmatrix);
2519 checkGLcall("glLoadMatrixf(...)");
2521 /* Reset lights */
2522 lightChain = This->stateBlock->lights;
2523 while (lightChain && lightChain->glIndex != -1) {
2524 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2525 checkGLcall("glLightfv posn");
2526 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2527 checkGLcall("glLightfv dirn");
2528 lightChain = lightChain->next;
2531 /* Reset Clipping Planes if clipping is enabled */
2532 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2533 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2534 checkGLcall("glClipPlane");
2536 glPopMatrix();
2538 } else { /* What was requested!?? */
2539 WARN("invalid matrix specified: %i\n", d3dts);
2542 /* Release lock, all done */
2543 LEAVE_GL();
2544 return WINED3D_OK;
2547 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 TRACE("(%p) : for Transform State %d\n", This, State);
2550 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2551 return WINED3D_OK;
2554 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2555 D3DMATRIX *mat = NULL;
2556 D3DMATRIX temp;
2558 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2559 * below means it will be recorded in a state block change, but it
2560 * works regardless where it is recorded.
2561 * If this is found to be wrong, change to StateBlock.
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 TRACE("(%p) : For state %u\n", This, State);
2566 if (State < HIGHEST_TRANSFORMSTATE)
2568 mat = &This->updateStateBlock->transforms[State];
2569 } else {
2570 FIXME("Unhandled transform state!!\n");
2573 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2575 /* Apply change via set transform - will reapply to eg. lights this way */
2576 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2579 /*****
2580 * Get / Set Light
2581 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2582 *****/
2583 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2584 you can reference any indexes you want as long as that number max are enabled at any
2585 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2586 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2587 but when recording, just build a chain pretty much of commands to be replayed. */
2589 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2590 float rho;
2591 PLIGHTINFOEL *object, *temp;
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2596 /* If recording state block, just add to end of lights chain */
2597 if (This->isRecordingState) {
2598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2599 if (NULL == object) {
2600 return WINED3DERR_OUTOFVIDEOMEMORY;
2602 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2603 object->OriginalIndex = Index;
2604 object->glIndex = -1;
2605 object->changed = TRUE;
2607 /* Add to the END of the chain of lights changes to be replayed */
2608 if (This->updateStateBlock->lights == NULL) {
2609 This->updateStateBlock->lights = object;
2610 } else {
2611 temp = This->updateStateBlock->lights;
2612 while (temp->next != NULL) temp=temp->next;
2613 temp->next = object;
2615 TRACE("Recording... not performing anything more\n");
2616 return WINED3D_OK;
2619 /* Ok, not recording any longer so do real work */
2620 object = This->stateBlock->lights;
2621 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2623 /* If we didn't find it in the list of lights, time to add it */
2624 if (object == NULL) {
2625 PLIGHTINFOEL *insertAt,*prevPos;
2627 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2628 if (NULL == object) {
2629 return WINED3DERR_OUTOFVIDEOMEMORY;
2631 object->OriginalIndex = Index;
2632 object->glIndex = -1;
2634 /* Add it to the front of list with the idea that lights will be changed as needed
2635 BUT after any lights currently assigned GL indexes */
2636 insertAt = This->stateBlock->lights;
2637 prevPos = NULL;
2638 while (insertAt != NULL && insertAt->glIndex != -1) {
2639 prevPos = insertAt;
2640 insertAt = insertAt->next;
2643 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2644 This->stateBlock->lights = object;
2645 } else if (insertAt == NULL) { /* End of list */
2646 prevPos->next = object;
2647 object->prev = prevPos;
2648 } else { /* Middle of chain */
2649 if (prevPos == NULL) {
2650 This->stateBlock->lights = object;
2651 } else {
2652 prevPos->next = object;
2654 object->prev = prevPos;
2655 object->next = insertAt;
2656 insertAt->prev = object;
2660 /* Initialize the object */
2661 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,
2662 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2663 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2664 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2665 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2666 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2667 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2669 /* Save away the information */
2670 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2672 switch (pLight->Type) {
2673 case D3DLIGHT_POINT:
2674 /* Position */
2675 object->lightPosn[0] = pLight->Position.x;
2676 object->lightPosn[1] = pLight->Position.y;
2677 object->lightPosn[2] = pLight->Position.z;
2678 object->lightPosn[3] = 1.0f;
2679 object->cutoff = 180.0f;
2680 /* FIXME: Range */
2681 break;
2683 case D3DLIGHT_DIRECTIONAL:
2684 /* Direction */
2685 object->lightPosn[0] = -pLight->Direction.x;
2686 object->lightPosn[1] = -pLight->Direction.y;
2687 object->lightPosn[2] = -pLight->Direction.z;
2688 object->lightPosn[3] = 0.0;
2689 object->exponent = 0.0f;
2690 object->cutoff = 180.0f;
2691 break;
2693 case D3DLIGHT_SPOT:
2694 /* Position */
2695 object->lightPosn[0] = pLight->Position.x;
2696 object->lightPosn[1] = pLight->Position.y;
2697 object->lightPosn[2] = pLight->Position.z;
2698 object->lightPosn[3] = 1.0;
2700 /* Direction */
2701 object->lightDirn[0] = pLight->Direction.x;
2702 object->lightDirn[1] = pLight->Direction.y;
2703 object->lightDirn[2] = pLight->Direction.z;
2704 object->lightDirn[3] = 1.0;
2707 * opengl-ish and d3d-ish spot lights use too different models for the
2708 * light "intensity" as a function of the angle towards the main light direction,
2709 * so we only can approximate very roughly.
2710 * however spot lights are rather rarely used in games (if ever used at all).
2711 * furthermore if still used, probably nobody pays attention to such details.
2713 if (pLight->Falloff == 0) {
2714 rho = 6.28f;
2715 } else {
2716 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2718 if (rho < 0.0001) rho = 0.0001f;
2719 object->exponent = -0.3/log(cos(rho/2));
2720 object->cutoff = pLight->Phi*90/M_PI;
2722 /* FIXME: Range */
2723 break;
2725 default:
2726 FIXME("Unrecognized light type %d\n", pLight->Type);
2729 /* Update the live definitions if the light is currently assigned a glIndex */
2730 if (object->glIndex != -1) {
2731 setup_light(iface, object->glIndex, object);
2733 return WINED3D_OK;
2736 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2737 PLIGHTINFOEL *lightInfo = NULL;
2738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2739 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2741 /* Locate the light in the live lights */
2742 lightInfo = This->stateBlock->lights;
2743 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2745 if (lightInfo == NULL) {
2746 TRACE("Light information requested but light not defined\n");
2747 return WINED3DERR_INVALIDCALL;
2750 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2751 return WINED3D_OK;
2754 /*****
2755 * Get / Set Light Enable
2756 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2757 *****/
2758 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2759 PLIGHTINFOEL *lightInfo = NULL;
2760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2761 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2763 /* Tests show true = 128...not clear why */
2765 Enable = Enable? 128: 0;
2767 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2768 if (This->isRecordingState) {
2769 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2770 if (NULL == lightInfo) {
2771 return WINED3DERR_OUTOFVIDEOMEMORY;
2773 lightInfo->OriginalIndex = Index;
2774 lightInfo->glIndex = -1;
2775 lightInfo->enabledChanged = TRUE;
2776 lightInfo->lightEnabled = Enable;
2778 /* Add to the END of the chain of lights changes to be replayed */
2779 if (This->updateStateBlock->lights == NULL) {
2780 This->updateStateBlock->lights = lightInfo;
2781 } else {
2782 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2783 while (temp->next != NULL) temp=temp->next;
2784 temp->next = lightInfo;
2786 TRACE("Recording... not performing anything more\n");
2787 return WINED3D_OK;
2790 /* Not recording... So, locate the light in the live lights */
2791 lightInfo = This->stateBlock->lights;
2792 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2794 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2795 if (lightInfo == NULL) {
2797 TRACE("Light enabled requested but light not defined, so defining one!\n");
2798 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2800 /* Search for it again! Should be fairly quick as near head of list */
2801 lightInfo = This->stateBlock->lights;
2802 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2803 if (lightInfo == NULL) {
2804 FIXME("Adding default lights has failed dismally\n");
2805 return WINED3DERR_INVALIDCALL;
2809 /* OK, we now have a light... */
2810 if (Enable == FALSE) {
2812 /* If we are disabling it, check it was enabled, and
2813 still only do something if it has assigned a glIndex (which it should have!) */
2814 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2815 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2816 ENTER_GL();
2817 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2818 checkGLcall("glDisable GL_LIGHT0+Index");
2819 LEAVE_GL();
2820 } else {
2821 TRACE("Nothing to do as light was not enabled\n");
2823 lightInfo->lightEnabled = Enable;
2824 } else {
2826 /* We are enabling it. If it is enabled, it's really simple */
2827 if (lightInfo->lightEnabled) {
2828 /* nop */
2829 TRACE("Nothing to do as light was enabled\n");
2831 /* If it already has a glIndex, it's still simple */
2832 } else if (lightInfo->glIndex != -1) {
2833 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2834 lightInfo->lightEnabled = Enable;
2835 ENTER_GL();
2836 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2837 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2838 LEAVE_GL();
2840 /* Otherwise got to find space - lights are ordered gl indexes first */
2841 } else {
2842 PLIGHTINFOEL *bsf = NULL;
2843 PLIGHTINFOEL *pos = This->stateBlock->lights;
2844 PLIGHTINFOEL *prev = NULL;
2845 int Index= 0;
2846 int glIndex = -1;
2848 /* Try to minimize changes as much as possible */
2849 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2851 /* Try to remember which index can be replaced if necessary */
2852 if (bsf==NULL && pos->lightEnabled == FALSE) {
2853 /* Found a light we can replace, save as best replacement */
2854 bsf = pos;
2857 /* Step to next space */
2858 prev = pos;
2859 pos = pos->next;
2860 Index ++;
2863 /* If we have too many active lights, fail the call */
2864 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2865 FIXME("Program requests too many concurrent lights\n");
2866 return WINED3DERR_INVALIDCALL;
2868 /* If we have allocated all lights, but not all are enabled,
2869 reuse one which is not enabled */
2870 } else if (Index == This->maxConcurrentLights) {
2871 /* use bsf - Simply swap the new light and the BSF one */
2872 PLIGHTINFOEL *bsfNext = bsf->next;
2873 PLIGHTINFOEL *bsfPrev = bsf->prev;
2875 /* Sort out ends */
2876 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2877 if (bsf->prev != NULL) {
2878 bsf->prev->next = lightInfo;
2879 } else {
2880 This->stateBlock->lights = lightInfo;
2883 /* If not side by side, lots of chains to update */
2884 if (bsf->next != lightInfo) {
2885 lightInfo->prev->next = bsf;
2886 bsf->next->prev = lightInfo;
2887 bsf->next = lightInfo->next;
2888 bsf->prev = lightInfo->prev;
2889 lightInfo->next = bsfNext;
2890 lightInfo->prev = bsfPrev;
2892 } else {
2893 /* Simple swaps */
2894 bsf->prev = lightInfo;
2895 bsf->next = lightInfo->next;
2896 lightInfo->next = bsf;
2897 lightInfo->prev = bsfPrev;
2901 /* Update states */
2902 glIndex = bsf->glIndex;
2903 bsf->glIndex = -1;
2904 lightInfo->glIndex = glIndex;
2905 lightInfo->lightEnabled = Enable;
2907 /* Finally set up the light in gl itself */
2908 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2909 ENTER_GL();
2910 setup_light(iface, glIndex, lightInfo);
2911 glEnable(GL_LIGHT0 + glIndex);
2912 checkGLcall("glEnable GL_LIGHT0 new setup");
2913 LEAVE_GL();
2915 /* If we reached the end of the allocated lights, with space in the
2916 gl lights, setup a new light */
2917 } else if (pos->glIndex == -1) {
2919 /* We reached the end of the allocated gl lights, so already
2920 know the index of the next one! */
2921 glIndex = Index;
2922 lightInfo->glIndex = glIndex;
2923 lightInfo->lightEnabled = Enable;
2925 /* In an ideal world, it's already in the right place */
2926 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2927 /* No need to move it */
2928 } else {
2929 /* Remove this light from the list */
2930 lightInfo->prev->next = lightInfo->next;
2931 if (lightInfo->next != NULL) {
2932 lightInfo->next->prev = lightInfo->prev;
2935 /* Add in at appropriate place (inbetween prev and pos) */
2936 lightInfo->prev = prev;
2937 lightInfo->next = pos;
2938 if (prev == NULL) {
2939 This->stateBlock->lights = lightInfo;
2940 } else {
2941 prev->next = lightInfo;
2943 if (pos != NULL) {
2944 pos->prev = lightInfo;
2948 /* Finally set up the light in gl itself */
2949 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2950 ENTER_GL();
2951 setup_light(iface, glIndex, lightInfo);
2952 glEnable(GL_LIGHT0 + glIndex);
2953 checkGLcall("glEnable GL_LIGHT0 new setup");
2954 LEAVE_GL();
2959 return WINED3D_OK;
2962 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2964 PLIGHTINFOEL *lightInfo = NULL;
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 TRACE("(%p) : for idx(%ld)\n", This, Index);
2968 /* Locate the light in the live lights */
2969 lightInfo = This->stateBlock->lights;
2970 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2972 if (lightInfo == NULL) {
2973 TRACE("Light enabled state requested but light not defined\n");
2974 return WINED3DERR_INVALIDCALL;
2976 *pEnable = lightInfo->lightEnabled;
2977 return WINED3D_OK;
2980 /*****
2981 * Get / Set Clip Planes
2982 *****/
2983 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2987 /* Validate Index */
2988 if (Index >= GL_LIMITS(clipplanes)) {
2989 TRACE("Application has requested clipplane this device doesn't support\n");
2990 return WINED3DERR_INVALIDCALL;
2993 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2994 This->updateStateBlock->set.clipplane[Index] = TRUE;
2995 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2996 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2997 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2998 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3000 /* Handle recording of state blocks */
3001 if (This->isRecordingState) {
3002 TRACE("Recording... not performing anything\n");
3003 return WINED3D_OK;
3006 /* Apply it */
3008 ENTER_GL();
3010 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3011 glMatrixMode(GL_MODELVIEW);
3012 glPushMatrix();
3013 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3015 TRACE("Clipplane [%f,%f,%f,%f]\n",
3016 This->updateStateBlock->clipplane[Index][0],
3017 This->updateStateBlock->clipplane[Index][1],
3018 This->updateStateBlock->clipplane[Index][2],
3019 This->updateStateBlock->clipplane[Index][3]);
3020 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3021 checkGLcall("glClipPlane");
3023 glPopMatrix();
3024 LEAVE_GL();
3026 return WINED3D_OK;
3029 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 TRACE("(%p) : for idx %ld\n", This, Index);
3033 /* Validate Index */
3034 if (Index >= GL_LIMITS(clipplanes)) {
3035 TRACE("Application has requested clipplane this device doesn't support\n");
3036 return WINED3DERR_INVALIDCALL;
3039 pPlane[0] = This->stateBlock->clipplane[Index][0];
3040 pPlane[1] = This->stateBlock->clipplane[Index][1];
3041 pPlane[2] = This->stateBlock->clipplane[Index][2];
3042 pPlane[3] = This->stateBlock->clipplane[Index][3];
3043 return WINED3D_OK;
3046 /*****
3047 * Get / Set Clip Plane Status
3048 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3049 *****/
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3052 FIXME("(%p) : stub\n", This);
3053 if (NULL == pClipStatus) {
3054 return WINED3DERR_INVALIDCALL;
3056 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3057 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3058 return WINED3D_OK;
3061 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 FIXME("(%p) : stub\n", This);
3064 if (NULL == pClipStatus) {
3065 return WINED3DERR_INVALIDCALL;
3067 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3068 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3069 return WINED3D_OK;
3072 /*****
3073 * Get / Set Material
3074 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3075 *****/
3076 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 This->updateStateBlock->changed.material = TRUE;
3080 This->updateStateBlock->set.material = TRUE;
3081 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3083 /* Handle recording of state blocks */
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3086 return WINED3D_OK;
3089 ENTER_GL();
3090 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3091 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3092 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3093 pMaterial->Ambient.b, pMaterial->Ambient.a);
3094 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3095 pMaterial->Specular.b, pMaterial->Specular.a);
3096 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3097 pMaterial->Emissive.b, pMaterial->Emissive.a);
3098 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3100 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3101 checkGLcall("glMaterialfv(GL_AMBIENT)");
3102 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3103 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3105 /* Only change material color if specular is enabled, otherwise it is set to black */
3106 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3107 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3108 checkGLcall("glMaterialfv(GL_SPECULAR");
3109 } else {
3110 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3111 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3112 checkGLcall("glMaterialfv(GL_SPECULAR");
3114 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3115 checkGLcall("glMaterialfv(GL_EMISSION)");
3116 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3117 checkGLcall("glMaterialf(GL_SHININESS");
3119 LEAVE_GL();
3120 return WINED3D_OK;
3123 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3126 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3127 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3128 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3129 pMaterial->Ambient.b, pMaterial->Ambient.a);
3130 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3131 pMaterial->Specular.b, pMaterial->Specular.a);
3132 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3133 pMaterial->Emissive.b, pMaterial->Emissive.a);
3134 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3136 return WINED3D_OK;
3139 /*****
3140 * Get / Set Indices
3141 *****/
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3143 UINT BaseVertexIndex) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 IWineD3DIndexBuffer *oldIdxs;
3147 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3148 oldIdxs = This->updateStateBlock->pIndexData;
3150 This->updateStateBlock->changed.indices = TRUE;
3151 This->updateStateBlock->set.indices = TRUE;
3152 This->updateStateBlock->pIndexData = pIndexData;
3153 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3155 /* Handle recording of state blocks */
3156 if (This->isRecordingState) {
3157 TRACE("Recording... not performing anything\n");
3158 return WINED3D_OK;
3161 if (NULL != pIndexData) {
3162 IWineD3DIndexBuffer_AddRef(pIndexData);
3164 if (NULL != oldIdxs) {
3165 IWineD3DIndexBuffer_Release(oldIdxs);
3167 return WINED3D_OK;
3170 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 *ppIndexData = This->stateBlock->pIndexData;
3175 /* up ref count on ppindexdata */
3176 if (*ppIndexData) {
3177 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3178 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3179 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3180 }else{
3181 TRACE("(%p) No index data set\n", This);
3183 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3185 return WINED3D_OK;
3188 /*****
3189 * Get / Set Viewports
3190 *****/
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p)\n", This);
3195 This->updateStateBlock->changed.viewport = TRUE;
3196 This->updateStateBlock->set.viewport = TRUE;
3197 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3199 /* Handle recording of state blocks */
3200 if (This->isRecordingState) {
3201 TRACE("Recording... not performing anything\n");
3202 return WINED3D_OK;
3204 This->viewport_changed = TRUE;
3206 ENTER_GL();
3208 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3209 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3211 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3212 checkGLcall("glDepthRange");
3213 /* Note: GL requires lower left, DirectX supplies upper left */
3214 /* TODO: replace usage of renderTarget with context management */
3215 glViewport(pViewport->X,
3216 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3217 pViewport->Width, pViewport->Height);
3219 checkGLcall("glViewport");
3221 LEAVE_GL();
3223 return WINED3D_OK;
3227 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p)\n", This);
3230 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3231 return WINED3D_OK;
3234 static void renderstate_stencil_twosided(
3235 IWineD3DDeviceImpl *This,
3236 GLint face,
3237 GLint func,
3238 GLint ref,
3239 GLuint mask,
3240 GLint stencilFail,
3241 GLint depthFail,
3242 GLint stencilPass ) {
3243 #if 0 /* Don't use OpenGL 2.0 calls for now */
3244 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3245 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3246 checkGLcall("glStencilFuncSeparate(...)");
3247 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3248 checkGLcall("glStencilOpSeparate(...)");
3250 else
3251 #endif
3252 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3253 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3254 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3255 GL_EXTCALL(glActiveStencilFaceEXT(face));
3256 checkGLcall("glActiveStencilFaceEXT(...)");
3257 glStencilFunc(func, ref, mask);
3258 checkGLcall("glStencilFunc(...)");
3259 glStencilOp(stencilFail, depthFail, stencilPass);
3260 checkGLcall("glStencilOp(...)");
3261 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3262 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3263 checkGLcall("glStencilFuncSeparateATI(...)");
3264 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3265 checkGLcall("glStencilOpSeparateATI(...)");
3266 } else {
3267 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3271 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3272 DWORD onesided_enable = FALSE;
3273 DWORD twosided_enable = FALSE;
3274 GLint func = GL_ALWAYS;
3275 GLint func_ccw = GL_ALWAYS;
3276 GLint ref = 0;
3277 GLuint mask = 0;
3278 GLint stencilFail = GL_KEEP;
3279 GLint depthFail = GL_KEEP;
3280 GLint stencilPass = GL_KEEP;
3281 GLint stencilFail_ccw = GL_KEEP;
3282 GLint depthFail_ccw = GL_KEEP;
3283 GLint stencilPass_ccw = GL_KEEP;
3285 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3286 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3287 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3288 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3289 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3290 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3291 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3292 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3293 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3294 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3295 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3296 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3297 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3298 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3299 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3300 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3301 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3302 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3303 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3304 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3305 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3306 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3307 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3308 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3310 switch(State) {
3311 case WINED3DRS_STENCILENABLE :
3312 onesided_enable = Value;
3313 break;
3314 case WINED3DRS_TWOSIDEDSTENCILMODE :
3315 twosided_enable = Value;
3316 break;
3317 case WINED3DRS_STENCILFUNC :
3318 func = StencilFunc(Value);
3319 break;
3320 case WINED3DRS_CCW_STENCILFUNC :
3321 func_ccw = StencilFunc(Value);
3322 break;
3323 case WINED3DRS_STENCILREF :
3324 ref = Value;
3325 break;
3326 case WINED3DRS_STENCILMASK :
3327 mask = Value;
3328 break;
3329 case WINED3DRS_STENCILFAIL :
3330 stencilFail = StencilOp(Value);
3331 break;
3332 case WINED3DRS_STENCILZFAIL :
3333 depthFail = StencilOp(Value);
3334 break;
3335 case WINED3DRS_STENCILPASS :
3336 stencilPass = StencilOp(Value);
3337 break;
3338 case WINED3DRS_CCW_STENCILFAIL :
3339 stencilFail_ccw = StencilOp(Value);
3340 break;
3341 case WINED3DRS_CCW_STENCILZFAIL :
3342 depthFail_ccw = StencilOp(Value);
3343 break;
3344 case WINED3DRS_CCW_STENCILPASS :
3345 stencilPass_ccw = StencilOp(Value);
3346 break;
3347 default :
3348 ERR("This should not happen!");
3351 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3352 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3353 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3354 onesided_enable, twosided_enable, ref, mask,
3355 func, stencilFail, depthFail, stencilPass,
3356 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3358 if (twosided_enable) {
3359 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3360 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3361 } else {
3362 if (onesided_enable) {
3363 glEnable(GL_STENCIL_TEST);
3364 checkGLcall("glEnable GL_STENCIL_TEST");
3365 glStencilFunc(func, ref, mask);
3366 checkGLcall("glStencilFunc(...)");
3367 glStencilOp(stencilFail, depthFail, stencilPass);
3368 checkGLcall("glStencilOp(...)");
3369 } else {
3370 glDisable(GL_STENCIL_TEST);
3371 checkGLcall("glDisable GL_STENCIL_TEST");
3376 /*****
3377 * Get / Set Render States
3378 * TODO: Verify against dx9 definitions
3379 *****/
3380 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3383 DWORD OldValue = This->stateBlock->renderState[State];
3385 /* Simple way of referring to either a DWORD or a 4 byte float */
3386 union {
3387 DWORD d;
3388 float f;
3389 } tmpvalue;
3391 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3392 This->updateStateBlock->changed.renderState[State] = TRUE;
3393 This->updateStateBlock->set.renderState[State] = TRUE;
3394 This->updateStateBlock->renderState[State] = Value;
3396 /* Handle recording of state blocks */
3397 if (This->isRecordingState) {
3398 TRACE("Recording... not performing anything\n");
3399 return WINED3D_OK;
3402 ENTER_GL();
3404 switch (State) {
3405 case WINED3DRS_FILLMODE :
3406 switch ((D3DFILLMODE) Value) {
3407 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3408 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3409 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3410 default:
3411 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3413 checkGLcall("glPolygonMode (fillmode)");
3414 break;
3416 case WINED3DRS_LIGHTING :
3417 if (Value) {
3418 glEnable(GL_LIGHTING);
3419 checkGLcall("glEnable GL_LIGHTING");
3420 } else {
3421 glDisable(GL_LIGHTING);
3422 checkGLcall("glDisable GL_LIGHTING");
3424 break;
3426 case WINED3DRS_ZENABLE :
3427 switch ((D3DZBUFFERTYPE) Value) {
3428 case D3DZB_FALSE:
3429 glDisable(GL_DEPTH_TEST);
3430 checkGLcall("glDisable GL_DEPTH_TEST");
3431 break;
3432 case D3DZB_TRUE:
3433 glEnable(GL_DEPTH_TEST);
3434 checkGLcall("glEnable GL_DEPTH_TEST");
3435 break;
3436 case D3DZB_USEW:
3437 glEnable(GL_DEPTH_TEST);
3438 checkGLcall("glEnable GL_DEPTH_TEST");
3439 FIXME("W buffer is not well handled\n");
3440 break;
3441 default:
3442 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3444 break;
3446 case WINED3DRS_CULLMODE :
3448 /* If we are culling "back faces with clockwise vertices" then
3449 set front faces to be counter clockwise and enable culling
3450 of back faces */
3451 switch ((D3DCULL) Value) {
3452 case D3DCULL_NONE:
3453 glDisable(GL_CULL_FACE);
3454 checkGLcall("glDisable GL_CULL_FACE");
3455 break;
3456 case D3DCULL_CW:
3457 glEnable(GL_CULL_FACE);
3458 checkGLcall("glEnable GL_CULL_FACE");
3459 if (This->renderUpsideDown) {
3460 glFrontFace(GL_CW);
3461 checkGLcall("glFrontFace GL_CW");
3462 } else {
3463 glFrontFace(GL_CCW);
3464 checkGLcall("glFrontFace GL_CCW");
3466 glCullFace(GL_BACK);
3467 break;
3468 case D3DCULL_CCW:
3469 glEnable(GL_CULL_FACE);
3470 checkGLcall("glEnable GL_CULL_FACE");
3471 if (This->renderUpsideDown) {
3472 glFrontFace(GL_CCW);
3473 checkGLcall("glFrontFace GL_CCW");
3474 } else {
3475 glFrontFace(GL_CW);
3476 checkGLcall("glFrontFace GL_CW");
3478 glCullFace(GL_BACK);
3479 break;
3480 default:
3481 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3483 break;
3485 case WINED3DRS_SHADEMODE :
3486 switch ((D3DSHADEMODE) Value) {
3487 case D3DSHADE_FLAT:
3488 glShadeModel(GL_FLAT);
3489 checkGLcall("glShadeModel");
3490 break;
3491 case D3DSHADE_GOURAUD:
3492 glShadeModel(GL_SMOOTH);
3493 checkGLcall("glShadeModel");
3494 break;
3495 case D3DSHADE_PHONG:
3496 FIXME("D3DSHADE_PHONG isn't supported\n");
3497 break;
3498 default:
3499 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3501 break;
3503 case WINED3DRS_DITHERENABLE :
3504 if (Value) {
3505 glEnable(GL_DITHER);
3506 checkGLcall("glEnable GL_DITHER");
3507 } else {
3508 glDisable(GL_DITHER);
3509 checkGLcall("glDisable GL_DITHER");
3511 break;
3513 case WINED3DRS_ZWRITEENABLE :
3514 if (Value) {
3515 glDepthMask(1);
3516 checkGLcall("glDepthMask");
3517 } else {
3518 glDepthMask(0);
3519 checkGLcall("glDepthMask");
3521 break;
3523 case WINED3DRS_ZFUNC :
3525 int glParm = GL_LESS;
3527 switch ((D3DCMPFUNC) Value) {
3528 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3529 case D3DCMP_LESS: glParm=GL_LESS; break;
3530 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3531 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3532 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3533 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3534 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3535 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3536 default:
3537 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3539 glDepthFunc(glParm);
3540 checkGLcall("glDepthFunc");
3542 break;
3544 case WINED3DRS_AMBIENT :
3546 float col[4];
3547 D3DCOLORTOGLFLOAT4(Value, col);
3548 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3549 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3550 checkGLcall("glLightModel for MODEL_AMBIENT");
3553 break;
3555 case WINED3DRS_ALPHABLENDENABLE :
3556 if (Value) {
3557 glEnable(GL_BLEND);
3558 checkGLcall("glEnable GL_BLEND");
3559 } else {
3560 glDisable(GL_BLEND);
3561 checkGLcall("glDisable GL_BLEND");
3563 break;
3565 case WINED3DRS_SRCBLEND :
3566 case WINED3DRS_DESTBLEND :
3568 int newVal = GL_ZERO;
3569 switch (Value) {
3570 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3571 case D3DBLEND_ONE : newVal = GL_ONE; break;
3572 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3573 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3574 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3575 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3576 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3577 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3578 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3579 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3580 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3582 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3583 This->srcBlend = newVal;
3584 This->dstBlend = newVal;
3585 break;
3587 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3588 This->srcBlend = newVal;
3589 This->dstBlend = newVal;
3590 break;
3591 default:
3592 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3595 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3596 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3597 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3598 glBlendFunc(This->srcBlend, This->dstBlend);
3600 checkGLcall("glBlendFunc");
3602 break;
3604 case WINED3DRS_ALPHATESTENABLE :
3605 case WINED3DRS_ALPHAFUNC :
3606 case WINED3DRS_ALPHAREF :
3607 case WINED3DRS_COLORKEYENABLE :
3609 int glParm = 0.0;
3610 float ref = GL_LESS;
3611 BOOL enable_ckey = FALSE;
3613 IWineD3DSurfaceImpl *surf;
3615 /* Find out if the texture on the first stage has a ckey set */
3616 if(This->stateBlock->textures[0]) {
3617 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3618 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3621 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3622 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3623 glEnable(GL_ALPHA_TEST);
3624 checkGLcall("glEnable GL_ALPHA_TEST");
3625 } else {
3626 glDisable(GL_ALPHA_TEST);
3627 checkGLcall("glDisable GL_ALPHA_TEST");
3628 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3629 * enable call
3631 break;
3634 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3635 glParm = GL_NOTEQUAL;
3636 ref = 0.0;
3637 } else {
3638 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3640 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3641 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3642 case D3DCMP_LESS: glParm = GL_LESS; break;
3643 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3644 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3645 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3646 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3647 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3648 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3649 default:
3650 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3653 This->alphafunc = glParm;
3654 glAlphaFunc(glParm, ref);
3655 checkGLcall("glAlphaFunc");
3657 break;
3659 case WINED3DRS_CLIPPLANEENABLE :
3660 case WINED3DRS_CLIPPING :
3662 /* Ensure we only do the changed clip planes */
3663 DWORD enable = 0xFFFFFFFF;
3664 DWORD disable = 0x00000000;
3666 /* If enabling / disabling all */
3667 if (State == WINED3DRS_CLIPPING) {
3668 if (Value) {
3669 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3670 disable = 0x00;
3671 } else {
3672 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3673 enable = 0x00;
3675 } else {
3676 enable = Value & ~OldValue;
3677 disable = ~Value & OldValue;
3680 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3681 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3682 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3683 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3684 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3685 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3687 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3688 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3689 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3690 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3691 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3692 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3694 /** update clipping status */
3695 if (enable) {
3696 This->stateBlock->clip_status.ClipUnion = 0;
3697 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3698 } else {
3699 This->stateBlock->clip_status.ClipUnion = 0;
3700 This->stateBlock->clip_status.ClipIntersection = 0;
3703 break;
3705 case WINED3DRS_BLENDOP :
3707 int glParm = GL_FUNC_ADD;
3709 switch ((D3DBLENDOP) Value) {
3710 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3711 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3712 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3713 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3714 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3715 default:
3716 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3719 if(GL_SUPPORT(ARB_IMAGING)) {
3720 TRACE("glBlendEquation(%x)\n", glParm);
3721 GL_EXTCALL(glBlendEquation(glParm));
3722 checkGLcall("glBlendEquation");
3723 } else {
3724 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3727 break;
3729 case WINED3DRS_TEXTUREFACTOR :
3731 unsigned int i;
3733 /* Note the texture color applies to all textures whereas
3734 GL_TEXTURE_ENV_COLOR applies to active only */
3735 float col[4];
3736 D3DCOLORTOGLFLOAT4(Value, col);
3737 /* Set the default alpha blend color */
3738 if (GL_SUPPORT(ARB_IMAGING)) {
3739 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3740 checkGLcall("glBlendColor");
3741 } else {
3742 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3745 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3746 /* And now the default texture color as well */
3747 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3748 /* Note the D3DRS value applies to all textures, but GL has one
3749 per texture, so apply it now ready to be used! */
3750 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3751 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3752 checkGLcall("glActiveTextureARB");
3753 } else if (i>0) {
3754 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3757 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3758 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3762 break;
3764 case WINED3DRS_SPECULARENABLE :
3766 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3767 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3768 specular color. This is wrong:
3769 Separate specular color means the specular colour is maintained separately, whereas
3770 single color means it is merged in. However in both cases they are being used to
3771 some extent.
3772 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3773 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3774 running 1.4 yet!
3777 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3778 * Instead, we need to setup the FinalCombiner properly.
3780 * The default setup for the FinalCombiner is:
3782 * <variable> <input> <mapping> <usage>
3783 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3784 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3785 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3786 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3787 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3788 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3789 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3791 * That's pretty much fine as it is, except for variable B, which needs to take
3792 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3793 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3796 if (Value) {
3797 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3798 checkGLcall("glMaterialfv");
3799 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3800 glEnable(GL_COLOR_SUM_EXT);
3801 } else {
3802 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3804 checkGLcall("glEnable(GL_COLOR_SUM)");
3806 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3807 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3808 checkGLcall("glFinalCombinerInputNV()");
3810 } else {
3811 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3813 /* for the case of enabled lighting: */
3814 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3815 checkGLcall("glMaterialfv");
3817 /* for the case of disabled lighting: */
3818 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3819 glDisable(GL_COLOR_SUM_EXT);
3820 } else {
3821 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3823 checkGLcall("glDisable(GL_COLOR_SUM)");
3825 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3826 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3827 checkGLcall("glFinalCombinerInputNV()");
3831 break;
3833 case WINED3DRS_STENCILENABLE :
3834 case WINED3DRS_TWOSIDEDSTENCILMODE :
3835 case WINED3DRS_STENCILFUNC :
3836 case WINED3DRS_CCW_STENCILFUNC :
3837 case WINED3DRS_STENCILREF :
3838 case WINED3DRS_STENCILMASK :
3839 case WINED3DRS_STENCILFAIL :
3840 case WINED3DRS_STENCILZFAIL :
3841 case WINED3DRS_STENCILPASS :
3842 case WINED3DRS_CCW_STENCILFAIL :
3843 case WINED3DRS_CCW_STENCILZFAIL :
3844 case WINED3DRS_CCW_STENCILPASS :
3845 renderstate_stencil(This, State, Value);
3846 break;
3847 case WINED3DRS_STENCILWRITEMASK :
3849 glStencilMask(Value);
3850 TRACE("glStencilMask(%lu)\n", Value);
3851 checkGLcall("glStencilMask");
3853 break;
3855 case WINED3DRS_FOGENABLE :
3857 if (Value) {
3858 glEnable(GL_FOG);
3859 checkGLcall("glEnable GL_FOG");
3860 } else {
3861 glDisable(GL_FOG);
3862 checkGLcall("glDisable GL_FOG");
3865 break;
3867 case WINED3DRS_RANGEFOGENABLE :
3869 if (Value) {
3870 TRACE("Enabled RANGEFOG");
3871 } else {
3872 TRACE("Disabled RANGEFOG");
3875 break;
3877 case WINED3DRS_FOGCOLOR :
3879 float col[4];
3880 D3DCOLORTOGLFLOAT4(Value, col);
3881 /* Set the default alpha blend color */
3882 glFogfv(GL_FOG_COLOR, &col[0]);
3883 checkGLcall("glFog GL_FOG_COLOR");
3885 break;
3887 case WINED3DRS_FOGTABLEMODE :
3888 case WINED3DRS_FOGVERTEXMODE :
3890 /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */
3891 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3892 glHint(GL_FOG_HINT, GL_FASTEST);
3893 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3894 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3895 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3896 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3898 case D3DFOG_EXP: {
3899 if(!This->last_was_rhw) {
3900 glFogi(GL_FOG_MODE, GL_EXP);
3901 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3902 if(GL_SUPPORT(EXT_FOG_COORD)) {
3903 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3904 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3905 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3906 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3908 break;
3911 case D3DFOG_EXP2: {
3912 if(!This->last_was_rhw) {
3913 glFogi(GL_FOG_MODE, GL_EXP2);
3914 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3915 if(GL_SUPPORT(EXT_FOG_COORD)) {
3916 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3917 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3918 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3919 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3921 break;
3924 case D3DFOG_LINEAR: {
3925 if(!This->last_was_rhw) {
3926 glFogi(GL_FOG_MODE, GL_LINEAR);
3927 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3928 if(GL_SUPPORT(EXT_FOG_COORD)) {
3929 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3930 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3931 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3932 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3934 break;
3937 case D3DFOG_NONE: {
3938 /* Both are none? According to msdn the alpha channel of the specular
3939 * color contains a fog factor. Set it in drawStridedSlow.
3940 * Same happens with Vertexfog on transformed vertices
3942 if(GL_SUPPORT(EXT_FOG_COORD)) {
3943 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3944 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3945 glFogi(GL_FOG_MODE, GL_LINEAR);
3946 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3947 glFogf(GL_FOG_START, (float) 0xff);
3948 checkGLcall("glFogfv GL_FOG_START");
3949 glFogf(GL_FOG_END, 0.0);
3950 checkGLcall("glFogfv GL_FOG_END");
3951 } else {
3952 /* Disable GL fog, handle this in software in drawStridedSlow */
3953 glDisable(GL_FOG);
3954 checkGLcall("glDisable(GL_FOG)");
3956 break;
3958 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3960 } else {
3961 glHint(GL_FOG_HINT, GL_NICEST);
3962 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3963 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3964 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3965 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3966 if(GL_SUPPORT(EXT_FOG_COORD)) {
3967 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3968 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3969 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3970 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3972 break;
3973 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3974 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3975 if(GL_SUPPORT(EXT_FOG_COORD)) {
3976 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3977 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3978 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3979 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3981 break;
3982 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3983 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3984 if(GL_SUPPORT(EXT_FOG_COORD)) {
3985 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3986 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3987 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3990 break;
3991 case D3DFOG_NONE: /* Won't happen */
3992 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3995 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3996 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3999 break;
4001 case WINED3DRS_FOGSTART :
4003 tmpvalue.d = Value;
4004 glFogfv(GL_FOG_START, &tmpvalue.f);
4005 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4006 TRACE("Fog Start == %f\n", tmpvalue.f);
4008 break;
4010 case WINED3DRS_FOGEND :
4012 tmpvalue.d = Value;
4013 glFogfv(GL_FOG_END, &tmpvalue.f);
4014 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4015 TRACE("Fog End == %f\n", tmpvalue.f);
4017 break;
4019 case WINED3DRS_FOGDENSITY :
4021 tmpvalue.d = Value;
4022 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4023 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4025 break;
4027 case WINED3DRS_VERTEXBLEND :
4029 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4030 TRACE("Vertex Blending state to %ld\n", Value);
4032 break;
4034 case WINED3DRS_TWEENFACTOR :
4036 tmpvalue.d = Value;
4037 This->updateStateBlock->tween_factor = tmpvalue.f;
4038 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4040 break;
4042 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4044 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4046 break;
4048 case WINED3DRS_COLORVERTEX :
4049 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4050 case WINED3DRS_SPECULARMATERIALSOURCE :
4051 case WINED3DRS_AMBIENTMATERIALSOURCE :
4052 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4054 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4056 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4057 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4058 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4059 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4060 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4061 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4063 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4064 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4065 Parm = GL_AMBIENT_AND_DIFFUSE;
4066 } else {
4067 Parm = GL_DIFFUSE;
4069 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4070 Parm = GL_AMBIENT;
4071 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4072 Parm = GL_EMISSION;
4073 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4074 Parm = GL_SPECULAR;
4075 } else {
4076 Parm = -1;
4079 if (Parm == -1) {
4080 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4081 } else {
4082 This->tracking_color = NEEDS_TRACKING;
4083 This->tracking_parm = Parm;
4086 } else {
4087 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4090 break;
4092 case WINED3DRS_LINEPATTERN :
4094 union {
4095 DWORD d;
4096 D3DLINEPATTERN lp;
4097 } tmppattern;
4098 tmppattern.d = Value;
4100 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4102 if (tmppattern.lp.wRepeatFactor) {
4103 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4104 checkGLcall("glLineStipple(repeat, linepattern)");
4105 glEnable(GL_LINE_STIPPLE);
4106 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4107 } else {
4108 glDisable(GL_LINE_STIPPLE);
4109 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4112 break;
4114 case WINED3DRS_ZBIAS : /* D3D8 only */
4116 if (Value) {
4117 tmpvalue.d = Value;
4118 TRACE("ZBias value %f\n", tmpvalue.f);
4119 glPolygonOffset(0, -tmpvalue.f);
4120 checkGLcall("glPolygonOffset(0, -Value)");
4121 glEnable(GL_POLYGON_OFFSET_FILL);
4122 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4123 glEnable(GL_POLYGON_OFFSET_LINE);
4124 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4125 glEnable(GL_POLYGON_OFFSET_POINT);
4126 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4127 } else {
4128 glDisable(GL_POLYGON_OFFSET_FILL);
4129 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4130 glDisable(GL_POLYGON_OFFSET_LINE);
4131 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4132 glDisable(GL_POLYGON_OFFSET_POINT);
4133 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4136 break;
4138 case WINED3DRS_NORMALIZENORMALS :
4139 if (Value) {
4140 glEnable(GL_NORMALIZE);
4141 checkGLcall("glEnable(GL_NORMALIZE);");
4142 } else {
4143 glDisable(GL_NORMALIZE);
4144 checkGLcall("glDisable(GL_NORMALIZE);");
4146 break;
4148 case WINED3DRS_POINTSIZE :
4149 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4150 tmpvalue.d = Value;
4151 TRACE("Set point size to %f\n", tmpvalue.f);
4152 glPointSize(tmpvalue.f);
4153 checkGLcall("glPointSize(...);");
4154 break;
4156 case WINED3DRS_POINTSIZE_MIN :
4157 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4158 tmpvalue.d = Value;
4159 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4160 checkGLcall("glPointParameterfEXT(...);");
4161 } else {
4162 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4164 break;
4166 case WINED3DRS_POINTSIZE_MAX :
4167 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4168 tmpvalue.d = Value;
4169 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4170 checkGLcall("glPointParameterfEXT(...);");
4171 } else {
4172 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4174 break;
4176 case WINED3DRS_POINTSCALE_A :
4177 case WINED3DRS_POINTSCALE_B :
4178 case WINED3DRS_POINTSCALE_C :
4179 case WINED3DRS_POINTSCALEENABLE :
4182 * POINTSCALEENABLE controls how point size value is treated. If set to
4183 * true, the point size is scaled with respect to height of viewport.
4184 * When set to false point size is in pixels.
4186 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4189 /* Default values */
4190 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4193 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4194 * This means that OpenGL will clamp really small point sizes to 1.0f.
4195 * To correct for this we need to multiply by the scale factor when sizes
4196 * are less than 1.0f. scale_factor = 1.0f / point_size.
4198 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4199 if(pointSize > 0.0f) {
4200 GLfloat scaleFactor;
4202 if(pointSize < 1.0f) {
4203 scaleFactor = pointSize * pointSize;
4204 } else {
4205 scaleFactor = 1.0f;
4208 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4209 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4210 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4211 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4212 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4213 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4214 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4218 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4219 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4220 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4222 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4223 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4224 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4225 } else {
4226 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4228 break;
4230 case WINED3DRS_COLORWRITEENABLE :
4232 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4233 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4234 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4235 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4236 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4237 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4238 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4239 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4240 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4241 checkGLcall("glColorMask(...)");
4243 break;
4245 case WINED3DRS_LOCALVIEWER :
4247 GLint state = (Value) ? 1 : 0;
4248 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4249 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4251 break;
4253 case WINED3DRS_LASTPIXEL :
4255 if (Value) {
4256 TRACE("Last Pixel Drawing Enabled\n");
4257 } else {
4258 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4261 break;
4263 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4265 if (Value) {
4266 TRACE("Software Processing Enabled\n");
4267 } else {
4268 TRACE("Software Processing Disabled\n");
4271 break;
4273 /** not supported */
4274 case WINED3DRS_ZVISIBLE :
4276 LEAVE_GL();
4277 return WINED3DERR_INVALIDCALL;
4279 case WINED3DRS_POINTSPRITEENABLE :
4281 /* TODO: NV_POINT_SPRITE */
4282 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4283 TRACE("Point sprites not supported\n");
4284 break;
4288 * Point sprites are always enabled. Value controls texture coordinate
4289 * replacement mode. Must be set true for point sprites to use
4290 * textures.
4292 glEnable(GL_POINT_SPRITE_ARB);
4293 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4295 if (Value) {
4296 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4297 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4298 } else {
4299 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4300 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4302 break;
4304 case WINED3DRS_EDGEANTIALIAS :
4306 if(Value) {
4307 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4308 glEnable(GL_BLEND);
4309 checkGLcall("glEnable(GL_BLEND)");
4310 glEnable(GL_LINE_SMOOTH);
4311 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4312 } else {
4313 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4314 glDisable(GL_BLEND);
4315 checkGLcall("glDisable(GL_BLEND)");
4317 glDisable(GL_LINE_SMOOTH);
4318 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4320 break;
4322 case WINED3DRS_WRAP0 :
4323 case WINED3DRS_WRAP1 :
4324 case WINED3DRS_WRAP2 :
4325 case WINED3DRS_WRAP3 :
4326 case WINED3DRS_WRAP4 :
4327 case WINED3DRS_WRAP5 :
4328 case WINED3DRS_WRAP6 :
4329 case WINED3DRS_WRAP7 :
4330 case WINED3DRS_WRAP8 :
4331 case WINED3DRS_WRAP9 :
4332 case WINED3DRS_WRAP10 :
4333 case WINED3DRS_WRAP11 :
4334 case WINED3DRS_WRAP12 :
4335 case WINED3DRS_WRAP13 :
4336 case WINED3DRS_WRAP14 :
4337 case WINED3DRS_WRAP15 :
4339 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4340 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4341 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4342 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4343 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4345 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4347 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4348 break;
4349 case WINED3DRS_MULTISAMPLEANTIALIAS :
4351 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4352 TRACE("Multisample antialiasing not supported\n");
4353 break;
4356 if(Value) {
4357 glEnable(GL_MULTISAMPLE_ARB);
4358 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4359 } else {
4360 glDisable(GL_MULTISAMPLE_ARB);
4361 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4363 break;
4365 case WINED3DRS_SCISSORTESTENABLE :
4367 if(Value) {
4368 glEnable(GL_SCISSOR_TEST);
4369 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4370 } else {
4371 glDisable(GL_SCISSOR_TEST);
4372 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4374 break;
4376 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4378 if(Value) {
4379 tmpvalue.d = Value;
4380 glEnable(GL_POLYGON_OFFSET_FILL);
4381 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4382 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4383 checkGLcall("glPolygonOffset(...)");
4384 } else {
4385 glDisable(GL_POLYGON_OFFSET_FILL);
4386 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4388 break;
4390 case WINED3DRS_ANTIALIASEDLINEENABLE :
4392 if(Value) {
4393 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4394 glEnable(GL_BLEND);
4395 checkGLcall("glEnable(GL_BLEND)");
4396 glEnable(GL_LINE_SMOOTH);
4397 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4398 } else {
4399 glDisable(GL_BLEND);
4400 checkGLcall("glDisable(GL_BLEND)");
4401 glDisable(GL_LINE_SMOOTH);
4402 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4404 break;
4406 case WINED3DRS_DEPTHBIAS :
4408 if(Value) {
4409 tmpvalue.d = Value;
4410 glEnable(GL_POLYGON_OFFSET_FILL);
4411 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4412 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4413 checkGLcall("glPolygonOffset(...)");
4414 } else {
4415 glDisable(GL_POLYGON_OFFSET_FILL);
4416 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4418 break;
4421 case WINED3DRS_TEXTUREPERSPECTIVE :
4423 if (Value)
4424 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4425 else
4426 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4427 break;
4430 case WINED3DRS_STIPPLEDALPHA :
4432 if (Value)
4433 ERR(" Stippled Alpha not supported yet.\n");
4434 break;
4436 case WINED3DRS_ANTIALIAS :
4438 if (Value)
4439 ERR(" Antialias not supported yet.\n");
4440 break;
4442 default:
4443 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4446 LEAVE_GL();
4448 return WINED3D_OK;
4451 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4453 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4454 *pValue = This->stateBlock->renderState[State];
4455 return WINED3D_OK;
4458 /*****
4459 * Get / Set Sampler States
4460 * TODO: Verify against dx9 definitions
4461 *****/
4463 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4466 * SetSampler is designed to allow for more than the standard up to 8 textures
4467 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4468 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4470 * http://developer.nvidia.com/object/General_FAQ.html#t6
4472 * There are two new settings for GForce
4473 * the sampler one:
4474 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4475 * and the texture one:
4476 * GL_MAX_TEXTURE_COORDS_ARB.
4477 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4478 ******************/
4479 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4480 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4481 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4482 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4483 return WINED3DERR_INVALIDCALL;
4486 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4487 debug_d3dsamplerstate(Type), Type, Value);
4488 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4489 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4490 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4492 /* Handle recording of state blocks */
4493 if (This->isRecordingState) {
4494 TRACE("Recording... not performing anything\n");
4495 return WINED3D_OK;
4498 return WINED3D_OK;
4501 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 /** TODO: check that sampler is in range **/
4504 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4505 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4507 return WINED3D_OK;
4510 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4512 ENTER_GL();
4514 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4515 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4516 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4517 LEAVE_GL();
4519 return WINED3D_OK;
4522 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 GLint scissorBox[4];
4526 ENTER_GL();
4527 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4528 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4529 pRect->left = scissorBox[0];
4530 pRect->top = scissorBox[1];
4531 pRect->right = scissorBox[0] + scissorBox[2];
4532 pRect->bottom = scissorBox[1] + scissorBox[3];
4533 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4534 LEAVE_GL();
4535 return WINED3D_OK;
4538 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4540 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4542 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4544 This->updateStateBlock->vertexDecl = pDecl;
4545 This->updateStateBlock->changed.vertexDecl = TRUE;
4546 This->updateStateBlock->set.vertexDecl = TRUE;
4548 if (This->isRecordingState) {
4549 TRACE("Recording... not performing anything\n");
4552 if (NULL != pDecl) {
4553 IWineD3DVertexDeclaration_AddRef(pDecl);
4555 if (NULL != oldDecl) {
4556 IWineD3DVertexDeclaration_Release(oldDecl);
4558 return WINED3D_OK;
4561 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4566 *ppDecl = This->stateBlock->vertexDecl;
4567 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4568 return WINED3D_OK;
4571 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4575 This->updateStateBlock->vertexShader = pShader;
4576 This->updateStateBlock->changed.vertexShader = TRUE;
4577 This->updateStateBlock->set.vertexShader = TRUE;
4579 if (This->isRecordingState) {
4580 TRACE("Recording... not performing anything\n");
4583 if (NULL != pShader) {
4584 IWineD3DVertexShader_AddRef(pShader);
4586 if (NULL != oldShader) {
4587 IWineD3DVertexShader_Release(oldShader);
4590 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4592 * TODO: merge HAL shaders context switching from prototype
4594 return WINED3D_OK;
4597 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4600 if (NULL == ppShader) {
4601 return WINED3DERR_INVALIDCALL;
4603 *ppShader = This->stateBlock->vertexShader;
4604 if( NULL != *ppShader)
4605 IWineD3DVertexShader_AddRef(*ppShader);
4607 TRACE("(%p) : returning %p\n", This, *ppShader);
4608 return WINED3D_OK;
4611 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4612 IWineD3DDevice *iface,
4613 UINT start,
4614 CONST BOOL *srcData,
4615 UINT count) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 int i, cnt = min(count, MAX_CONST_B - start);
4620 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4621 iface, srcData, start, count);
4623 if (srcData == NULL || cnt < 0)
4624 return WINED3DERR_INVALIDCALL;
4626 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4627 for (i = 0; i < cnt; i++)
4628 TRACE("Set BOOL constant %u to %s\n", i, srcData[i]? "true":"false");
4630 for (i = start; i < cnt + start; ++i) {
4631 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4632 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4635 return WINED3D_OK;
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4639 IWineD3DDevice *iface,
4640 UINT start,
4641 BOOL *dstData,
4642 UINT count) {
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 int cnt = min(count, MAX_CONST_B - start);
4647 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4648 iface, dstData, start, count);
4650 if (dstData == NULL || cnt < 0)
4651 return WINED3DERR_INVALIDCALL;
4653 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4654 return WINED3D_OK;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4658 IWineD3DDevice *iface,
4659 UINT start,
4660 CONST int *srcData,
4661 UINT count) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 int i, cnt = min(count, MAX_CONST_I - start);
4666 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4667 iface, srcData, start, count);
4669 if (srcData == NULL || cnt < 0)
4670 return WINED3DERR_INVALIDCALL;
4672 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4673 for (i = 0; i < cnt; i++)
4674 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", i,
4675 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4677 for (i = start; i < cnt + start; ++i) {
4678 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4679 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4682 return WINED3D_OK;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4686 IWineD3DDevice *iface,
4687 UINT start,
4688 int *dstData,
4689 UINT count) {
4691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4692 int cnt = min(count, MAX_CONST_I - start);
4694 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4695 iface, dstData, start, count);
4697 if (dstData == NULL || cnt < 0)
4698 return WINED3DERR_INVALIDCALL;
4700 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4705 IWineD3DDevice *iface,
4706 UINT start,
4707 CONST float *srcData,
4708 UINT count) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4713 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4714 iface, srcData, start, count);
4716 if (srcData == NULL || cnt < 0)
4717 return WINED3DERR_INVALIDCALL;
4719 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4720 for (i = 0; i < cnt; i++)
4721 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", i,
4722 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4724 for (i = start; i < cnt + start; ++i) {
4725 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4726 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4729 return WINED3D_OK;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4733 IWineD3DDevice *iface,
4734 UINT start,
4735 float *dstData,
4736 UINT count) {
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4741 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4742 iface, dstData, start, count);
4744 if (dstData == NULL || cnt < 0)
4745 return WINED3DERR_INVALIDCALL;
4747 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4748 return WINED3D_OK;
4751 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4754 This->updateStateBlock->pixelShader = pShader;
4755 This->updateStateBlock->changed.pixelShader = TRUE;
4756 This->updateStateBlock->set.pixelShader = TRUE;
4758 /* Handle recording of state blocks */
4759 if (This->isRecordingState) {
4760 TRACE("Recording... not performing anything\n");
4763 if (NULL != pShader) {
4764 IWineD3DPixelShader_AddRef(pShader);
4766 if (NULL != oldShader) {
4767 IWineD3DPixelShader_Release(oldShader);
4770 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4772 * TODO: merge HAL shaders context switching from prototype
4774 return WINED3D_OK;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 if (NULL == ppShader) {
4781 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 *ppShader = This->stateBlock->pixelShader;
4786 if (NULL != *ppShader) {
4787 IWineD3DPixelShader_AddRef(*ppShader);
4789 TRACE("(%p) : returning %p\n", This, *ppShader);
4790 return WINED3D_OK;
4793 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4794 IWineD3DDevice *iface,
4795 UINT start,
4796 CONST BOOL *srcData,
4797 UINT count) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 int i, cnt = min(count, MAX_CONST_B - start);
4802 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4803 iface, srcData, start, count);
4805 if (srcData == NULL || cnt < 0)
4806 return WINED3DERR_INVALIDCALL;
4808 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4809 for (i = 0; i < cnt; i++)
4810 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4812 for (i = start; i < cnt + start; ++i) {
4813 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4814 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4817 return WINED3D_OK;
4820 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4821 IWineD3DDevice *iface,
4822 UINT start,
4823 BOOL *dstData,
4824 UINT count) {
4826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4827 int cnt = min(count, MAX_CONST_B - start);
4829 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4830 iface, dstData, start, count);
4832 if (dstData == NULL || cnt < 0)
4833 return WINED3DERR_INVALIDCALL;
4835 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4840 IWineD3DDevice *iface,
4841 UINT start,
4842 CONST int *srcData,
4843 UINT count) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 int i, cnt = min(count, MAX_CONST_I - start);
4848 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4849 iface, srcData, start, count);
4851 if (srcData == NULL || cnt < 0)
4852 return WINED3DERR_INVALIDCALL;
4854 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4855 for (i = 0; i < cnt; i++)
4856 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4857 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4859 for (i = start; i < cnt + start; ++i) {
4860 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4861 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4864 return WINED3D_OK;
4867 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4868 IWineD3DDevice *iface,
4869 UINT start,
4870 int *dstData,
4871 UINT count) {
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4874 int cnt = min(count, MAX_CONST_I - start);
4876 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4877 iface, dstData, start, count);
4879 if (dstData == NULL || cnt < 0)
4880 return WINED3DERR_INVALIDCALL;
4882 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4887 IWineD3DDevice *iface,
4888 UINT start,
4889 CONST float *srcData,
4890 UINT count) {
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4895 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4896 iface, srcData, start, count);
4898 if (srcData == NULL || cnt < 0)
4899 return WINED3DERR_INVALIDCALL;
4901 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4902 for (i = 0; i < cnt; i++)
4903 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4904 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4906 for (i = start; i < cnt + start; ++i) {
4907 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4908 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4911 return WINED3D_OK;
4914 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4915 IWineD3DDevice *iface,
4916 UINT start,
4917 float *dstData,
4918 UINT count) {
4920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4921 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4923 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4924 iface, dstData, start, count);
4926 if (dstData == NULL || cnt < 0)
4927 return WINED3DERR_INVALIDCALL;
4929 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4930 return WINED3D_OK;
4933 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4934 static HRESULT
4935 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4936 char *dest_ptr, *dest_conv = NULL;
4937 unsigned int i;
4938 DWORD DestFVF = dest->fvf;
4939 D3DVIEWPORT9 vp;
4940 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4941 BOOL doClip;
4942 int numTextures;
4944 if (SrcFVF & D3DFVF_NORMAL) {
4945 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4948 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4949 ERR("Source has no position mask\n");
4950 return WINED3DERR_INVALIDCALL;
4953 /* We might access VBOs from this code, so hold the lock */
4954 ENTER_GL();
4956 if (dest->resource.allocatedMemory == NULL) {
4957 /* This may happen if we do direct locking into a vbo. Unlikely,
4958 * but theoretically possible(ddraw processvertices test)
4960 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4961 if(!dest->resource.allocatedMemory) {
4962 LEAVE_GL();
4963 ERR("Out of memory\n");
4964 return E_OUTOFMEMORY;
4966 if(dest->vbo) {
4967 void *src;
4968 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4969 checkGLcall("glBindBufferARB");
4970 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4971 if(src) {
4972 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4974 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4975 checkGLcall("glUnmapBufferARB");
4979 /* Get a pointer into the destination vbo(create one if none exists) and
4980 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4982 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4983 CreateVBO(dest);
4986 if(dest->vbo) {
4987 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4988 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4989 if(!dest_conv) {
4990 ERR("glMapBuffer failed\n");
4991 /* Continue without storing converted vertices */
4995 /* Should I clip?
4996 * a) D3DRS_CLIPPING is enabled
4997 * b) WINED3DVOP_CLIP is passed
4999 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5000 static BOOL warned = FALSE;
5002 * The clipping code is not quite correct. Some things need
5003 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5004 * so disable clipping for now.
5005 * (The graphics in Half-Life are broken, and my processvertices
5006 * test crashes with IDirect3DDevice3)
5007 doClip = TRUE;
5009 doClip = FALSE;
5010 if(!warned) {
5011 warned = TRUE;
5012 FIXME("Clipping is broken and disabled for now\n");
5014 } else doClip = FALSE;
5015 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5016 if(dest_conv) {
5017 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5020 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5021 D3DTS_VIEW,
5022 &view_mat);
5023 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5024 D3DTS_PROJECTION,
5025 &proj_mat);
5026 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5027 D3DTS_WORLDMATRIX(0),
5028 &world_mat);
5030 TRACE("View mat:\n");
5031 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); \
5032 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); \
5033 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); \
5034 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); \
5036 TRACE("Proj mat:\n");
5037 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); \
5038 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); \
5039 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); \
5040 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); \
5042 TRACE("World mat:\n");
5043 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); \
5044 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); \
5045 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); \
5046 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); \
5048 /* Get the viewport */
5049 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5050 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5051 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5053 multiply_matrix(&mat,&view_mat,&world_mat);
5054 multiply_matrix(&mat,&proj_mat,&mat);
5056 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5058 for (i = 0; i < dwCount; i+= 1) {
5059 unsigned int tex_index;
5061 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5062 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5063 /* The position first */
5064 float *p =
5065 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5066 float x, y, z, rhw;
5067 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5069 /* Multiplication with world, view and projection matrix */
5070 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);
5071 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);
5072 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);
5073 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);
5075 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5077 /* WARNING: The following things are taken from d3d7 and were not yet checked
5078 * against d3d8 or d3d9!
5081 /* Clipping conditions: From
5082 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5084 * A vertex is clipped if it does not match the following requirements
5085 * -rhw < x <= rhw
5086 * -rhw < y <= rhw
5087 * 0 < z <= rhw
5088 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5090 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5091 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5095 if( doClip == FALSE ||
5096 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5097 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5098 ( rhw > eps ) ) ) {
5100 /* "Normal" viewport transformation (not clipped)
5101 * 1) The values are divided by rhw
5102 * 2) The y axis is negative, so multiply it with -1
5103 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5104 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5105 * 4) Multiply x with Width/2 and add Width/2
5106 * 5) The same for the height
5107 * 6) Add the viewpoint X and Y to the 2D coordinates and
5108 * The minimum Z value to z
5109 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5111 * Well, basically it's simply a linear transformation into viewport
5112 * coordinates
5115 x /= rhw;
5116 y /= rhw;
5117 z /= rhw;
5119 y *= -1;
5121 x *= vp.Width / 2;
5122 y *= vp.Height / 2;
5123 z *= vp.MaxZ - vp.MinZ;
5125 x += vp.Width / 2 + vp.X;
5126 y += vp.Height / 2 + vp.Y;
5127 z += vp.MinZ;
5129 rhw = 1 / rhw;
5130 } else {
5131 /* That vertex got clipped
5132 * Contrary to OpenGL it is not dropped completely, it just
5133 * undergoes a different calculation.
5135 TRACE("Vertex got clipped\n");
5136 x += rhw;
5137 y += rhw;
5139 x /= 2;
5140 y /= 2;
5142 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5143 * outside of the main vertex buffer memory. That needs some more
5144 * investigation...
5148 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5151 ( (float *) dest_ptr)[0] = x;
5152 ( (float *) dest_ptr)[1] = y;
5153 ( (float *) dest_ptr)[2] = z;
5154 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5156 dest_ptr += 3 * sizeof(float);
5158 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5159 dest_ptr += sizeof(float);
5162 if(dest_conv) {
5163 float w = 1 / rhw;
5164 ( (float *) dest_conv)[0] = x * w;
5165 ( (float *) dest_conv)[1] = y * w;
5166 ( (float *) dest_conv)[2] = z * w;
5167 ( (float *) dest_conv)[3] = w;
5169 dest_conv += 3 * sizeof(float);
5171 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5172 dest_conv += sizeof(float);
5176 if (DestFVF & D3DFVF_PSIZE) {
5177 dest_ptr += sizeof(DWORD);
5178 if(dest_conv) dest_conv += sizeof(DWORD);
5180 if (DestFVF & D3DFVF_NORMAL) {
5181 float *normal =
5182 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5183 /* AFAIK this should go into the lighting information */
5184 FIXME("Didn't expect the destination to have a normal\n");
5185 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5186 if(dest_conv) {
5187 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5191 if (DestFVF & D3DFVF_DIFFUSE) {
5192 DWORD *color_d =
5193 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5194 if(!color_d) {
5195 static BOOL warned = FALSE;
5197 if(warned == FALSE) {
5198 ERR("No diffuse color in source, but destination has one\n");
5199 warned = TRUE;
5202 *( (DWORD *) dest_ptr) = 0xffffffff;
5203 dest_ptr += sizeof(DWORD);
5205 if(dest_conv) {
5206 *( (DWORD *) dest_conv) = 0xffffffff;
5207 dest_conv += sizeof(DWORD);
5210 else {
5211 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5212 if(dest_conv) {
5213 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5214 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5215 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5216 dest_conv += sizeof(DWORD);
5221 if (DestFVF & D3DFVF_SPECULAR) {
5222 /* What's the color value in the feedback buffer? */
5223 DWORD *color_s =
5224 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5225 if(!color_s) {
5226 static BOOL warned = FALSE;
5228 if(warned == FALSE) {
5229 ERR("No specular color in source, but destination has one\n");
5230 warned = TRUE;
5233 *( (DWORD *) dest_ptr) = 0xFF000000;
5234 dest_ptr += sizeof(DWORD);
5236 if(dest_conv) {
5237 *( (DWORD *) dest_conv) = 0xFF000000;
5238 dest_conv += sizeof(DWORD);
5241 else {
5242 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5243 if(dest_conv) {
5244 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5245 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5246 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5247 dest_conv += sizeof(DWORD);
5252 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5253 float *tex_coord =
5254 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5255 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5256 if(!tex_coord) {
5257 ERR("No source texture, but destination requests one\n");
5258 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5259 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5261 else {
5262 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5263 if(dest_conv) {
5264 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5270 if(dest_conv) {
5271 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5272 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5275 LEAVE_GL();
5277 return WINED3D_OK;
5279 #undef copy_and_next
5281 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5283 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5284 WineDirect3DVertexStridedData strided;
5285 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5287 /* We don't need the source vbo because this buffer is only used as
5288 * a source for ProcessVertices. Avoid wasting resources by converting the
5289 * buffer and loading the VBO
5291 if(SrcImpl->vbo) {
5292 TRACE("Releaseing the source vbo, it won't be needed\n");
5294 if(!SrcImpl->resource.allocatedMemory) {
5295 /* Rescue the data from the buffer */
5296 void *src;
5297 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5298 if(!SrcImpl->resource.allocatedMemory) {
5299 ERR("Out of memory\n");
5300 return E_OUTOFMEMORY;
5303 ENTER_GL();
5304 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5305 checkGLcall("glBindBufferARB");
5307 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5308 if(src) {
5309 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5312 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5313 checkGLcall("glUnmapBufferARB");
5314 } else {
5315 ENTER_GL();
5318 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5319 checkGLcall("glBindBufferARB");
5320 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5321 checkGLcall("glDeleteBuffersARB");
5322 LEAVE_GL();
5324 SrcImpl->vbo = 0;
5327 memset(&strided, 0, sizeof(strided));
5328 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5330 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5333 /*****
5334 * Apply / Get / Set Texture Stage States
5335 * TODO: Verify against dx9 definitions
5336 *****/
5338 /* 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 */
5339 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5341 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5342 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5344 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5346 /* Check that the stage is within limits */
5347 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5348 TRACE("Attempt to access invalid texture rejected\n");
5349 return;
5352 ENTER_GL();
5354 switch (Type) {
5355 case WINED3DTSS_ALPHAOP :
5356 case WINED3DTSS_COLOROP :
5357 /* nothing to do as moved to drawprim for now */
5358 break;
5359 case WINED3DTSS_ADDRESSW :
5360 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5361 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5362 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5364 } else {
5365 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5366 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5367 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5368 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5370 #endif
5371 case WINED3DTSS_TEXCOORDINDEX :
5373 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5375 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5376 one flag, you can still specify an index value, which the system uses to
5377 determine the texture wrapping mode.
5378 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5379 means use the vertex position (camera-space) as the input texture coordinates
5380 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5381 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5382 to the TEXCOORDINDEX value */
5385 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5387 switch (Value & 0xFFFF0000) {
5388 case D3DTSS_TCI_PASSTHRU:
5389 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5390 glDisable(GL_TEXTURE_GEN_S);
5391 glDisable(GL_TEXTURE_GEN_T);
5392 glDisable(GL_TEXTURE_GEN_R);
5393 glDisable(GL_TEXTURE_GEN_Q);
5394 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5395 break;
5397 case D3DTSS_TCI_CAMERASPACEPOSITION:
5398 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5399 as the input texture coordinates for this stage's texture transformation. This
5400 equates roughly to EYE_LINEAR */
5402 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5403 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5404 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5405 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5406 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5408 glMatrixMode(GL_MODELVIEW);
5409 glPushMatrix();
5410 glLoadIdentity();
5411 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5412 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5413 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5414 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5415 glPopMatrix();
5417 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5418 glEnable(GL_TEXTURE_GEN_S);
5419 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5420 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5421 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5422 glEnable(GL_TEXTURE_GEN_T);
5423 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5424 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5425 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5426 glEnable(GL_TEXTURE_GEN_R);
5427 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5428 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5429 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5431 break;
5433 case D3DTSS_TCI_CAMERASPACENORMAL:
5435 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5436 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5437 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5438 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5439 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5440 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5442 glMatrixMode(GL_MODELVIEW);
5443 glPushMatrix();
5444 glLoadIdentity();
5445 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5446 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5447 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5448 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5449 glPopMatrix();
5451 glEnable(GL_TEXTURE_GEN_S);
5452 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5453 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5454 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5455 glEnable(GL_TEXTURE_GEN_T);
5456 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5457 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5458 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5459 glEnable(GL_TEXTURE_GEN_R);
5460 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5461 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5462 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5465 break;
5467 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5469 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5470 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5471 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5472 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5473 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5474 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5476 glMatrixMode(GL_MODELVIEW);
5477 glPushMatrix();
5478 glLoadIdentity();
5479 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5480 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5481 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5482 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5483 glPopMatrix();
5485 glEnable(GL_TEXTURE_GEN_S);
5486 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5487 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5488 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5489 glEnable(GL_TEXTURE_GEN_T);
5490 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5491 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5492 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5493 glEnable(GL_TEXTURE_GEN_R);
5494 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5495 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5496 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5499 break;
5501 /* Unhandled types: */
5502 default:
5503 /* Todo: */
5504 /* ? disable GL_TEXTURE_GEN_n ? */
5505 glDisable(GL_TEXTURE_GEN_S);
5506 glDisable(GL_TEXTURE_GEN_T);
5507 glDisable(GL_TEXTURE_GEN_R);
5508 glDisable(GL_TEXTURE_GEN_Q);
5509 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5510 break;
5513 break;
5515 /* Unhandled */
5516 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5517 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);
5518 break;
5520 case WINED3DTSS_BUMPENVMAT00 :
5521 case WINED3DTSS_BUMPENVMAT01 :
5522 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5523 break;
5524 case WINED3DTSS_BUMPENVMAT10 :
5525 case WINED3DTSS_BUMPENVMAT11 :
5526 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5527 break;
5529 case WINED3DTSS_BUMPENVLSCALE :
5530 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5531 break;
5533 case WINED3DTSS_BUMPENVLOFFSET :
5534 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5535 break;
5537 case WINED3DTSS_RESULTARG :
5538 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5539 break;
5541 default:
5542 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5543 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5546 LEAVE_GL();
5548 return;
5551 /*****
5552 * Get / Set Texture Stage States
5553 * TODO: Verify against dx9 definitions
5554 *****/
5555 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5558 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5560 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5562 /* Reject invalid texture units */
5563 if (Stage >= GL_LIMITS(texture_stages)) {
5564 TRACE("Attempt to access invalid texture rejected\n");
5565 return WINED3DERR_INVALIDCALL;
5568 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5569 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5570 This->updateStateBlock->textureState[Stage][Type] = Value;
5572 return WINED3D_OK;
5575 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5578 *pValue = This->updateStateBlock->textureState[Stage][Type];
5579 return WINED3D_OK;
5582 /*****
5583 * Get / Set Texture
5584 *****/
5585 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5588 IWineD3DBaseTexture *oldTexture;
5590 oldTexture = This->updateStateBlock->textures[Stage];
5591 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5593 #if 0 /* TODO: check so vertex textures */
5594 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5595 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5596 return WINED3D_OK;
5598 #endif
5600 /* Reject invalid texture units */
5601 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5602 WARN("Attempt to access invalid texture rejected\n");
5603 return WINED3DERR_INVALIDCALL;
5606 if(pTexture != NULL) {
5607 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5609 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5610 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5611 return WINED3DERR_INVALIDCALL;
5615 oldTexture = This->updateStateBlock->textures[Stage];
5616 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5617 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5619 This->updateStateBlock->set.textures[Stage] = TRUE;
5620 This->updateStateBlock->changed.textures[Stage] = TRUE;
5621 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5622 This->updateStateBlock->textures[Stage] = pTexture;
5624 /* Handle recording of state blocks */
5625 if (This->isRecordingState) {
5626 TRACE("Recording... not performing anything\n");
5627 return WINED3D_OK;
5630 /** NOTE: MSDN says that setTexture increases the reference count,
5631 * and the the application nust set the texture back to null (or have a leaky application),
5632 * This means we should pass the refcount up to the parent
5633 *******************************/
5634 if (NULL != This->updateStateBlock->textures[Stage]) {
5635 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5638 if (NULL != oldTexture) {
5639 IWineD3DBaseTexture_Release(oldTexture);
5642 /* Reset color keying */
5643 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5644 BOOL enable_ckey = FALSE;
5646 if(pTexture) {
5647 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5648 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5651 if(enable_ckey) {
5652 glAlphaFunc(GL_NOTEQUAL, 0.0);
5653 checkGLcall("glAlphaFunc");
5657 return WINED3D_OK;
5660 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5664 /* Reject invalid texture units */
5665 if (Stage >= GL_LIMITS(sampler_stages)) {
5666 TRACE("Attempt to access invalid texture rejected\n");
5667 return WINED3DERR_INVALIDCALL;
5669 *ppTexture=This->updateStateBlock->textures[Stage];
5670 if (*ppTexture)
5671 IWineD3DBaseTexture_AddRef(*ppTexture);
5672 else
5673 return WINED3DERR_INVALIDCALL;
5674 return WINED3D_OK;
5677 /*****
5678 * Get Back Buffer
5679 *****/
5680 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5681 IWineD3DSurface **ppBackBuffer) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 IWineD3DSwapChain *swapChain;
5684 HRESULT hr;
5686 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5688 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5689 if (hr == WINED3D_OK) {
5690 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5691 IWineD3DSwapChain_Release(swapChain);
5692 } else {
5693 *ppBackBuffer = NULL;
5695 return hr;
5698 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5700 WARN("(%p) : stub, calling idirect3d for now\n", This);
5701 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 IWineD3DSwapChain *swapChain;
5707 HRESULT hr;
5709 if(iSwapChain > 0) {
5710 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5711 if (hr == WINED3D_OK) {
5712 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5713 IWineD3DSwapChain_Release(swapChain);
5714 } else {
5715 FIXME("(%p) Error getting display mode\n", This);
5717 } else {
5718 /* Don't read the real display mode,
5719 but return the stored mode instead. X11 can't change the color
5720 depth, and some apps are pretty angry if they SetDisplayMode from
5721 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5723 Also don't relay to the swapchain because with ddraw it's possible
5724 that there isn't a swapchain at all */
5725 pMode->Width = This->ddraw_width;
5726 pMode->Height = This->ddraw_height;
5727 pMode->Format = This->ddraw_format;
5728 pMode->RefreshRate = 0;
5729 hr = WINED3D_OK;
5732 return hr;
5735 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 TRACE("(%p)->(%p)\n", This, hWnd);
5739 This->ddraw_window = hWnd;
5740 return WINED3D_OK;
5743 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 TRACE("(%p)->(%p)\n", This, hWnd);
5747 *hWnd = This->ddraw_window;
5748 return WINED3D_OK;
5751 /*****
5752 * Stateblock related functions
5753 *****/
5755 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 IWineD3DStateBlockImpl *object;
5758 HRESULT temp_result;
5760 TRACE("(%p)", This);
5762 if (This->isRecordingState) {
5763 return WINED3DERR_INVALIDCALL;
5766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5767 if (NULL == object ) {
5768 FIXME("(%p)Error allocating memory for stateblock\n", This);
5769 return E_OUTOFMEMORY;
5771 TRACE("(%p) created object %p\n", This, object);
5772 object->wineD3DDevice= This;
5773 /** FIXME: object->parent = parent; **/
5774 object->parent = NULL;
5775 object->blockType = WINED3DSBT_ALL;
5776 object->ref = 1;
5777 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5779 temp_result = allocate_shader_constants(object);
5780 if (WINED3D_OK != temp_result)
5781 return temp_result;
5783 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5784 This->updateStateBlock = object;
5785 This->isRecordingState = TRUE;
5787 TRACE("(%p) recording stateblock %p\n",This , object);
5788 return WINED3D_OK;
5791 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 if (!This->isRecordingState) {
5795 FIXME("(%p) not recording! returning error\n", This);
5796 *ppStateBlock = NULL;
5797 return WINED3DERR_INVALIDCALL;
5800 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5801 This->isRecordingState = FALSE;
5802 This->updateStateBlock = This->stateBlock;
5803 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5804 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5805 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5806 return WINED3D_OK;
5809 /*****
5810 * Scene related functions
5811 *****/
5812 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5813 /* At the moment we have no need for any functionality at the beginning
5814 of a scene */
5815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5816 TRACE("(%p) : stub\n", This);
5817 return WINED3D_OK;
5820 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 TRACE("(%p)\n", This);
5823 ENTER_GL();
5824 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5825 glFlush();
5826 checkGLcall("glFlush");
5828 TRACE("End Scene\n");
5829 if(This->renderTarget != NULL) {
5831 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5832 IUnknown *targetContainer = NULL;
5833 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5834 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5835 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5836 /** always dirtify for now. we must find a better way to see that surface have been modified
5837 (Modifications should will only occur via draw-primitive, but we do need better locking
5838 switching to render-to-texture should remove the overhead though.
5840 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5841 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5842 IWineD3DSurface_PreLoad(This->renderTarget);
5843 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5844 IUnknown_Release(targetContainer);
5847 This->sceneEnded = TRUE;
5848 LEAVE_GL();
5849 return WINED3D_OK;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5853 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5854 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5856 IWineD3DSwapChain *swapChain = NULL;
5857 int i;
5858 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5860 TRACE("(%p) Presenting the frame\n", This);
5862 for(i = 0 ; i < swapchains ; i ++) {
5864 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5865 TRACE("presentinng chain %d, %p\n", i, swapChain);
5866 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5867 IWineD3DSwapChain_Release(swapChain);
5870 return WINED3D_OK;
5873 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5874 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5877 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5878 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5879 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5880 GLbitfield glMask = 0;
5881 GLboolean old_ztest;
5882 GLfloat old_z_clear_value;
5883 GLint old_stencil_clear_value;
5884 GLfloat old_color_clear_value[4];
5885 unsigned int i;
5886 CONST D3DRECT* curRect;
5888 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5889 Count, pRects, Flags, Z, Stencil);
5891 ENTER_GL();
5893 glEnable(GL_SCISSOR_TEST);
5894 checkGLcall("glEnable GL_SCISSOR_TEST");
5896 if (Count > 0 && pRects) {
5897 curRect = pRects;
5898 } else {
5899 curRect = NULL;
5902 /* Only set the values up once, as they are not changing */
5903 if (Flags & D3DCLEAR_STENCIL) {
5904 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5905 glClearStencil(Stencil);
5906 checkGLcall("glClearStencil");
5907 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5908 glStencilMask(0xFFFFFFFF);
5911 if (Flags & D3DCLEAR_ZBUFFER) {
5912 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5913 glDepthMask(GL_TRUE);
5914 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5915 glClearDepth(Z);
5916 checkGLcall("glClearDepth");
5917 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5920 if (Flags & D3DCLEAR_TARGET) {
5921 TRACE("Clearing screen with glClear to color %lx\n", Color);
5922 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5923 glClearColor(D3DCOLOR_R(Color),
5924 D3DCOLOR_G(Color),
5925 D3DCOLOR_B(Color),
5926 D3DCOLOR_A(Color));
5927 checkGLcall("glClearColor");
5929 /* Clear ALL colors! */
5930 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5931 glMask = glMask | GL_COLOR_BUFFER_BIT;
5934 /* Now process each rect in turn */
5935 for (i = 0; i < Count || i == 0; i++) {
5937 if (curRect) {
5938 /* Note gl uses lower left, width/height */
5939 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5940 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5941 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5942 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5943 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5944 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5945 checkGLcall("glScissor");
5946 } else {
5947 glScissor(This->stateBlock->viewport.X,
5948 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5949 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5950 This->stateBlock->viewport.Width,
5951 This->stateBlock->viewport.Height);
5952 checkGLcall("glScissor");
5955 /* Clear the selected rectangle (or full screen) */
5956 glClear(glMask);
5957 checkGLcall("glClear");
5959 /* Step to the next rectangle */
5960 if (curRect) curRect = curRect + sizeof(D3DRECT);
5963 /* Restore the old values (why..?) */
5964 if (Flags & D3DCLEAR_STENCIL) {
5965 glClearStencil(old_stencil_clear_value);
5966 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5968 if (Flags & D3DCLEAR_ZBUFFER) {
5969 glDepthMask(old_ztest);
5970 glClearDepth(old_z_clear_value);
5972 if (Flags & D3DCLEAR_TARGET) {
5973 glClearColor(old_color_clear_value[0],
5974 old_color_clear_value[1],
5975 old_color_clear_value[2],
5976 old_color_clear_value[3]);
5977 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5978 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5979 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5980 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5983 glDisable(GL_SCISSOR_TEST);
5984 checkGLcall("glDisable");
5985 LEAVE_GL();
5987 return WINED3D_OK;
5990 /*****
5991 * Drawing functions
5992 *****/
5993 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5994 UINT PrimitiveCount) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 This->stateBlock->streamIsUP = FALSE;
5999 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6000 debug_d3dprimitivetype(PrimitiveType),
6001 StartVertex, PrimitiveCount);
6002 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6003 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6006 return WINED3D_OK;
6009 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6010 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6011 D3DPRIMITIVETYPE PrimitiveType,
6012 INT baseVIndex, UINT minIndex,
6013 UINT NumVertices, UINT startIndex, UINT primCount) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 UINT idxStride = 2;
6017 IWineD3DIndexBuffer *pIB;
6018 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6020 pIB = This->stateBlock->pIndexData;
6021 This->stateBlock->streamIsUP = FALSE;
6023 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6024 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6025 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6027 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6028 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6029 idxStride = 2;
6030 } else {
6031 idxStride = 4;
6034 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6035 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6037 return WINED3D_OK;
6040 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6041 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6042 UINT VertexStreamZeroStride) {
6043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6045 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6046 debug_d3dprimitivetype(PrimitiveType),
6047 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6049 /* release the stream source */
6050 if (This->stateBlock->streamSource[0] != NULL) {
6051 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6054 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6055 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6056 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6057 This->stateBlock->streamIsUP = TRUE;
6059 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6060 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6062 /* MSDN specifies stream zero settings must be set to NULL */
6063 This->stateBlock->streamStride[0] = 0;
6064 This->stateBlock->streamSource[0] = NULL;
6066 /*stream zero settings set to null at end, as per the msdn */
6067 return WINED3D_OK;
6070 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6071 UINT MinVertexIndex, UINT NumVertices,
6072 UINT PrimitiveCount, CONST void* pIndexData,
6073 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6074 UINT VertexStreamZeroStride) {
6075 int idxStride;
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6078 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6079 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6080 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6081 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6083 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6084 idxStride = 2;
6085 } else {
6086 idxStride = 4;
6089 /* release the stream and index data */
6090 if (This->stateBlock->streamSource[0] != NULL) {
6091 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6093 if (This->stateBlock->pIndexData) {
6094 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6097 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6098 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6099 This->stateBlock->streamIsUP = TRUE;
6100 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6102 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6104 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6105 This->stateBlock->streamSource[0] = NULL;
6106 This->stateBlock->streamStride[0] = 0;
6107 This->stateBlock->pIndexData = NULL;
6109 return WINED3D_OK;
6112 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6114 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6115 return WINED3D_OK;
6117 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6118 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 HRESULT hr = WINED3D_OK;
6121 WINED3DRESOURCETYPE sourceType;
6122 WINED3DRESOURCETYPE destinationType;
6123 int i ,levels;
6125 /* TODO: think about moving the code into IWineD3DBaseTexture */
6127 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6129 /* verify that the source and destination textures aren't NULL */
6130 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6131 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6132 This, pSourceTexture, pDestinationTexture);
6133 hr = WINED3DERR_INVALIDCALL;
6136 if (pSourceTexture == pDestinationTexture) {
6137 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6138 This, pSourceTexture, pDestinationTexture);
6139 hr = WINED3DERR_INVALIDCALL;
6141 /* Verify that the source and destination textures are the same type */
6142 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6143 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6145 if (sourceType != destinationType) {
6146 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6147 This);
6148 hr = WINED3DERR_INVALIDCALL;
6151 /* check that both textures have the identical numbers of levels */
6152 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6153 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6154 hr = WINED3DERR_INVALIDCALL;
6157 if (WINED3D_OK == hr) {
6159 /* Make sure that the destination texture is loaded */
6160 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6162 /* Update every surface level of the texture */
6163 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6165 switch (sourceType) {
6166 case WINED3DRTYPE_TEXTURE:
6168 IWineD3DSurface *srcSurface;
6169 IWineD3DSurface *destSurface;
6171 for (i = 0 ; i < levels ; ++i) {
6172 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6173 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6174 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6175 IWineD3DSurface_Release(srcSurface);
6176 IWineD3DSurface_Release(destSurface);
6177 if (WINED3D_OK != hr) {
6178 WARN("(%p) : Call to update surface failed\n", This);
6179 return hr;
6183 break;
6184 case WINED3DRTYPE_CUBETEXTURE:
6186 IWineD3DSurface *srcSurface;
6187 IWineD3DSurface *destSurface;
6188 WINED3DCUBEMAP_FACES faceType;
6190 for (i = 0 ; i < levels ; ++i) {
6191 /* Update each cube face */
6192 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6193 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6194 if (WINED3D_OK != hr) {
6195 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6196 } else {
6197 TRACE("Got srcSurface %p\n", srcSurface);
6199 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6200 if (WINED3D_OK != hr) {
6201 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6202 } else {
6203 TRACE("Got desrSurface %p\n", destSurface);
6205 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6206 IWineD3DSurface_Release(srcSurface);
6207 IWineD3DSurface_Release(destSurface);
6208 if (WINED3D_OK != hr) {
6209 WARN("(%p) : Call to update surface failed\n", This);
6210 return hr;
6215 break;
6216 #if 0 /* TODO: Add support for volume textures */
6217 case WINED3DRTYPE_VOLUMETEXTURE:
6219 IWineD3DVolume srcVolume = NULL;
6220 IWineD3DSurface destVolume = NULL;
6222 for (i = 0 ; i < levels ; ++i) {
6223 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6224 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6225 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6226 IWineD3DVolume_Release(srcSurface);
6227 IWineD3DVolume_Release(destSurface);
6228 if (WINED3D_OK != hr) {
6229 WARN("(%p) : Call to update volume failed\n", This);
6230 return hr;
6234 break;
6235 #endif
6236 default:
6237 FIXME("(%p) : Unsupported source and destination type\n", This);
6238 hr = WINED3DERR_INVALIDCALL;
6242 return hr;
6245 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6246 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6247 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6250 TRACE("(%p) : stub\n", This);
6251 return WINED3D_OK;
6253 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6255 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6256 * NOTE It may be best to move the code into surface to occomplish this
6257 ****************************************/
6259 WINED3DSURFACE_DESC surfaceDesc;
6260 unsigned int surfaceWidth, surfaceHeight;
6261 glDescriptor *targetGlDescription = NULL;
6262 glDescriptor *surfaceGlDescription = NULL;
6263 IWineD3DSwapChainImpl *container = NULL;
6265 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6266 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6267 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6269 surfaceDesc.Width = &surfaceWidth;
6270 surfaceDesc.Height = &surfaceHeight;
6271 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6272 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6274 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6275 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6276 ENTER_GL();
6277 /* TODO: opengl Context switching for swapchains etc... */
6278 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6279 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6280 glReadBuffer(GL_BACK);
6281 vcheckGLcall("glReadBuffer(GL_BACK)");
6282 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6283 glReadBuffer(GL_FRONT);
6284 vcheckGLcall("glReadBuffer(GL_FRONT)");
6285 } else if (pRenderTarget == This->depthStencilBuffer) {
6286 FIXME("Reading of depthstencil not yet supported\n");
6289 glReadPixels(surfaceGlDescription->target,
6290 surfaceGlDescription->level,
6291 surfaceWidth,
6292 surfaceHeight,
6293 surfaceGlDescription->glFormat,
6294 surfaceGlDescription->glType,
6295 (void *)IWineD3DSurface_GetData(pSurface));
6296 vcheckGLcall("glReadPixels(...)");
6297 if(NULL != container ){
6298 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6300 } else {
6301 IWineD3DBaseTexture *container;
6302 GLenum textureDimensions = GL_TEXTURE_2D;
6304 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6305 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6306 IWineD3DBaseTexture_Release(container);
6308 /* TODO: 2D -> Cube surface coppies etc.. */
6309 if (surfaceGlDescription->target != textureDimensions) {
6310 FIXME("(%p) : Texture dimension mismatch\n", This);
6312 glEnable(textureDimensions);
6313 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6314 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6315 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6316 vcheckGLcall("glBindTexture");
6317 glGetTexImage(surfaceGlDescription->target,
6318 surfaceGlDescription->level,
6319 surfaceGlDescription->glFormat,
6320 surfaceGlDescription->glType,
6321 (void *)IWineD3DSurface_GetData(pSurface));
6322 glDisable(textureDimensions);
6323 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6326 LEAVE_GL();
6327 return WINED3D_OK;
6330 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6331 IWineD3DSwapChain *swapChain;
6332 HRESULT hr;
6333 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6334 if(hr == WINED3D_OK) {
6335 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6336 IWineD3DSwapChain_Release(swapChain);
6338 return hr;
6341 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6343 /* return a sensible default */
6344 *pNumPasses = 1;
6345 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6346 FIXME("(%p) : stub\n", This);
6347 return WINED3D_OK;
6350 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6352 int j;
6353 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6354 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6355 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6356 return WINED3DERR_INVALIDCALL;
6358 for (j = 0; j < 256; ++j) {
6359 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6360 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6361 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6362 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6364 TRACE("(%p) : returning\n", This);
6365 return WINED3D_OK;
6368 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6370 int j;
6371 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6372 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6373 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6374 return WINED3DERR_INVALIDCALL;
6376 for (j = 0; j < 256; ++j) {
6377 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6378 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6379 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6380 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6382 TRACE("(%p) : returning\n", This);
6383 return WINED3D_OK;
6386 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6388 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6389 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6390 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6391 return WINED3DERR_INVALIDCALL;
6393 /*TODO: stateblocks */
6394 This->currentPalette = PaletteNumber;
6395 TRACE("(%p) : returning\n", This);
6396 return WINED3D_OK;
6399 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 if (PaletteNumber == NULL) {
6402 WARN("(%p) : returning Invalid Call\n", This);
6403 return WINED3DERR_INVALIDCALL;
6405 /*TODO: stateblocks */
6406 *PaletteNumber = This->currentPalette;
6407 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6408 return WINED3D_OK;
6411 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6413 static BOOL showFixmes = TRUE;
6414 if (showFixmes) {
6415 FIXME("(%p) : stub\n", This);
6416 showFixmes = FALSE;
6419 This->softwareVertexProcessing = bSoftware;
6420 return WINED3D_OK;
6424 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6426 static BOOL showFixmes = TRUE;
6427 if (showFixmes) {
6428 FIXME("(%p) : stub\n", This);
6429 showFixmes = FALSE;
6431 return This->softwareVertexProcessing;
6435 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 IWineD3DSwapChain *swapChain;
6438 HRESULT hr;
6440 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6442 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6443 if(hr == WINED3D_OK){
6444 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6445 IWineD3DSwapChain_Release(swapChain);
6446 }else{
6447 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6449 return hr;
6453 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6455 static BOOL showfixmes = TRUE;
6456 if(nSegments != 0.0f) {
6457 if( showfixmes) {
6458 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6459 showfixmes = FALSE;
6462 return WINED3D_OK;
6465 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6467 static BOOL showfixmes = TRUE;
6468 if( showfixmes) {
6469 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6470 showfixmes = FALSE;
6472 return 0.0f;
6475 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6477 /** TODO: remove casts to IWineD3DSurfaceImpl
6478 * NOTE: move code to surface to accomplish this
6479 ****************************************/
6480 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6481 int srcWidth, srcHeight;
6482 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6483 WINED3DFORMAT destFormat, srcFormat;
6484 UINT destSize;
6485 int destLeft, destTop;
6486 WINED3DPOOL srcPool, destPool;
6487 int offset = 0;
6488 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6489 glDescriptor *glDescription = NULL;
6490 GLenum textureDimensions = GL_TEXTURE_2D;
6491 IWineD3DBaseTexture *baseTexture;
6493 WINED3DSURFACE_DESC winedesc;
6495 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6496 memset(&winedesc, 0, sizeof(winedesc));
6497 winedesc.Width = &srcSurfaceWidth;
6498 winedesc.Height = &srcSurfaceHeight;
6499 winedesc.Pool = &srcPool;
6500 winedesc.Format = &srcFormat;
6502 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6504 winedesc.Width = &destSurfaceWidth;
6505 winedesc.Height = &destSurfaceHeight;
6506 winedesc.Pool = &destPool;
6507 winedesc.Format = &destFormat;
6508 winedesc.Size = &destSize;
6510 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6512 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6513 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6514 return WINED3DERR_INVALIDCALL;
6517 if (destFormat == WINED3DFMT_UNKNOWN) {
6518 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6519 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6521 /* Get the update surface description */
6522 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6525 /* Make sure the surface is loaded and up to date */
6526 IWineD3DSurface_PreLoad(pDestinationSurface);
6528 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6530 ENTER_GL();
6532 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6533 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6534 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6535 destLeft = pDestPoint ? pDestPoint->x : 0;
6536 destTop = pDestPoint ? pDestPoint->y : 0;
6539 /* This function doesn't support compressed textures
6540 the pitch is just bytesPerPixel * width */
6541 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6542 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6543 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6544 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6546 /* TODO DXT formats */
6548 if(pSourceRect != NULL && pSourceRect->top != 0){
6549 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6551 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6552 ,This
6553 ,glDescription->level
6554 ,destLeft
6555 ,destTop
6556 ,srcWidth
6557 ,srcHeight
6558 ,glDescription->glFormat
6559 ,glDescription->glType
6560 ,IWineD3DSurface_GetData(pSourceSurface)
6563 /* Sanity check */
6564 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6566 /* need to lock the surface to get the data */
6567 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6570 /* TODO: Cube and volume support */
6571 if(rowoffset != 0){
6572 /* not a whole row so we have to do it a line at a time */
6573 int j;
6575 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6576 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6578 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6580 glTexSubImage2D(glDescription->target
6581 ,glDescription->level
6582 ,destLeft
6584 ,srcWidth
6586 ,glDescription->glFormat
6587 ,glDescription->glType
6588 ,data /* could be quicker using */
6590 data += rowoffset;
6593 } else { /* Full width, so just write out the whole texture */
6595 if (WINED3DFMT_DXT1 == destFormat ||
6596 WINED3DFMT_DXT2 == destFormat ||
6597 WINED3DFMT_DXT3 == destFormat ||
6598 WINED3DFMT_DXT4 == destFormat ||
6599 WINED3DFMT_DXT5 == destFormat) {
6600 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6601 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6602 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6603 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6604 } if (destFormat != srcFormat) {
6605 FIXME("Updating mixed format compressed texture is not curretly support\n");
6606 } else {
6607 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6608 glDescription->level,
6609 glDescription->glFormatInternal,
6610 srcWidth,
6611 srcHeight,
6613 destSize,
6614 IWineD3DSurface_GetData(pSourceSurface));
6616 } else {
6617 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6621 } else {
6622 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6624 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6625 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6626 data returned by GetData non-power2 width/height with hardware non-power2
6627 pow2Width/height are set to surface width height, repacking isn't needed so it
6628 doesn't matter which function gets called. */
6629 glTexSubImage2D(glDescription->target
6630 ,glDescription->level
6631 ,destLeft
6632 ,destTop
6633 ,srcWidth
6634 ,srcHeight
6635 ,glDescription->glFormat
6636 ,glDescription->glType
6637 ,IWineD3DSurface_GetData(pSourceSurface)
6639 } else {
6641 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6642 glTexSubImage2D(glDescription->target
6643 ,glDescription->level
6644 ,destLeft
6645 ,destTop
6646 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6647 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6648 ,glDescription->glFormat
6649 ,glDescription->glType
6650 ,IWineD3DSurface_GetData(pSourceSurface)
6656 checkGLcall("glTexSubImage2D");
6658 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6659 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6660 * surface bigger than it needs to be hmm.. */
6661 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6662 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6663 IWineD3DBaseTexture_Release(baseTexture);
6666 glDisable(textureDimensions); /* This needs to be managed better.... */
6667 LEAVE_GL();
6669 return WINED3D_OK;
6672 /* Used by DirectX 8 */
6673 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6674 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6675 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6678 HRESULT hr = WINED3D_OK;
6679 WINED3DFORMAT srcFormat, destFormat;
6680 UINT srcWidth, destWidth;
6681 UINT srcHeight, destHeight;
6682 UINT srcSize;
6683 WINED3DSURFACE_DESC winedesc;
6685 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6686 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6689 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6690 memset(&winedesc, 0, sizeof(winedesc));
6692 winedesc.Format = &srcFormat;
6693 winedesc.Width = &srcWidth;
6694 winedesc.Height = &srcHeight;
6695 winedesc.Size = &srcSize;
6696 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6698 winedesc.Format = &destFormat;
6699 winedesc.Width = &destWidth;
6700 winedesc.Height = &destHeight;
6701 winedesc.Size = NULL;
6702 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6704 /* Check that the source and destination formats match */
6705 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6706 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6707 return WINED3DERR_INVALIDCALL;
6708 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6709 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6710 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6711 destFormat = srcFormat;
6714 /* Quick if complete copy ... */
6715 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6717 if (srcWidth == destWidth && srcHeight == destHeight) {
6718 WINED3DLOCKED_RECT lrSrc;
6719 WINED3DLOCKED_RECT lrDst;
6720 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6721 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6722 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6724 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6726 IWineD3DSurface_UnlockRect(pSourceSurface);
6727 IWineD3DSurface_UnlockRect(pDestinationSurface);
6728 TRACE("Unlocked src and dst\n");
6730 } else {
6732 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6733 hr = WINED3DERR_INVALIDCALL;
6736 } else {
6738 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6740 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6741 unsigned int i;
6743 /* Copy rect by rect */
6744 for (i = 0; i < cRects; ++i) {
6745 CONST RECT* r = &pSourceRectsArray[i];
6746 CONST POINT* p = &pDestPointsArray[i];
6747 int copyperline;
6748 int j;
6749 WINED3DLOCKED_RECT lrSrc;
6750 WINED3DLOCKED_RECT lrDst;
6751 RECT dest_rect;
6753 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6754 if (srcFormat == WINED3DFMT_DXT1) {
6755 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6756 } else {
6757 copyperline = ((r->right - r->left) * bytesPerPixel);
6760 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6761 dest_rect.left = p->x;
6762 dest_rect.top = p->y;
6763 dest_rect.right = p->x + (r->right - r->left);
6764 dest_rect.bottom= p->y + (r->bottom - r->top);
6765 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6766 TRACE("Locked src and dst\n");
6768 /* Find where to start */
6769 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6770 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6772 IWineD3DSurface_UnlockRect(pSourceSurface);
6773 IWineD3DSurface_UnlockRect(pDestinationSurface);
6774 TRACE("Unlocked src and dst\n");
6776 } else {
6777 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6778 hr = WINED3DERR_INVALIDCALL;
6782 return hr;
6785 /* Implementation details at http://developer.nvidia.com/attach/6494
6787 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6788 hmm.. no longer supported use
6789 OpenGL evaluators or tessellate surfaces within your application.
6792 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6793 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6795 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6796 FIXME("(%p) : Stub\n", This);
6797 return WINED3D_OK;
6801 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6802 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6804 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6805 FIXME("(%p) : Stub\n", This);
6806 return WINED3D_OK;
6809 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6811 TRACE("(%p) Handle(%d)\n", This, Handle);
6812 FIXME("(%p) : Stub\n", This);
6813 return WINED3D_OK;
6816 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6817 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6818 fill a surface with a block of color! */
6819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6820 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6821 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6822 IWineD3DSwapChainImpl *container = NULL;
6823 BOOL isRenderTarget = FALSE;
6824 unsigned int width, height;
6825 unsigned int top, left;
6826 unsigned int u, v;
6827 DWORD *data;
6828 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6830 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6831 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6832 return WINED3DERR_INVALIDCALL;
6835 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6836 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6837 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6838 /* TODO: make sure we set everything back to the way it was, and context management!
6839 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6840 vcheckGLcall("glIntegerv");
6841 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6842 vcheckGLcall("glIntegerv");
6844 TRACE("Color fill to render targets may cause some graphics issues\n");
6845 if (pSurface == container->frontBuffer) {
6846 glDrawBuffer(GL_FRONT);
6847 } else {
6848 glDrawBuffer(GL_BACK);
6850 } else {
6851 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6852 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6853 } else {
6854 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6856 if (container != NULL) {
6857 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6859 /* we can use GL_STENCIL_INDEX etc...*/
6860 return WINED3D_OK;
6862 if (container != NULL) {
6863 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6865 isRenderTarget = TRUE;
6867 /* TODO: drawing to GL_FRONT and GL_BACK */
6868 /* TODO: see if things can be speeded up by using the correct
6869 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6870 if (pRect == NULL) {
6871 top = 0;
6872 left = 0;
6873 width = surface->currentDesc.Width;
6874 height = surface->currentDesc.Height;
6875 } else {
6876 left = pRect->x1;
6877 top = pRect->y1;
6878 width = pRect->x2 - left;
6879 height = pRect->y2 - top;
6882 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6883 /* Create a 'line' of color color, in the correct format for the surface */
6884 for (u = 0 ; u < width ; u ++) {
6885 data[u] = color;
6888 ENTER_GL();
6889 if (isRenderTarget == FALSE) {
6890 glDescriptor *glDesc;
6891 IWineD3DSurface_PreLoad(pSurface);
6893 /* draw a block of the coloured line on the sufrace */
6894 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6895 for (v = 0 ; v< height;v++) {
6896 glTexSubImage2D(glDesc->target
6897 ,glDesc->level /* level */
6898 ,left
6899 ,top + v
6900 ,width
6901 ,1 /* height */
6902 ,GL_RGBA
6903 ,GL_UNSIGNED_BYTE
6904 ,data
6907 checkGLcall("glTexSubImage2D");
6908 /* clean up */
6909 glDisable(glDesc->target);
6910 } else {
6911 /** FIXME: Using GLClear may be faster **/
6912 glRasterPos2i(left, top);
6913 glPixelZoom((float)width ,(float)height);
6914 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6915 checkGLcall("glDrawPixels");
6917 HeapFree(GetProcessHeap(), 0, data);
6918 LEAVE_GL();
6919 return WINED3D_OK;
6923 /* rendertarget and deptth stencil functions */
6924 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6927 /* FIXME: Implelent RenderTargetIndex >0 */
6928 if(RenderTargetIndex > 0)
6929 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6931 *ppRenderTarget = This->renderTarget;
6932 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6933 /* Note inc ref on returned surface */
6934 if(*ppRenderTarget != NULL)
6935 IWineD3DSurface_AddRef(*ppRenderTarget);
6936 return WINED3D_OK;
6939 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6941 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6942 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6943 IWineD3DSwapChainImpl *Swapchain;
6944 HRESULT hr;
6946 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6948 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6949 if(hr != WINED3D_OK) {
6950 ERR("Can't get the swapchain\n");
6951 return hr;
6954 /* Make sure to release the swapchain */
6955 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6957 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6958 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6959 return WINED3DERR_INVALIDCALL;
6961 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6962 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6963 return WINED3DERR_INVALIDCALL;
6966 if(Swapchain->frontBuffer != Front) {
6967 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6969 if(Swapchain->frontBuffer)
6970 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6971 Swapchain->frontBuffer = Front;
6973 if(Swapchain->frontBuffer) {
6974 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6978 if(Back && !Swapchain->backBuffer) {
6979 /* We need memory for the back buffer array - only one back buffer this way */
6980 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6981 if(!Swapchain->backBuffer) {
6982 ERR("Out of memory\n");
6983 return E_OUTOFMEMORY;
6987 if(Swapchain->backBuffer[0] != Back) {
6988 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6989 ENTER_GL();
6990 if(!Swapchain->backBuffer[0]) {
6991 /* GL was told to draw to the front buffer at creation,
6992 * undo that
6994 glDrawBuffer(GL_BACK);
6995 checkGLcall("glDrawBuffer(GL_BACK)");
6996 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6997 Swapchain->presentParms.BackBufferCount = 1;
6998 } else if (!Back) {
6999 /* That makes problems - disable for now */
7000 /* glDrawBuffer(GL_FRONT); */
7001 checkGLcall("glDrawBuffer(GL_FRONT)");
7002 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7003 Swapchain->presentParms.BackBufferCount = 0;
7005 LEAVE_GL();
7007 if(Swapchain->backBuffer[0])
7008 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7009 Swapchain->backBuffer[0] = Back;
7011 if(Swapchain->backBuffer[0]) {
7012 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7013 } else {
7014 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7019 return WINED3D_OK;
7022 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7024 *ppZStencilSurface = This->depthStencilBuffer;
7025 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7027 if(*ppZStencilSurface != NULL) {
7028 /* Note inc ref on returned surface */
7029 IWineD3DSurface_AddRef(*ppZStencilSurface);
7031 return WINED3D_OK;
7034 /* internal static helper functions */
7035 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7036 IWineD3DSurface *RenderSurface);
7038 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7040 HRESULT hr = WINED3D_OK;
7041 WINED3DVIEWPORT viewport;
7043 TRACE("(%p) Swapping rendertarget\n",This);
7044 if (RenderTargetIndex > 0) {
7045 FIXME("(%p) Render targets other than the first are not supported\n",This);
7046 RenderTargetIndex = 0;
7049 /* MSDN says that null disables the render target
7050 but a device must always be associated with a render target
7051 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7053 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7054 for more details
7056 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7057 FIXME("Trying to set render target 0 to NULL\n");
7058 return WINED3DERR_INVALIDCALL;
7060 /* TODO: replace Impl* usage with interface usage */
7061 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7062 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);
7063 return WINED3DERR_INVALIDCALL;
7065 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7066 * builds, but I think wine counts as a 'debug' build for now.
7067 ******************************/
7068 /* If we are trying to set what we already have, don't bother */
7069 if (pRenderTarget == This->renderTarget) {
7070 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7071 } else {
7072 /* Otherwise, set the render target up */
7074 if (FALSE == This->sceneEnded) {
7075 IWineD3DDevice_EndScene(iface);
7077 TRACE("clearing renderer\n");
7078 /* IWineD3DDeviceImpl_CleanRender(iface); */
7079 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7080 depending on the renter target implementation being used.
7081 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7082 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7083 stencil buffer and incure an extra memory overhead */
7084 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7087 if (SUCCEEDED(hr)) {
7088 /* Finally, reset the viewport as the MSDN states. */
7089 /* TODO: Replace impl usage */
7090 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7091 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7092 viewport.X = 0;
7093 viewport.Y = 0;
7094 viewport.MaxZ = 1.0f;
7095 viewport.MinZ = 0.0f;
7096 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7097 } else {
7098 FIXME("Unknown error setting the render target\n");
7100 This->sceneEnded = FALSE;
7101 return hr;
7104 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7106 HRESULT hr = WINED3D_OK;
7107 IWineD3DSurface *tmp;
7109 TRACE("(%p) Swapping z-buffer\n",This);
7111 if (pNewZStencil == This->stencilBufferTarget) {
7112 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7113 } else {
7114 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7115 * depending on the renter target implementation being used.
7116 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7117 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7118 * stencil buffer and incure an extra memory overhead
7119 ******************************************************/
7122 tmp = This->stencilBufferTarget;
7123 This->stencilBufferTarget = pNewZStencil;
7124 /* should we be calling the parent or the wined3d surface? */
7125 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7126 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7127 hr = WINED3D_OK;
7128 /** TODO: glEnable/glDisable on depth/stencil depending on
7129 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7130 **********************************************************/
7133 return hr;
7137 #ifdef GL_VERSION_1_3
7138 /* Internal functions not in DirectX */
7139 /** TODO: move this off to the opengl context manager
7140 *(the swapchain doesn't need to know anything about offscreen rendering!)
7141 ****************************************************/
7143 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7147 TRACE("(%p), %p\n", This, swapchain);
7149 if (swapchain->win != swapchain->drawable) {
7150 /* Set everything back the way it ws */
7151 swapchain->render_ctx = swapchain->glCtx;
7152 swapchain->drawable = swapchain->win;
7154 return WINED3D_OK;
7157 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7158 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7160 int i;
7161 unsigned int width;
7162 unsigned int height;
7163 WINED3DFORMAT format;
7164 WINED3DSURFACE_DESC surfaceDesc;
7165 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7166 surfaceDesc.Width = &width;
7167 surfaceDesc.Height = &height;
7168 surfaceDesc.Format = &format;
7169 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7170 *context = NULL;
7171 /* I need a get width/height function (and should do something with the format) */
7172 for (i = 0; i < CONTEXT_CACHE; ++i) {
7173 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7174 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7175 the pSurface can be set to 0 allowing it to be reused from cache **/
7176 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7177 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7178 *context = &This->contextCache[i];
7179 break;
7181 if (This->contextCache[i].Width == 0) {
7182 This->contextCache[i].pSurface = pSurface;
7183 This->contextCache[i].Width = width;
7184 This->contextCache[i].Height = height;
7185 *context = &This->contextCache[i];
7186 break;
7189 if (i == CONTEXT_CACHE) {
7190 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7191 glContext *dropContext = 0;
7192 for (i = 0; i < CONTEXT_CACHE; i++) {
7193 if (This->contextCache[i].usedcount < minUsage) {
7194 dropContext = &This->contextCache[i];
7195 minUsage = This->contextCache[i].usedcount;
7198 /* clean up the context (this doesn't work for ATI at the moment */
7199 #if 0
7200 glXDestroyContext(swapchain->display, dropContext->context);
7201 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7202 #endif
7203 FIXME("Leak\n");
7204 dropContext->Width = 0;
7205 dropContext->pSurface = pSurface;
7206 *context = dropContext;
7207 } else {
7208 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7209 for (i = 0; i < CONTEXT_CACHE; i++) {
7210 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7214 if (*context != NULL)
7215 return WINED3D_OK;
7216 else
7217 return E_OUTOFMEMORY;
7219 #endif
7221 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7222 * the functionality needs splitting up so that we don't do more than we should do.
7223 * this only seems to impact performance a little.
7224 ******************************/
7225 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7226 IWineD3DSurface *RenderSurface) {
7227 HRESULT ret = WINED3DERR_INVALIDCALL;
7228 BOOL oldRecording;
7229 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7232 * Currently only active for GLX >= 1.3
7233 * for others versions we'll have to use GLXPixmaps
7235 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7236 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7237 * so only check OpenGL version
7238 * ..........................
7239 * I don't believe that it is a problem with NVidia headers,
7240 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7241 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7242 * ATI Note:
7243 * Your application will report GLX version 1.2 on glXQueryVersion.
7244 * However, it is safe to call the GLX 1.3 functions as described below.
7246 #if defined(GL_VERSION_1_3)
7248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7249 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7250 IWineD3DSurface *tmp;
7251 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7252 GLXFBConfig* cfgs = NULL;
7253 int nCfgs = 0;
7254 int attribs[256];
7255 int nAttribs = 0;
7256 IWineD3DSwapChain *currentSwapchain;
7257 IWineD3DSwapChainImpl *swapchain;
7258 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7259 * but switch them off if the StencilSurface is set to NULL
7260 ** *********************************************************/
7261 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7262 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7264 /**TODO:
7265 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7266 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7269 #define PUSH1(att) attribs[nAttribs++] = (att);
7270 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7272 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7274 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7275 IWineD3DSwapChainImpl *impSwapChain;
7276 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7277 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7278 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7281 ENTER_GL();
7283 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7284 PUSH2(GLX_X_RENDERABLE, TRUE);
7285 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7286 TRACE("calling makeglcfg\n");
7287 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7288 PUSH1(None);
7290 TRACE("calling chooseFGConfig\n");
7291 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7292 attribs, &nCfgs);
7294 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7295 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7296 why we failed and only show this message once! */
7297 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"); /**/
7298 nAttribs = 0;
7299 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7300 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7301 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7302 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7303 TRACE("calling makeglcfg\n");
7304 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7305 PUSH1(None);
7306 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7307 attribs, &nCfgs);
7310 if (NULL != cfgs) {
7311 #ifdef EXTRA_TRACES
7312 int i;
7313 for (i = 0; i < nCfgs; ++i) {
7314 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7315 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7316 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7319 if (NULL != This->renderTarget) {
7320 glFlush();
7321 vcheckGLcall("glFlush");
7322 /** This is only useful if the old render target was a swapchain,
7323 * we need to supercede this with a function that displays
7324 * the current buffer on the screen. This is easy to do in glx1.3 but
7325 * we need to do copy-write pixels in glx 1.2.
7326 ************************************************/
7327 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7329 printf("Hit Enter to get next frame ...\n");
7330 getchar();
7332 #endif
7335 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7336 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7337 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7341 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7342 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7343 **********************************************************************/
7344 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7345 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7346 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7347 TRACE("making swapchain active\n");
7348 if (RenderSurface != This->renderTarget) {
7349 BOOL backbuf = FALSE;
7350 int i;
7352 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7353 if(RenderSurface == swapchain->backBuffer[i]) {
7354 backbuf = TRUE;
7355 break;
7359 if (backbuf) {
7360 } else {
7361 /* This could be flagged so that some operations work directly with the front buffer */
7362 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7364 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7365 == False) {
7366 TRACE("Error in setting current context: context %p drawable %ld !\n",
7367 impSwapChain->glCtx, impSwapChain->win);
7370 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7372 checkGLcall("glXMakeContextCurrent");
7374 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7376 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7378 /** ********************************************************************
7379 * This is a quickly hacked out implementation of offscreen textures.
7380 * It will work in most cases but there may be problems if the client
7381 * modifies the texture directly, or expects the contents of the rendertarget
7382 * to be persistent.
7384 * There are some real speed vs compatibility issues here:
7385 * we should really use a new context for every texture, but that eats ram.
7386 * we should also be restoring the texture to the pbuffer but that eats CPU
7387 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7388 * but if this means reusing the display backbuffer then we need to make sure that
7389 * states are correctly preserved.
7390 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7391 * and gain a good performance increase at the cost of compatibility.
7392 * I would suggest that, when this is the case, a user configurable flag be made
7393 * available, allowing the user to choose the best emulated experience for them.
7394 *********************************************************************/
7396 XVisualInfo *visinfo;
7397 glContext *newContext;
7399 /* Here were using a shared context model */
7400 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7401 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7404 /* If the context doesn't exist then create a new one */
7405 /* TODO: This should really be part of findGlContext */
7406 if (NULL == newContext->context) {
7408 TRACE("making new buffer\n");
7409 nAttribs = 0;
7410 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7411 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7412 PUSH1(None);
7414 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7416 /** ****************************************
7417 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7418 *they note:
7419 * In future releases, we may provide the calls glXCreateNewContext,
7420 * glXQueryDrawable and glXMakeContextCurrent.
7421 * so until then we have to use glXGetVisualFromFBConfig &co..
7422 ********************************************/
7425 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7426 if (!visinfo) {
7427 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7428 } else {
7429 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7430 XFree(visinfo);
7433 if (NULL == newContext || NULL == newContext->context) {
7434 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7435 } else {
7436 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7437 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7438 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7441 /* Clean up the old context */
7442 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7443 /* Set the current context of the swapchain to the new context */
7444 impSwapChain->drawable = newContext->drawable;
7445 impSwapChain->render_ctx = newContext->context;
7449 /* Disable recording, and apply the stateblock to the new context
7450 * FIXME: This is a bit of a hack, each context should know it's own state,
7451 * the directX current directX state should then be applied to the context */
7452 oldUpdateStateBlock = This->updateStateBlock;
7453 oldRecording= This->isRecordingState;
7454 This->isRecordingState = FALSE;
7455 This->updateStateBlock = This->stateBlock;
7456 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7458 /* clean up the current rendertargets swapchain (if it belonged to one) */
7459 if (currentSwapchain != NULL) {
7460 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7463 /* Were done with the opengl context management, setup the rendertargets */
7465 tmp = This->renderTarget;
7466 This->renderTarget = RenderSurface;
7467 IWineD3DSurface_AddRef(This->renderTarget);
7468 IWineD3DSurface_Release(tmp);
7471 DWORD value;
7473 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7474 /* Check that the container is not a swapchain member */
7476 IWineD3DSwapChain *tmpSwapChain;
7477 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7478 This->renderUpsideDown = TRUE;
7479 }else{
7480 This->renderUpsideDown = FALSE;
7481 IWineD3DSwapChain_Release(tmpSwapChain);
7483 /* Force updating the cull mode */
7484 TRACE("setting render state\n");
7485 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7486 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7488 /* Force updating projection matrix */
7489 This->last_was_rhw = FALSE;
7490 This->proj_valid = FALSE;
7493 /* Restore recording state */
7494 This->isRecordingState = oldRecording;
7495 This->updateStateBlock = oldUpdateStateBlock;
7497 ret = WINED3D_OK;
7499 if (cfgs != NULL) {
7500 XFree(cfgs);
7501 } else {
7502 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7503 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7506 #undef PUSH1
7507 #undef PUSH2
7508 if ( NULL != impSwapChain) {
7509 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7511 LEAVE_GL();
7513 #endif
7514 return ret;
7517 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7518 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7520 /* TODO: the use of Impl is deprecated. */
7521 /* some basic validation checks */
7522 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7524 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7526 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7527 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7528 return WINED3DERR_INVALIDCALL;
7530 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7531 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7532 return WINED3DERR_INVALIDCALL;
7534 /* TODO: make the cursor 'real' */
7536 This->xHotSpot = XHotSpot;
7537 This->yHotSpot = YHotSpot;
7539 return WINED3D_OK;
7542 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7544 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7546 This->xScreenSpace = XScreenSpace;
7547 This->yScreenSpace = YScreenSpace;
7549 return;
7553 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7555 TRACE("(%p) : visible(%d)\n", This, bShow);
7557 This->bCursorVisible = bShow;
7559 return WINED3D_OK;
7562 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7564 TRACE("(%p) : state (%lu)\n", This, This->state);
7565 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7566 switch (This->state) {
7567 case WINED3D_OK:
7568 return WINED3D_OK;
7569 case WINED3DERR_DEVICELOST:
7571 ResourceList *resourceList = This->resources;
7572 while (NULL != resourceList) {
7573 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7574 return WINED3DERR_DEVICENOTRESET;
7575 resourceList = resourceList->next;
7577 return WINED3DERR_DEVICELOST;
7579 case WINED3DERR_DRIVERINTERNALERROR:
7580 return WINED3DERR_DRIVERINTERNALERROR;
7583 /* Unknown state */
7584 return WINED3DERR_DRIVERINTERNALERROR;
7588 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7590 /** FIXME: Resource tracking needs to be done,
7591 * The closes we can do to this is set the priorities of all managed textures low
7592 * and then reset them.
7593 ***********************************************************/
7594 FIXME("(%p) : stub\n", This);
7595 return WINED3D_OK;
7598 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7600 /** FIXME: Resource trascking needs to be done.
7601 * in effect this pulls all non only default
7602 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7603 * and should clear down the context and set it up according to pPresentationParameters
7604 ***********************************************************/
7605 FIXME("(%p) : stub\n", This);
7606 return WINED3D_OK;
7609 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7611 /** FIXME: always true at the moment **/
7612 if(bEnableDialogs == FALSE) {
7613 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7615 return WINED3D_OK;
7619 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7621 TRACE("(%p) : pParameters %p\n", This, pParameters);
7623 *pParameters = This->createParms;
7624 return WINED3D_OK;
7627 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7628 IWineD3DSwapChain *swapchain;
7629 HRESULT hrc = WINED3D_OK;
7631 TRACE("Relaying to swapchain\n");
7633 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7634 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7635 IWineD3DSwapChain_Release(swapchain);
7637 return;
7640 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7641 IWineD3DSwapChain *swapchain;
7642 HRESULT hrc = WINED3D_OK;
7644 TRACE("Relaying to swapchain\n");
7646 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7647 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7648 IWineD3DSwapChain_Release(swapchain);
7650 return;
7654 /** ********************************************************
7655 * Notification functions
7656 ** ********************************************************/
7657 /** This function must be called in the release of a resource when ref == 0,
7658 * the contents of resource must still be correct,
7659 * any handels to other resource held by the caller must be closed
7660 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7661 *****************************************************/
7662 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7664 ResourceList* resourceList;
7666 TRACE("(%p) : resource %p\n", This, resource);
7667 #if 0
7668 EnterCriticalSection(&resourceStoreCriticalSection);
7669 #endif
7670 /* add a new texture to the frot of the linked list */
7671 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7672 resourceList->resource = resource;
7674 /* Get the old head */
7675 resourceList->next = This->resources;
7677 This->resources = resourceList;
7678 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7680 #if 0
7681 LeaveCriticalSection(&resourceStoreCriticalSection);
7682 #endif
7683 return;
7686 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7688 ResourceList* resourceList = NULL;
7689 ResourceList* previousResourceList = NULL;
7691 TRACE("(%p) : resource %p\n", This, resource);
7693 #if 0
7694 EnterCriticalSection(&resourceStoreCriticalSection);
7695 #endif
7696 resourceList = This->resources;
7698 while (resourceList != NULL) {
7699 if(resourceList->resource == resource) break;
7700 previousResourceList = resourceList;
7701 resourceList = resourceList->next;
7704 if (resourceList == NULL) {
7705 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7706 #if 0
7707 LeaveCriticalSection(&resourceStoreCriticalSection);
7708 #endif
7709 return;
7710 } else {
7711 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7713 /* make sure we don't leave a hole in the list */
7714 if (previousResourceList != NULL) {
7715 previousResourceList->next = resourceList->next;
7716 } else {
7717 This->resources = resourceList->next;
7720 #if 0
7721 LeaveCriticalSection(&resourceStoreCriticalSection);
7722 #endif
7723 return;
7727 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7729 int counter;
7731 TRACE("(%p) : resource %p\n", This, resource);
7732 switch(IWineD3DResource_GetType(resource)){
7733 case WINED3DRTYPE_SURFACE:
7734 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7735 break;
7736 case WINED3DRTYPE_TEXTURE:
7737 case WINED3DRTYPE_CUBETEXTURE:
7738 case WINED3DRTYPE_VOLUMETEXTURE:
7739 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7740 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7741 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7742 This->stateBlock->textures[counter] = NULL;
7744 if (This->updateStateBlock != This->stateBlock ){
7745 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7746 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7747 This->updateStateBlock->textures[counter] = NULL;
7751 break;
7752 case WINED3DRTYPE_VOLUME:
7753 /* TODO: nothing really? */
7754 break;
7755 case WINED3DRTYPE_VERTEXBUFFER:
7756 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7758 int streamNumber;
7759 TRACE("Cleaning up stream pointers\n");
7761 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7762 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7763 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7765 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7766 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7767 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7768 This->updateStateBlock->streamSource[streamNumber] = 0;
7769 /* Set changed flag? */
7772 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) */
7773 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7774 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7775 This->stateBlock->streamSource[streamNumber] = 0;
7778 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7779 else { /* This shouldn't happen */
7780 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7782 #endif
7786 break;
7787 case WINED3DRTYPE_INDEXBUFFER:
7788 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7789 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7790 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7791 This->updateStateBlock->pIndexData = NULL;
7794 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7795 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7796 This->stateBlock->pIndexData = NULL;
7800 break;
7801 default:
7802 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7803 break;
7807 /* Remove the resoruce from the resourceStore */
7808 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7810 TRACE("Resource released\n");
7814 /**********************************************************
7815 * IWineD3DDevice VTbl follows
7816 **********************************************************/
7818 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7820 /*** IUnknown methods ***/
7821 IWineD3DDeviceImpl_QueryInterface,
7822 IWineD3DDeviceImpl_AddRef,
7823 IWineD3DDeviceImpl_Release,
7824 /*** IWineD3DDevice methods ***/
7825 IWineD3DDeviceImpl_GetParent,
7826 /*** Creation methods**/
7827 IWineD3DDeviceImpl_CreateVertexBuffer,
7828 IWineD3DDeviceImpl_CreateIndexBuffer,
7829 IWineD3DDeviceImpl_CreateStateBlock,
7830 IWineD3DDeviceImpl_CreateSurface,
7831 IWineD3DDeviceImpl_CreateTexture,
7832 IWineD3DDeviceImpl_CreateVolumeTexture,
7833 IWineD3DDeviceImpl_CreateVolume,
7834 IWineD3DDeviceImpl_CreateCubeTexture,
7835 IWineD3DDeviceImpl_CreateQuery,
7836 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7837 IWineD3DDeviceImpl_CreateVertexDeclaration,
7838 IWineD3DDeviceImpl_CreateVertexShader,
7839 IWineD3DDeviceImpl_CreatePixelShader,
7840 IWineD3DDeviceImpl_CreatePalette,
7841 /*** Odd functions **/
7842 IWineD3DDeviceImpl_Init3D,
7843 IWineD3DDeviceImpl_Uninit3D,
7844 IWineD3DDeviceImpl_EnumDisplayModes,
7845 IWineD3DDeviceImpl_EvictManagedResources,
7846 IWineD3DDeviceImpl_GetAvailableTextureMem,
7847 IWineD3DDeviceImpl_GetBackBuffer,
7848 IWineD3DDeviceImpl_GetCreationParameters,
7849 IWineD3DDeviceImpl_GetDeviceCaps,
7850 IWineD3DDeviceImpl_GetDirect3D,
7851 IWineD3DDeviceImpl_GetDisplayMode,
7852 IWineD3DDeviceImpl_SetDisplayMode,
7853 IWineD3DDeviceImpl_GetHWND,
7854 IWineD3DDeviceImpl_SetHWND,
7855 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7856 IWineD3DDeviceImpl_GetRasterStatus,
7857 IWineD3DDeviceImpl_GetSwapChain,
7858 IWineD3DDeviceImpl_Reset,
7859 IWineD3DDeviceImpl_SetDialogBoxMode,
7860 IWineD3DDeviceImpl_SetCursorProperties,
7861 IWineD3DDeviceImpl_SetCursorPosition,
7862 IWineD3DDeviceImpl_ShowCursor,
7863 IWineD3DDeviceImpl_TestCooperativeLevel,
7864 /*** Getters and setters **/
7865 IWineD3DDeviceImpl_SetClipPlane,
7866 IWineD3DDeviceImpl_GetClipPlane,
7867 IWineD3DDeviceImpl_SetClipStatus,
7868 IWineD3DDeviceImpl_GetClipStatus,
7869 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7870 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7871 IWineD3DDeviceImpl_SetDepthStencilSurface,
7872 IWineD3DDeviceImpl_GetDepthStencilSurface,
7873 IWineD3DDeviceImpl_SetFVF,
7874 IWineD3DDeviceImpl_GetFVF,
7875 IWineD3DDeviceImpl_SetGammaRamp,
7876 IWineD3DDeviceImpl_GetGammaRamp,
7877 IWineD3DDeviceImpl_SetIndices,
7878 IWineD3DDeviceImpl_GetIndices,
7879 IWineD3DDeviceImpl_SetLight,
7880 IWineD3DDeviceImpl_GetLight,
7881 IWineD3DDeviceImpl_SetLightEnable,
7882 IWineD3DDeviceImpl_GetLightEnable,
7883 IWineD3DDeviceImpl_SetMaterial,
7884 IWineD3DDeviceImpl_GetMaterial,
7885 IWineD3DDeviceImpl_SetNPatchMode,
7886 IWineD3DDeviceImpl_GetNPatchMode,
7887 IWineD3DDeviceImpl_SetPaletteEntries,
7888 IWineD3DDeviceImpl_GetPaletteEntries,
7889 IWineD3DDeviceImpl_SetPixelShader,
7890 IWineD3DDeviceImpl_GetPixelShader,
7891 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7892 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7893 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7894 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7895 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7896 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7897 IWineD3DDeviceImpl_SetRenderState,
7898 IWineD3DDeviceImpl_GetRenderState,
7899 IWineD3DDeviceImpl_SetRenderTarget,
7900 IWineD3DDeviceImpl_GetRenderTarget,
7901 IWineD3DDeviceImpl_SetFrontBackBuffers,
7902 IWineD3DDeviceImpl_SetSamplerState,
7903 IWineD3DDeviceImpl_GetSamplerState,
7904 IWineD3DDeviceImpl_SetScissorRect,
7905 IWineD3DDeviceImpl_GetScissorRect,
7906 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7907 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7908 IWineD3DDeviceImpl_SetStreamSource,
7909 IWineD3DDeviceImpl_GetStreamSource,
7910 IWineD3DDeviceImpl_SetStreamSourceFreq,
7911 IWineD3DDeviceImpl_GetStreamSourceFreq,
7912 IWineD3DDeviceImpl_SetTexture,
7913 IWineD3DDeviceImpl_GetTexture,
7914 IWineD3DDeviceImpl_SetTextureStageState,
7915 IWineD3DDeviceImpl_GetTextureStageState,
7916 IWineD3DDeviceImpl_SetTransform,
7917 IWineD3DDeviceImpl_GetTransform,
7918 IWineD3DDeviceImpl_SetVertexDeclaration,
7919 IWineD3DDeviceImpl_GetVertexDeclaration,
7920 IWineD3DDeviceImpl_SetVertexShader,
7921 IWineD3DDeviceImpl_GetVertexShader,
7922 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7923 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7924 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7925 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7926 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7927 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7928 IWineD3DDeviceImpl_SetViewport,
7929 IWineD3DDeviceImpl_GetViewport,
7930 IWineD3DDeviceImpl_MultiplyTransform,
7931 IWineD3DDeviceImpl_ValidateDevice,
7932 IWineD3DDeviceImpl_ProcessVertices,
7933 /*** State block ***/
7934 IWineD3DDeviceImpl_BeginStateBlock,
7935 IWineD3DDeviceImpl_EndStateBlock,
7936 /*** Scene management ***/
7937 IWineD3DDeviceImpl_BeginScene,
7938 IWineD3DDeviceImpl_EndScene,
7939 IWineD3DDeviceImpl_Present,
7940 IWineD3DDeviceImpl_Clear,
7941 /*** Drawing ***/
7942 IWineD3DDeviceImpl_DrawPrimitive,
7943 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7944 IWineD3DDeviceImpl_DrawPrimitiveUP,
7945 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7946 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7947 IWineD3DDeviceImpl_DrawRectPatch,
7948 IWineD3DDeviceImpl_DrawTriPatch,
7949 IWineD3DDeviceImpl_DeletePatch,
7950 IWineD3DDeviceImpl_ColorFill,
7951 IWineD3DDeviceImpl_UpdateTexture,
7952 IWineD3DDeviceImpl_UpdateSurface,
7953 IWineD3DDeviceImpl_CopyRects,
7954 IWineD3DDeviceImpl_StretchRect,
7955 IWineD3DDeviceImpl_GetRenderTargetData,
7956 IWineD3DDeviceImpl_GetFrontBufferData,
7957 /*** Internal use IWineD3DDevice methods ***/
7958 IWineD3DDeviceImpl_SetupTextureStates,
7959 /*** object tracking ***/
7960 IWineD3DDeviceImpl_ResourceReleased
7964 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7965 WINED3DRS_ALPHABLENDENABLE ,
7966 WINED3DRS_ALPHAFUNC ,
7967 WINED3DRS_ALPHAREF ,
7968 WINED3DRS_ALPHATESTENABLE ,
7969 WINED3DRS_BLENDOP ,
7970 WINED3DRS_COLORWRITEENABLE ,
7971 WINED3DRS_DESTBLEND ,
7972 WINED3DRS_DITHERENABLE ,
7973 WINED3DRS_FILLMODE ,
7974 WINED3DRS_FOGDENSITY ,
7975 WINED3DRS_FOGEND ,
7976 WINED3DRS_FOGSTART ,
7977 WINED3DRS_LASTPIXEL ,
7978 WINED3DRS_SHADEMODE ,
7979 WINED3DRS_SRCBLEND ,
7980 WINED3DRS_STENCILENABLE ,
7981 WINED3DRS_STENCILFAIL ,
7982 WINED3DRS_STENCILFUNC ,
7983 WINED3DRS_STENCILMASK ,
7984 WINED3DRS_STENCILPASS ,
7985 WINED3DRS_STENCILREF ,
7986 WINED3DRS_STENCILWRITEMASK ,
7987 WINED3DRS_STENCILZFAIL ,
7988 WINED3DRS_TEXTUREFACTOR ,
7989 WINED3DRS_WRAP0 ,
7990 WINED3DRS_WRAP1 ,
7991 WINED3DRS_WRAP2 ,
7992 WINED3DRS_WRAP3 ,
7993 WINED3DRS_WRAP4 ,
7994 WINED3DRS_WRAP5 ,
7995 WINED3DRS_WRAP6 ,
7996 WINED3DRS_WRAP7 ,
7997 WINED3DRS_ZENABLE ,
7998 WINED3DRS_ZFUNC ,
7999 WINED3DRS_ZWRITEENABLE
8002 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8003 WINED3DTSS_ADDRESSW ,
8004 WINED3DTSS_ALPHAARG0 ,
8005 WINED3DTSS_ALPHAARG1 ,
8006 WINED3DTSS_ALPHAARG2 ,
8007 WINED3DTSS_ALPHAOP ,
8008 WINED3DTSS_BUMPENVLOFFSET ,
8009 WINED3DTSS_BUMPENVLSCALE ,
8010 WINED3DTSS_BUMPENVMAT00 ,
8011 WINED3DTSS_BUMPENVMAT01 ,
8012 WINED3DTSS_BUMPENVMAT10 ,
8013 WINED3DTSS_BUMPENVMAT11 ,
8014 WINED3DTSS_COLORARG0 ,
8015 WINED3DTSS_COLORARG1 ,
8016 WINED3DTSS_COLORARG2 ,
8017 WINED3DTSS_COLOROP ,
8018 WINED3DTSS_RESULTARG ,
8019 WINED3DTSS_TEXCOORDINDEX ,
8020 WINED3DTSS_TEXTURETRANSFORMFLAGS
8023 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8024 WINED3DSAMP_ADDRESSU ,
8025 WINED3DSAMP_ADDRESSV ,
8026 WINED3DSAMP_ADDRESSW ,
8027 WINED3DSAMP_BORDERCOLOR ,
8028 WINED3DSAMP_MAGFILTER ,
8029 WINED3DSAMP_MINFILTER ,
8030 WINED3DSAMP_MIPFILTER ,
8031 WINED3DSAMP_MIPMAPLODBIAS ,
8032 WINED3DSAMP_MAXMIPLEVEL ,
8033 WINED3DSAMP_MAXANISOTROPY ,
8034 WINED3DSAMP_SRGBTEXTURE ,
8035 WINED3DSAMP_ELEMENTINDEX
8038 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8039 WINED3DRS_AMBIENT ,
8040 WINED3DRS_AMBIENTMATERIALSOURCE ,
8041 WINED3DRS_CLIPPING ,
8042 WINED3DRS_CLIPPLANEENABLE ,
8043 WINED3DRS_COLORVERTEX ,
8044 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8045 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8046 WINED3DRS_FOGDENSITY ,
8047 WINED3DRS_FOGEND ,
8048 WINED3DRS_FOGSTART ,
8049 WINED3DRS_FOGTABLEMODE ,
8050 WINED3DRS_FOGVERTEXMODE ,
8051 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8052 WINED3DRS_LIGHTING ,
8053 WINED3DRS_LOCALVIEWER ,
8054 WINED3DRS_MULTISAMPLEANTIALIAS ,
8055 WINED3DRS_MULTISAMPLEMASK ,
8056 WINED3DRS_NORMALIZENORMALS ,
8057 WINED3DRS_PATCHEDGESTYLE ,
8058 WINED3DRS_POINTSCALE_A ,
8059 WINED3DRS_POINTSCALE_B ,
8060 WINED3DRS_POINTSCALE_C ,
8061 WINED3DRS_POINTSCALEENABLE ,
8062 WINED3DRS_POINTSIZE ,
8063 WINED3DRS_POINTSIZE_MAX ,
8064 WINED3DRS_POINTSIZE_MIN ,
8065 WINED3DRS_POINTSPRITEENABLE ,
8066 WINED3DRS_RANGEFOGENABLE ,
8067 WINED3DRS_SPECULARMATERIALSOURCE ,
8068 WINED3DRS_TWEENFACTOR ,
8069 WINED3DRS_VERTEXBLEND
8072 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8073 WINED3DTSS_TEXCOORDINDEX ,
8074 WINED3DTSS_TEXTURETRANSFORMFLAGS
8077 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8078 WINED3DSAMP_DMAPOFFSET