wined3d: Correct check for GL ext. support in MULTISAMPLEANTIALIAS.
[wine/hacks.git] / dlls / wined3d / device.c
blob10d85463667a9140d7100a1a2527cb411d27f2fd
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 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
74 /* enable pbuffer support for offscreen textures */
75 BOOL pbuffer_support = FALSE;
76 /* allocate one pbuffer per surface */
77 BOOL pbuffer_per_surface = FALSE;
79 /* static function declarations */
80 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
82 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
84 /* helper macros */
85 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
87 #define D3DCREATEOBJECTINSTANCE(object, type) { \
88 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
89 D3DMEMCHECK(object, pp##type); \
90 object->lpVtbl = &IWineD3D##type##_Vtbl; \
91 object->wineD3DDevice = This; \
92 object->parent = parent; \
93 object->ref = 1; \
94 *pp##type = (IWineD3D##type *) object; \
97 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
98 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
99 D3DMEMCHECK(object, pp##type); \
100 object->lpVtbl = &IWineD3D##type##_Vtbl; \
101 object->resource.wineD3DDevice = This; \
102 object->resource.parent = parent; \
103 object->resource.resourceType = d3dtype; \
104 object->resource.ref = 1; \
105 object->resource.pool = Pool; \
106 object->resource.format = Format; \
107 object->resource.usage = Usage; \
108 object->resource.size = _size; \
109 /* Check that we have enough video ram left */ \
110 if (Pool == WINED3DPOOL_DEFAULT) { \
111 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
112 WARN("Out of 'bogus' video memory\n"); \
113 HeapFree(GetProcessHeap(), 0, object); \
114 *pp##type = NULL; \
115 return WINED3DERR_OUTOFVIDEOMEMORY; \
117 globalChangeGlRam(_size); \
119 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
120 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
121 FIXME("Out of memory!\n"); \
122 HeapFree(GetProcessHeap(), 0, object); \
123 *pp##type = NULL; \
124 return WINED3DERR_OUTOFVIDEOMEMORY; \
126 *pp##type = (IWineD3D##type *) object; \
127 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
128 TRACE("(%p) : Created resource %p\n", This, object); \
131 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
132 _basetexture.levels = Levels; \
133 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
134 _basetexture.LOD = 0; \
135 _basetexture.dirty = TRUE; \
138 /**********************************************************
139 * Global variable / Constants follow
140 **********************************************************/
141 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
143 /**********************************************************
144 * Utility functions follow
145 **********************************************************/
146 /* Convert the D3DLIGHT properties into equivalent gl lights */
147 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
149 float quad_att;
150 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
154 glMatrixMode(GL_MODELVIEW);
155 glPushMatrix();
156 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
158 /* Diffuse: */
159 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
160 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
161 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
162 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
163 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
164 checkGLcall("glLightfv");
166 /* Specular */
167 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
168 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
169 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
170 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
171 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
172 checkGLcall("glLightfv");
174 /* Ambient */
175 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
176 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
177 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
178 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
179 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
180 checkGLcall("glLightfv");
182 /* Attenuation - Are these right? guessing... */
183 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
184 checkGLcall("glLightf");
185 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
186 checkGLcall("glLightf");
188 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
189 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
190 } else {
191 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
194 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
195 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
196 checkGLcall("glLightf");
198 switch (lightInfo->OriginalParms.Type) {
199 case D3DLIGHT_POINT:
200 /* Position */
201 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
202 checkGLcall("glLightfv");
203 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
204 checkGLcall("glLightf");
205 /* FIXME: Range */
206 break;
208 case D3DLIGHT_SPOT:
209 /* Position */
210 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
211 checkGLcall("glLightfv");
212 /* Direction */
213 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
214 checkGLcall("glLightfv");
215 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
216 checkGLcall("glLightf");
217 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
218 checkGLcall("glLightf");
219 /* FIXME: Range */
220 break;
222 case D3DLIGHT_DIRECTIONAL:
223 /* Direction */
224 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
225 checkGLcall("glLightfv");
226 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
227 checkGLcall("glLightf");
228 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
229 checkGLcall("glLightf");
230 break;
232 default:
233 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
236 /* Restore the modelview matrix */
237 glPopMatrix();
240 /**********************************************************
241 * GLSL helper functions follow
242 **********************************************************/
244 /** Attach a GLSL pixel or vertex shader object to the shader program */
245 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
248 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
249 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
250 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
251 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
252 checkGLcall("glAttachObjectARB");
256 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
257 * It sets the programId on the current StateBlock (because it should be called
258 * inside of the DrawPrimitive() part of the render loop).
260 * If a program for the given combination does not exist, create one, and store
261 * the program in the list. If it creates a program, it will link the given
262 * objects, too.
264 * We keep the shader programs around on a list because linking
265 * shader objects together is an expensive operation. It's much
266 * faster to loop through a list of pre-compiled & linked programs
267 * each time that the application sets a new pixel or vertex shader
268 * than it is to re-link them together at that time.
270 * The list will be deleted in IWineD3DDevice::Release().
272 void set_glsl_shader_program(IWineD3DDevice *iface) {
274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
275 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
276 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
277 struct glsl_shader_prog_link *curLink = NULL;
278 struct glsl_shader_prog_link *newLink = NULL;
279 struct list *ptr = NULL;
280 GLhandleARB programId = 0;
282 ptr = list_head( &This->glsl_shader_progs );
283 while (ptr) {
284 /* At least one program exists - see if it matches our ps/vs combination */
285 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
286 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
287 /* Existing Program found, use it */
288 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
289 curLink->programId);
290 This->stateBlock->shaderPrgId = curLink->programId;
291 return;
293 /* This isn't the entry we need - try the next one */
294 ptr = list_next( &This->glsl_shader_progs, ptr );
297 /* If we get to this point, then no matching program exists, so we create one */
298 programId = GL_EXTCALL(glCreateProgramObjectARB());
299 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
300 This->stateBlock->shaderPrgId = programId;
302 /* Allocate a new link for the list of programs */
303 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
304 newLink->programId = programId;
306 /* Attach GLSL vshader */
307 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
308 int i;
309 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
310 char tmp_name[10];
312 TRACE("Attaching vertex shader to GLSL program\n");
313 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
315 /* Bind vertex attributes to a corresponding index number to match
316 * the same index numbers as ARB_vertex_programs (makes loading
317 * vertex attributes simpler). With this method, we can use the
318 * exact same code to load the attributes later for both ARB and
319 * GLSL shaders.
321 * We have to do this here because we need to know the Program ID
322 * in order to make the bindings work, and it has to be done prior
323 * to linking the GLSL program. */
324 for (i = 0; i < max_attribs; ++i) {
325 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
326 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
328 checkGLcall("glBindAttribLocationARB");
329 newLink->vertexShader = vshader;
332 /* Attach GLSL pshader */
333 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
334 TRACE("Attaching pixel shader to GLSL program\n");
335 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
336 newLink->pixelShader = pshader;
339 /* Link the program */
340 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
341 GL_EXTCALL(glLinkProgramARB(programId));
342 print_glsl_info_log(&GLINFO_LOCATION, programId);
343 list_add_head( &This->glsl_shader_progs, &newLink->entry);
344 return;
347 /** Detach the GLSL pixel or vertex shader object from the shader program */
348 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
352 if (shaderObj != 0 && programId != 0) {
353 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
354 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
355 checkGLcall("glDetachObjectARB");
359 /** Delete a GLSL shader program */
360 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
364 if (obj != 0) {
365 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
366 GL_EXTCALL(glDeleteObjectARB(obj));
367 checkGLcall("glDeleteObjectARB");
371 /** Delete the list of linked programs this shader is associated with.
372 * Also at this point, check to see if there are any objects left attached
373 * to each GLSL program. If not, delete the GLSL program object.
374 * This will be run when a device is released. */
375 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
377 struct list *ptr = NULL;
378 struct glsl_shader_prog_link *curLink = NULL;
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
381 int numAttached = 0;
382 int i;
383 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
384 (one pixel shader and one vertex shader at most) */
386 ptr = list_head( &This->glsl_shader_progs );
387 while (ptr) {
388 /* First, get the current item,
389 * save the link to the next pointer,
390 * detach and delete shader objects,
391 * then de-allocate the list item's memory */
392 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
393 ptr = list_next( &This->glsl_shader_progs, ptr );
395 /* See if this object is still attached to the program - it may have been detached already */
396 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
397 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
398 for (i = 0; i < numAttached; i++) {
399 detach_glsl_shader(iface, objList[i], curLink->programId);
402 delete_glsl_shader_program(iface, curLink->programId);
404 /* Free the memory for this list item */
405 HeapFree(GetProcessHeap(), 0, curLink);
410 /* Apply the current values to the specified texture stage */
411 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
413 float col[4];
415 union {
416 float f;
417 DWORD d;
418 } tmpvalue;
420 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
421 clamping, MIPLOD, etc. This will work for up to 16 samplers.
424 if (Sampler >= GL_LIMITS(sampler_stages)) {
425 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
426 return;
428 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
429 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
430 ENTER_GL();
431 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
432 checkGLcall("glActiveTextureARB");
433 LEAVE_GL();
434 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
435 } else if (Sampler > 0) {
436 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
437 return;
440 /* TODO: change this to a lookup table
441 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
442 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
443 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
444 especially when there are a number of groups of states. */
446 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
448 /* 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 */
449 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
450 /* these are the only two supported states that need to be applied */
451 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
452 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
453 #if 0 /* not supported at the moment */
454 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
455 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
456 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
457 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
458 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
459 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
460 APPLY_STATE(WINED3DTSS_RESULTARG);
461 APPLY_STATE(WINED3DTSS_CONSTANT);
462 #endif
463 /* a quick sanity check in case someone forgot to update this function */
464 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
465 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
467 #undef APPLY_STATE
469 /* apply any sampler states that always need applying */
470 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
471 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
472 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
473 GL_TEXTURE_LOD_BIAS_EXT,
474 tmpvalue.f);
475 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
478 /* Note the D3DRS value applies to all textures, but GL has one
479 * per texture, so apply it now ready to be used!
481 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
482 /* Set the default alpha blend color */
483 if (GL_SUPPORT(ARB_IMAGING)) {
484 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
485 checkGLcall("glBlendColor");
486 } else {
487 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
490 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
491 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
492 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
494 /* TODO: NV_POINT_SPRITE */
495 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
496 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
497 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
498 glDisable(GL_POINT_SMOOTH);
500 /* Centre the texture on the vertex */
501 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
502 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
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);
506 checkGLcall("glTexEnvf(...)");
507 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
508 glEnable( GL_POINT_SPRITE_ARB );
509 checkGLcall("glEnable(...)");
510 } else {
511 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
512 glDisable( GL_POINT_SPRITE_ARB );
513 checkGLcall("glEnable(...)");
517 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
520 /**********************************************************
521 * IUnknown parts follows
522 **********************************************************/
524 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
528 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
529 if (IsEqualGUID(riid, &IID_IUnknown)
530 || IsEqualGUID(riid, &IID_IWineD3DBase)
531 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
532 IUnknown_AddRef(iface);
533 *ppobj = This;
534 return S_OK;
536 *ppobj = NULL;
537 return E_NOINTERFACE;
540 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
542 ULONG refCount = InterlockedIncrement(&This->ref);
544 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
545 return refCount;
548 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
550 ULONG refCount = InterlockedDecrement(&This->ref);
552 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
554 if (!refCount) {
555 /* TODO: Clean up all the surfaces and textures! */
556 /* NOTE: You must release the parent if the object was created via a callback
557 ** ***************************/
559 /* Delete any GLSL shader programs that may exist */
560 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
561 wined3d_settings.ps_selected_mode == SHADER_GLSL)
562 delete_glsl_shader_list(iface);
564 /* Release the update stateblock */
565 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
566 if(This->updateStateBlock != This->stateBlock)
567 FIXME("(%p) Something's still holding the Update stateblock\n",This);
569 This->updateStateBlock = NULL;
570 { /* because were not doing proper internal refcounts releasing the primary state block
571 causes recursion with the extra checks in ResourceReleased, to avoid this we have
572 to set this->stateBlock = NULL; first */
573 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
574 This->stateBlock = NULL;
576 /* Release the stateblock */
577 if(IWineD3DStateBlock_Release(stateBlock) > 0){
578 FIXME("(%p) Something's still holding the Update stateblock\n",This);
582 if (This->resources != NULL ) {
583 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
584 dumpResources(This->resources);
588 IWineD3D_Release(This->wineD3D);
589 This->wineD3D = NULL;
590 HeapFree(GetProcessHeap(), 0, This);
591 TRACE("Freed device %p\n", This);
592 This = NULL;
594 return refCount;
597 /**********************************************************
598 * IWineD3DDevice implementation follows
599 **********************************************************/
600 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
602 *pParent = This->parent;
603 IUnknown_AddRef(This->parent);
604 return WINED3D_OK;
607 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
608 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
609 GLenum error, glUsage;
610 DWORD vboUsage = object->resource.usage;
611 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
612 WARN("Creating a vbo failed once, not trying again\n");
613 return;
616 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
618 ENTER_GL();
619 /* Make sure that the gl error is cleared. Do not use checkGLcall
620 * here because checkGLcall just prints a fixme and continues. However,
621 * if an error during VBO creation occurs we can fall back to non-vbo operation
622 * with full functionality(but performance loss)
624 while(glGetError() != GL_NO_ERROR);
626 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
627 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
628 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
629 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
630 * to check if the rhw and color values are in the correct format.
633 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
634 error = glGetError();
635 if(object->vbo == 0 || error != GL_NO_ERROR) {
636 WARN("Failed to create a VBO with error %d\n", error);
637 goto error;
640 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
641 error = glGetError();
642 if(error != GL_NO_ERROR) {
643 WARN("Failed to bind the VBO, error %d\n", error);
644 goto error;
647 /* Transformed vertices are horribly inflexible. If the app specifies an
648 * vertex buffer with transformed vertices in default pool without DYNAMIC
649 * usage assume DYNAMIC usage and print a warning. The app will have to update
650 * the vertices regularily for them to be useful
652 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
653 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
654 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
655 vboUsage |= WINED3DUSAGE_DYNAMIC;
658 /* Don't use static, because dx apps tend to update the buffer
659 * quite often even if they specify 0 usage
661 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
662 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
663 TRACE("Gl usage = GL_STREAM_DRAW\n");
664 glUsage = GL_STREAM_DRAW_ARB;
665 break;
666 case D3DUSAGE_WRITEONLY:
667 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
668 glUsage = GL_DYNAMIC_DRAW_ARB;
669 break;
670 case D3DUSAGE_DYNAMIC:
671 TRACE("Gl usage = GL_STREAM_COPY\n");
672 glUsage = GL_STREAM_COPY_ARB;
673 break;
674 default:
675 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
676 glUsage = GL_DYNAMIC_COPY_ARB;
677 break;
680 /* Reserve memory for the buffer. The amount of data won't change
681 * so we are safe with calling glBufferData once with a NULL ptr and
682 * calling glBufferSubData on updates
684 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
685 error = glGetError();
686 if(error != GL_NO_ERROR) {
687 WARN("glBufferDataARB failed with error %d\n", error);
688 goto error;
691 LEAVE_GL();
693 return;
694 error:
695 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
696 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
697 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
698 object->vbo = 0;
699 object->Flags |= VBFLAG_VBOCREATEFAIL;
700 LEAVE_GL();
701 return;
704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
705 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
706 IUnknown *parent) {
707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
708 IWineD3DVertexBufferImpl *object;
709 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
710 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
711 BOOL conv;
712 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
714 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
715 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
717 if(Size == 0) return WINED3DERR_INVALIDCALL;
719 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
720 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
722 object->fvf = FVF;
724 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
725 * drawStridedFast (half-life 2).
727 * Basically converting the vertices in the buffer is quite expensive, and observations
728 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
729 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
731 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
732 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
733 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
734 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
735 * dx7 apps.
736 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
737 * more. In this call we can convert dx7 buffers too.
739 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
740 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
741 (dxVersion > 7 || !conv) ) {
742 CreateVBO(object);
744 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
745 if(dxVersion == 7 && object->vbo) {
746 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
747 object->resource.allocatedMemory = NULL;
751 return WINED3D_OK;
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
755 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
756 HANDLE *sharedHandle, IUnknown *parent) {
757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
758 IWineD3DIndexBufferImpl *object;
759 TRACE("(%p) Creating index buffer\n", This);
761 /* Allocate the storage for the device */
762 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
764 /*TODO: use VBO's */
765 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
766 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
769 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
770 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
771 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
773 return WINED3D_OK;
776 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
779 IWineD3DStateBlockImpl *object;
780 int i, j;
781 HRESULT temp_result;
783 D3DCREATEOBJECTINSTANCE(object, StateBlock)
784 object->blockType = Type;
786 /* Special case - Used during initialization to produce a placeholder stateblock
787 so other functions called can update a state block */
788 if (Type == WINED3DSBT_INIT) {
789 /* Don't bother increasing the reference count otherwise a device will never
790 be freed due to circular dependencies */
791 return WINED3D_OK;
794 temp_result = allocate_shader_constants(object);
795 if (WINED3D_OK != temp_result)
796 return temp_result;
798 /* Otherwise, might as well set the whole state block to the appropriate values */
799 if (This->stateBlock != NULL)
800 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
801 else
802 memset(object->streamFreq, 1, sizeof(object->streamFreq));
804 /* Reset the ref and type after kludging it */
805 object->wineD3DDevice = This;
806 object->ref = 1;
807 object->blockType = Type;
809 TRACE("Updating changed flags appropriate for type %d\n", Type);
811 if (Type == WINED3DSBT_ALL) {
813 TRACE("ALL => Pretend everything has changed\n");
814 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
816 } else if (Type == WINED3DSBT_PIXELSTATE) {
818 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
819 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
821 object->changed.pixelShader = TRUE;
823 /* Pixel Shader Constants */
824 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
825 object->changed.pixelShaderConstantsF[i] = TRUE;
826 for (i = 0; i < MAX_CONST_B; ++i)
827 object->changed.pixelShaderConstantsB[i] = TRUE;
828 for (i = 0; i < MAX_CONST_I; ++i)
829 object->changed.pixelShaderConstantsI[i] = TRUE;
831 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
832 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
834 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
835 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
836 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
839 for (j = 0 ; j < 16; j++) {
840 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
842 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
846 } else if (Type == WINED3DSBT_VERTEXSTATE) {
848 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
849 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
851 object->changed.vertexShader = TRUE;
853 /* Vertex Shader Constants */
854 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
855 object->changed.vertexShaderConstantsF[i] = TRUE;
856 for (i = 0; i < MAX_CONST_B; ++i)
857 object->changed.vertexShaderConstantsB[i] = TRUE;
858 for (i = 0; i < MAX_CONST_I; ++i)
859 object->changed.vertexShaderConstantsI[i] = TRUE;
861 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
862 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
864 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
865 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
866 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
869 for (j = 0 ; j < 16; j++){
870 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
871 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
875 /* Duplicate light chain */
877 PLIGHTINFOEL *src = NULL;
878 PLIGHTINFOEL *dst = NULL;
879 PLIGHTINFOEL *newEl = NULL;
880 src = This->stateBlock->lights;
881 object->lights = NULL;
884 while (src) {
885 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
886 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
887 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
888 newEl->prev = dst;
889 newEl->changed = TRUE;
890 newEl->enabledChanged = TRUE;
891 if (dst == NULL) {
892 object->lights = newEl;
893 } else {
894 dst->next = newEl;
896 dst = newEl;
897 src = src->next;
902 } else {
903 FIXME("Unrecognized state block type %d\n", Type);
906 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
907 return WINED3D_OK;
911 /* ************************************
912 MSDN:
913 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
915 Discard
916 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
918 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.
920 ******************************** */
922 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) {
923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
924 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
925 unsigned int pow2Width, pow2Height;
926 unsigned int Size = 1;
927 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
928 TRACE("(%p) Create surface\n",This);
930 /** FIXME: Check ranges on the inputs are valid
931 * MSDN
932 * MultisampleQuality
933 * [in] Quality level. The valid range is between zero and one less than the level
934 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
935 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
936 * values of paired render targets, depth stencil surfaces, and the MultiSample type
937 * must all match.
938 *******************************/
942 * TODO: Discard MSDN
943 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
945 * If this flag is set, the contents of the depth stencil buffer will be
946 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
947 * with a different depth surface.
949 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
950 ***************************/
952 if(MultisampleQuality < 0) {
953 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
954 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
957 if(MultisampleQuality > 0) {
958 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
959 MultisampleQuality=0;
962 /** FIXME: Check that the format is supported
963 * by the device.
964 *******************************/
966 /* Non-power2 support */
968 /* Find the nearest pow2 match */
969 pow2Width = pow2Height = 1;
970 while (pow2Width < Width) pow2Width <<= 1;
971 while (pow2Height < Height) pow2Height <<= 1;
973 if (pow2Width > Width || pow2Height > Height) {
974 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
975 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
976 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
977 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
978 This, Width, Height);
979 return WINED3DERR_NOTAVAILABLE;
983 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
984 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
985 * space!
986 *********************************/
987 if (WINED3DFMT_UNKNOWN == Format) {
988 Size = 0;
989 } else if (Format == WINED3DFMT_DXT1) {
990 /* DXT1 is half byte per pixel */
991 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
993 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
994 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
995 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
996 } else {
997 Size = (pow2Width * tableEntry->bpp) * pow2Height;
1000 /** Create and initialise the surface resource **/
1001 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1002 /* "Standalone" surface */
1003 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1005 object->currentDesc.Width = Width;
1006 object->currentDesc.Height = Height;
1007 object->currentDesc.MultiSampleType = MultiSample;
1008 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1010 /* Setup some glformat defaults */
1011 object->glDescription.glFormat = tableEntry->glFormat;
1012 object->glDescription.glFormatInternal = tableEntry->glInternal;
1013 object->glDescription.glType = tableEntry->glType;
1015 object->glDescription.textureName = 0;
1016 object->glDescription.level = Level;
1017 object->glDescription.target = GL_TEXTURE_2D;
1019 /* Internal data */
1020 object->pow2Width = pow2Width;
1021 object->pow2Height = pow2Height;
1023 /* Flags */
1024 object->Flags = 0; /* We start without flags set */
1025 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1026 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1027 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1028 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1031 if (WINED3DFMT_UNKNOWN != Format) {
1032 object->bytesPerPixel = tableEntry->bpp;
1033 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1034 } else {
1035 object->bytesPerPixel = 0;
1036 object->pow2Size = 0;
1039 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1041 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1043 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1044 * this function is too deap to need to care about things like this.
1045 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1046 * ****************************************/
1047 switch(Pool) {
1048 case WINED3DPOOL_SCRATCH:
1049 if(Lockable == FALSE)
1050 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1051 which are mutually exclusive, setting lockable to true\n");
1052 Lockable = TRUE;
1053 break;
1054 case WINED3DPOOL_SYSTEMMEM:
1055 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1056 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1057 case WINED3DPOOL_MANAGED:
1058 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1059 Usage of DYNAMIC which are mutually exclusive, not doing \
1060 anything just telling you.\n");
1061 break;
1062 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1063 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1064 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1065 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1066 break;
1067 default:
1068 FIXME("(%p) Unknown pool %d\n", This, Pool);
1069 break;
1072 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1073 FIXME("Trying to create a render target that isn't in the default pool\n");
1076 /* mark the texture as dirty so that it get's loaded first time around*/
1077 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1078 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1079 This, Width, Height, Format, debug_d3dformat(Format),
1080 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1082 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1083 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1084 This->ddraw_primary = (IWineD3DSurface *) object;
1086 /* Look at the implementation and set the correct Vtable */
1087 switch(Impl) {
1088 case SURFACE_OPENGL:
1089 /* Nothing to do, it's set already */
1090 break;
1092 case SURFACE_GDI:
1093 object->lpVtbl = &IWineGDISurface_Vtbl;
1094 break;
1096 default:
1097 /* To be sure to catch this */
1098 ERR("Unknown requested surface implementation %d!\n", Impl);
1099 IWineD3DSurface_Release((IWineD3DSurface *) object);
1100 return WINED3DERR_INVALIDCALL;
1103 /* Call the private setup routine */
1104 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1108 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1109 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1110 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1111 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1114 IWineD3DTextureImpl *object;
1115 unsigned int i;
1116 UINT tmpW;
1117 UINT tmpH;
1118 HRESULT hr;
1119 unsigned int pow2Width = Width;
1120 unsigned int pow2Height = Height;
1123 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#lx\n", This, Width, Height, Levels, Usage);
1124 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1125 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1127 /* TODO: It should only be possible to create textures for formats
1128 that are reported as supported */
1129 if (WINED3DFMT_UNKNOWN >= Format) {
1130 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1131 return WINED3DERR_INVALIDCALL;
1134 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1135 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1136 object->width = Width;
1137 object->height = Height;
1139 /** Non-power2 support **/
1140 /* Find the nearest pow2 match */
1141 pow2Width = pow2Height = 1;
1142 while (pow2Width < Width) pow2Width <<= 1;
1143 while (pow2Height < Height) pow2Height <<= 1;
1145 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1146 /* Precalculated scaling for 'faked' non power of two texture coords */
1147 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1148 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1149 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1151 /* Calculate levels for mip mapping */
1152 if (Levels == 0) {
1153 TRACE("calculating levels %d\n", object->baseTexture.levels);
1154 object->baseTexture.levels++;
1155 tmpW = Width;
1156 tmpH = Height;
1157 while (tmpW > 1 || tmpH > 1) {
1158 tmpW = max(1, tmpW >> 1);
1159 tmpH = max(1, tmpH >> 1);
1160 object->baseTexture.levels++;
1162 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1165 /* Generate all the surfaces */
1166 tmpW = Width;
1167 tmpH = Height;
1168 for (i = 0; i < object->baseTexture.levels; i++)
1170 /* use the callback to create the texture surface */
1171 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1172 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1173 FIXME("Failed to create surface %p\n", object);
1174 /* clean up */
1175 object->surfaces[i] = NULL;
1176 IWineD3DTexture_Release((IWineD3DTexture *)object);
1178 *ppTexture = NULL;
1179 return hr;
1182 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1183 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1184 /* calculate the next mipmap level */
1185 tmpW = max(1, tmpW >> 1);
1186 tmpH = max(1, tmpH >> 1);
1189 TRACE("(%p) : Created texture %p\n", This, object);
1190 return WINED3D_OK;
1193 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1194 UINT Width, UINT Height, UINT Depth,
1195 UINT Levels, DWORD Usage,
1196 WINED3DFORMAT Format, WINED3DPOOL Pool,
1197 IWineD3DVolumeTexture **ppVolumeTexture,
1198 HANDLE *pSharedHandle, IUnknown *parent,
1199 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1202 IWineD3DVolumeTextureImpl *object;
1203 unsigned int i;
1204 UINT tmpW;
1205 UINT tmpH;
1206 UINT tmpD;
1208 /* TODO: It should only be possible to create textures for formats
1209 that are reported as supported */
1210 if (WINED3DFMT_UNKNOWN >= Format) {
1211 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1212 return WINED3DERR_INVALIDCALL;
1215 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1216 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1218 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1219 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1221 object->width = Width;
1222 object->height = Height;
1223 object->depth = Depth;
1225 /* Calculate levels for mip mapping */
1226 if (Levels == 0) {
1227 object->baseTexture.levels++;
1228 tmpW = Width;
1229 tmpH = Height;
1230 tmpD = Depth;
1231 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1232 tmpW = max(1, tmpW >> 1);
1233 tmpH = max(1, tmpH >> 1);
1234 tmpD = max(1, tmpD >> 1);
1235 object->baseTexture.levels++;
1237 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1240 /* Generate all the surfaces */
1241 tmpW = Width;
1242 tmpH = Height;
1243 tmpD = Depth;
1245 for (i = 0; i < object->baseTexture.levels; i++)
1247 /* Create the volume */
1248 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1249 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1251 /* Set it's container to this object */
1252 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1254 /* calcualte the next mipmap level */
1255 tmpW = max(1, tmpW >> 1);
1256 tmpH = max(1, tmpH >> 1);
1257 tmpD = max(1, tmpD >> 1);
1260 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1261 TRACE("(%p) : Created volume texture %p\n", This, object);
1262 return WINED3D_OK;
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1266 UINT Width, UINT Height, UINT Depth,
1267 DWORD Usage,
1268 WINED3DFORMAT Format, WINED3DPOOL Pool,
1269 IWineD3DVolume** ppVolume,
1270 HANDLE* pSharedHandle, IUnknown *parent) {
1272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1274 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1276 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1278 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1279 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1281 object->currentDesc.Width = Width;
1282 object->currentDesc.Height = Height;
1283 object->currentDesc.Depth = Depth;
1284 object->bytesPerPixel = formatDesc->bpp;
1286 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1287 object->lockable = TRUE;
1288 object->locked = FALSE;
1289 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1290 object->dirty = TRUE;
1292 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1295 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1296 UINT Levels, DWORD Usage,
1297 WINED3DFORMAT Format, WINED3DPOOL Pool,
1298 IWineD3DCubeTexture **ppCubeTexture,
1299 HANDLE *pSharedHandle, IUnknown *parent,
1300 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1304 unsigned int i, j;
1305 UINT tmpW;
1306 HRESULT hr;
1307 unsigned int pow2EdgeLength = EdgeLength;
1309 /* TODO: It should only be possible to create textures for formats
1310 that are reported as supported */
1311 if (WINED3DFMT_UNKNOWN >= Format) {
1312 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1313 return WINED3DERR_INVALIDCALL;
1316 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1317 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1319 TRACE("(%p) Create Cube Texture\n", This);
1321 /** Non-power2 support **/
1323 /* Find the nearest pow2 match */
1324 pow2EdgeLength = 1;
1325 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1327 object->edgeLength = EdgeLength;
1328 /* TODO: support for native non-power 2 */
1329 /* Precalculated scaling for 'faked' non power of two texture coords */
1330 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1332 /* Calculate levels for mip mapping */
1333 if (Levels == 0) {
1334 object->baseTexture.levels++;
1335 tmpW = EdgeLength;
1336 while (tmpW > 1) {
1337 tmpW = max(1, tmpW >> 1);
1338 object->baseTexture.levels++;
1340 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1343 /* Generate all the surfaces */
1344 tmpW = EdgeLength;
1345 for (i = 0; i < object->baseTexture.levels; i++) {
1347 /* Create the 6 faces */
1348 for (j = 0; j < 6; j++) {
1350 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1351 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1353 if(hr!= WINED3D_OK) {
1354 /* clean up */
1355 int k;
1356 int l;
1357 for (l = 0; l < j; l++) {
1358 IWineD3DSurface_Release(object->surfaces[j][i]);
1360 for (k = 0; k < i; k++) {
1361 for (l = 0; l < 6; l++) {
1362 IWineD3DSurface_Release(object->surfaces[l][j]);
1366 FIXME("(%p) Failed to create surface\n",object);
1367 HeapFree(GetProcessHeap(),0,object);
1368 *ppCubeTexture = NULL;
1369 return hr;
1371 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1372 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1374 tmpW = max(1, tmpW >> 1);
1377 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1378 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1379 return WINED3D_OK;
1382 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1384 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1386 if (NULL == ppQuery) {
1387 /* Just a check to see if we support this type of query */
1388 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1389 switch(Type) {
1390 case WINED3DQUERYTYPE_OCCLUSION:
1391 TRACE("(%p) occlusion query\n", This);
1392 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1393 hr = WINED3D_OK;
1394 else
1395 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1396 break;
1397 case WINED3DQUERYTYPE_VCACHE:
1398 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1399 case WINED3DQUERYTYPE_VERTEXSTATS:
1400 case WINED3DQUERYTYPE_EVENT:
1401 case WINED3DQUERYTYPE_TIMESTAMP:
1402 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1403 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1404 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1405 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1406 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1407 case WINED3DQUERYTYPE_PIXELTIMINGS:
1408 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1409 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1410 default:
1411 FIXME("(%p) Unhandled query type %d\n", This, Type);
1413 return hr;
1416 D3DCREATEOBJECTINSTANCE(object, Query)
1417 object->type = Type;
1418 /* allocated the 'extended' data based on the type of query requested */
1419 switch(Type){
1420 case D3DQUERYTYPE_OCCLUSION:
1421 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1422 TRACE("(%p) Allocating data for an occlusion query\n", This);
1423 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1424 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1425 break;
1427 case D3DQUERYTYPE_VCACHE:
1428 case D3DQUERYTYPE_RESOURCEMANAGER:
1429 case D3DQUERYTYPE_VERTEXSTATS:
1430 case D3DQUERYTYPE_EVENT:
1431 case D3DQUERYTYPE_TIMESTAMP:
1432 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1433 case D3DQUERYTYPE_TIMESTAMPFREQ:
1434 case D3DQUERYTYPE_PIPELINETIMINGS:
1435 case D3DQUERYTYPE_INTERFACETIMINGS:
1436 case D3DQUERYTYPE_VERTEXTIMINGS:
1437 case D3DQUERYTYPE_PIXELTIMINGS:
1438 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1439 case D3DQUERYTYPE_CACHEUTILIZATION:
1440 default:
1441 object->extendedData = 0;
1442 FIXME("(%p) Unhandled query type %d\n",This , Type);
1444 TRACE("(%p) : Created Query %p\n", This, object);
1445 return WINED3D_OK;
1448 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1449 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1450 IUnknown* parent,
1451 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1452 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1455 HDC hDc;
1456 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1457 int num;
1458 XVisualInfo template;
1459 GLXContext oldContext;
1460 Drawable oldDrawable;
1461 HRESULT hr = WINED3D_OK;
1463 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1465 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1466 * does a device hold a reference to a swap chain giving them a lifetime of the device
1467 * or does the swap chain notify the device of its destruction.
1468 *******************************/
1470 /* Check the params */
1471 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1472 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1473 return WINED3DERR_INVALIDCALL;
1474 } else if (*pPresentationParameters->BackBufferCount > 1) {
1475 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");
1478 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1480 /*********************
1481 * Lookup the window Handle and the relating X window handle
1482 ********************/
1484 /* Setup hwnd we are using, plus which display this equates to */
1485 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1486 if (!object->win_handle) {
1487 object->win_handle = This->createParms.hFocusWindow;
1490 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1491 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1492 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1493 return WINED3DERR_NOTAVAILABLE;
1495 hDc = GetDC(object->win_handle);
1496 object->display = get_display(hDc);
1497 ReleaseDC(object->win_handle, hDc);
1498 TRACE("Using a display of %p %p\n", object->display, hDc);
1500 if (NULL == object->display || NULL == hDc) {
1501 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1502 return WINED3DERR_NOTAVAILABLE;
1505 if (object->win == 0) {
1506 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1507 return WINED3DERR_NOTAVAILABLE;
1510 * Create an opengl context for the display visual
1511 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1512 * use different properties after that point in time. FIXME: How to handle when requested format
1513 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1514 * it chooses is identical to the one already being used!
1515 **********************************/
1517 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1518 ENTER_GL();
1520 /* Create a new context for this swapchain */
1521 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1522 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1523 (or the best possible if none is requested) */
1524 TRACE("Found x visual ID : %ld\n", template.visualid);
1526 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1527 if (NULL == object->visInfo) {
1528 ERR("cannot really get XVisual\n");
1529 LEAVE_GL();
1530 return WINED3DERR_NOTAVAILABLE;
1531 } else {
1532 int n, value;
1533 /* Write out some debug info about the visual/s */
1534 TRACE("Using x visual ID : %ld\n", template.visualid);
1535 TRACE(" visual info: %p\n", object->visInfo);
1536 TRACE(" num items : %d\n", num);
1537 for (n = 0;n < num; n++) {
1538 TRACE("=====item=====: %d\n", n + 1);
1539 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1540 TRACE(" screen : %d\n", object->visInfo[n].screen);
1541 TRACE(" depth : %u\n", object->visInfo[n].depth);
1542 TRACE(" class : %d\n", object->visInfo[n].class);
1543 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1544 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1545 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1546 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1547 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1548 /* log some extra glx info */
1549 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1550 TRACE(" gl_aux_buffers : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1552 TRACE(" gl_buffer_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1554 TRACE(" gl_red_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1556 TRACE(" gl_green_size : %d\n", value);
1557 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1558 TRACE(" gl_blue_size : %d\n", value);
1559 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1560 TRACE(" gl_alpha_size : %d\n", value);
1561 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1562 TRACE(" gl_depth_size : %d\n", value);
1563 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1564 TRACE(" gl_stencil_size : %d\n", value);
1566 /* Now choose a simila visual ID*/
1568 #ifdef USE_CONTEXT_MANAGER
1570 /** TODO: use a context mamager **/
1571 #endif
1574 IWineD3DSwapChain *implSwapChain;
1575 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1576 /* The first time around we create the context that is shared with all other swapchains and render targets */
1577 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1578 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1579 } else {
1581 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1582 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1583 /* and create a new context with the implicit swapchains context as the shared context */
1584 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1585 IWineD3DSwapChain_Release(implSwapChain);
1589 /* Cleanup */
1590 XFree(object->visInfo);
1591 object->visInfo = NULL;
1593 LEAVE_GL();
1595 if (!object->glCtx) {
1596 ERR("Failed to create GLX context\n");
1597 return WINED3DERR_NOTAVAILABLE;
1598 } else {
1599 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1600 object->win_handle, object->glCtx, object->win, object->visInfo);
1603 /*********************
1604 * Windowed / Fullscreen
1605 *******************/
1608 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1609 * so we should really check to see if there is a fullscreen swapchain already
1610 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1611 **************************************/
1613 if (!*(pPresentationParameters->Windowed)) {
1615 DEVMODEW devmode;
1616 HDC hdc;
1617 int bpp = 0;
1619 /* Get info on the current display setup */
1620 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1621 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1622 DeleteDC(hdc);
1624 /* Change the display settings */
1625 memset(&devmode, 0, sizeof(DEVMODEW));
1626 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1627 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1628 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1629 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1630 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1631 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1633 /* Make popup window */
1634 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1635 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1636 *(pPresentationParameters->BackBufferWidth),
1637 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1639 /* For GetDisplayMode */
1640 This->ddraw_width = devmode.dmPelsWidth;
1641 This->ddraw_height = devmode.dmPelsHeight;
1642 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1646 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1647 * then the corresponding dimension of the client area of the hDeviceWindow
1648 * (or the focus window, if hDeviceWindow is NULL) is taken.
1649 **********************/
1651 if (*(pPresentationParameters->Windowed) &&
1652 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1653 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1655 RECT Rect;
1656 GetClientRect(object->win_handle, &Rect);
1658 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1659 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1660 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1662 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1663 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1664 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1668 /*********************
1669 * finish off parameter initialization
1670 *******************/
1672 /* Put the correct figures in the presentation parameters */
1673 TRACE("Coppying accross presentaion paraneters\n");
1674 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1675 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1676 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1677 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1678 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1679 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1680 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1681 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1682 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1683 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1684 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1685 object->presentParms.Flags = *(pPresentationParameters->Flags);
1686 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1687 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1690 /*********************
1691 * Create the back, front and stencil buffers
1692 *******************/
1694 TRACE("calling rendertarget CB\n");
1695 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1696 object->presentParms.BackBufferWidth,
1697 object->presentParms.BackBufferHeight,
1698 object->presentParms.BackBufferFormat,
1699 object->presentParms.MultiSampleType,
1700 object->presentParms.MultiSampleQuality,
1701 TRUE /* Lockable */,
1702 &object->frontBuffer,
1703 NULL /* pShared (always null)*/);
1704 if (object->frontBuffer != NULL)
1705 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1707 if(object->presentParms.BackBufferCount > 0) {
1708 int i;
1710 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1711 if(!object->backBuffer) {
1712 ERR("Out of memory\n");
1714 if (object->frontBuffer) {
1715 IUnknown *bufferParent;
1716 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1717 IUnknown_Release(bufferParent); /* once for the get parent */
1718 if (IUnknown_Release(bufferParent) > 0) {
1719 FIXME("(%p) Something's still holding the front buffer\n",This);
1722 HeapFree(GetProcessHeap(), 0, object);
1723 return E_OUTOFMEMORY;
1726 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1727 TRACE("calling rendertarget CB\n");
1728 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1729 object->presentParms.BackBufferWidth,
1730 object->presentParms.BackBufferHeight,
1731 object->presentParms.BackBufferFormat,
1732 object->presentParms.MultiSampleType,
1733 object->presentParms.MultiSampleQuality,
1734 TRUE /* Lockable */,
1735 &object->backBuffer[i],
1736 NULL /* pShared (always null)*/);
1737 if(hr == WINED3D_OK && object->backBuffer[i]) {
1738 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1739 } else {
1740 break;
1743 } else {
1744 object->backBuffer = NULL;
1747 if (object->backBuffer != NULL) {
1748 ENTER_GL();
1749 glDrawBuffer(GL_BACK);
1750 checkGLcall("glDrawBuffer(GL_BACK)");
1751 LEAVE_GL();
1752 } else {
1753 /* Single buffering - draw to front buffer */
1754 ENTER_GL();
1755 glDrawBuffer(GL_FRONT);
1756 checkGLcall("glDrawBuffer(GL_FRONT)");
1757 LEAVE_GL();
1760 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1761 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1762 TRACE("Creating depth stencil buffer\n");
1763 if (This->depthStencilBuffer == NULL ) {
1764 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1765 object->presentParms.BackBufferWidth,
1766 object->presentParms.BackBufferHeight,
1767 object->presentParms.AutoDepthStencilFormat,
1768 object->presentParms.MultiSampleType,
1769 object->presentParms.MultiSampleQuality,
1770 FALSE /* FIXME: Discard */,
1771 &This->depthStencilBuffer,
1772 NULL /* pShared (always null)*/ );
1773 if (This->depthStencilBuffer != NULL)
1774 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1777 /** TODO: A check on width, height and multisample types
1778 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1779 ****************************/
1780 object->wantsDepthStencilBuffer = TRUE;
1781 } else {
1782 object->wantsDepthStencilBuffer = FALSE;
1785 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1788 /*********************
1789 * init the default renderTarget management
1790 *******************/
1791 object->drawable = object->win;
1792 object->render_ctx = object->glCtx;
1794 if (hr == WINED3D_OK) {
1795 /*********************
1796 * Setup some defaults and clear down the buffers
1797 *******************/
1798 ENTER_GL();
1799 /** save current context and drawable **/
1800 oldContext = glXGetCurrentContext();
1801 oldDrawable = glXGetCurrentDrawable();
1803 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1804 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1805 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1807 checkGLcall("glXMakeCurrent");
1809 TRACE("Setting up the screen\n");
1810 /* Clear the screen */
1811 glClearColor(1.0, 0.0, 0.0, 0.0);
1812 checkGLcall("glClearColor");
1813 glClearIndex(0);
1814 glClearDepth(1);
1815 glClearStencil(0xffff);
1817 checkGLcall("glClear");
1819 glColor3f(1.0, 1.0, 1.0);
1820 checkGLcall("glColor3f");
1822 glEnable(GL_LIGHTING);
1823 checkGLcall("glEnable");
1825 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1826 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1828 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1829 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1831 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1832 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1834 /* switch back to the original context (if there was one)*/
1835 if (This->swapchains) {
1836 /** TODO: restore the context and drawable **/
1837 glXMakeCurrent(object->display, oldDrawable, oldContext);
1840 LEAVE_GL();
1842 TRACE("Set swapchain to %p\n", object);
1843 } else { /* something went wrong so clean up */
1844 IUnknown* bufferParent;
1845 if (object->frontBuffer) {
1847 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1848 IUnknown_Release(bufferParent); /* once for the get parent */
1849 if (IUnknown_Release(bufferParent) > 0) {
1850 FIXME("(%p) Something's still holding the front buffer\n",This);
1853 if (object->backBuffer) {
1854 int i;
1855 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1856 if(object->backBuffer[i]) {
1857 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1858 IUnknown_Release(bufferParent); /* once for the get parent */
1859 if (IUnknown_Release(bufferParent) > 0) {
1860 FIXME("(%p) Something's still holding the back buffer\n",This);
1864 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1865 object->backBuffer = NULL;
1867 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1868 /* Clean up the context */
1869 /* check that we are the current context first (we shouldn't be though!) */
1870 if (object->glCtx != 0) {
1871 if(glXGetCurrentContext() == object->glCtx) {
1872 glXMakeCurrent(object->display, None, NULL);
1874 glXDestroyContext(object->display, object->glCtx);
1876 HeapFree(GetProcessHeap(), 0, object);
1880 return hr;
1883 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1884 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 TRACE("(%p)\n", This);
1888 return This->NumberOfSwapChains;
1891 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1895 if(iSwapChain < This->NumberOfSwapChains) {
1896 *pSwapChain = This->swapchains[iSwapChain];
1897 IWineD3DSwapChain_AddRef(*pSwapChain);
1898 TRACE("(%p) returning %p\n", This, *pSwapChain);
1899 return WINED3D_OK;
1900 } else {
1901 TRACE("Swapchain out of range\n");
1902 *pSwapChain = NULL;
1903 return WINED3DERR_INVALIDCALL;
1907 /*****
1908 * Vertex Declaration
1909 *****/
1910 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 IWineD3DVertexDeclarationImpl *object = NULL;
1913 HRESULT hr = WINED3D_OK;
1914 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1915 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1916 object->allFVF = 0;
1918 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1920 return hr;
1923 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1927 HRESULT hr = WINED3D_OK;
1928 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1929 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1931 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1933 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1934 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1935 if (pDeclaration != NULL) {
1936 IWineD3DVertexDeclaration *vertexDeclaration;
1937 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1938 if (WINED3D_OK == hr) {
1939 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1940 object->vertexDeclaration = vertexDeclaration;
1941 } else {
1942 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1943 IWineD3DVertexShader_Release(*ppVertexShader);
1944 return WINED3DERR_INVALIDCALL;
1948 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1950 if (WINED3D_OK != hr) {
1951 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1952 IWineD3DVertexShader_Release(*ppVertexShader);
1953 return WINED3DERR_INVALIDCALL;
1956 #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. */
1957 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1958 /* Foo */
1959 } else {
1960 /* Bar */
1963 #endif
1965 return WINED3D_OK;
1968 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1970 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1971 HRESULT hr = WINED3D_OK;
1973 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1974 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1975 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1976 if (WINED3D_OK == hr) {
1977 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1978 } else {
1979 WARN("(%p) : Failed to create pixel shader\n", This);
1982 return hr;
1985 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 IWineD3DPaletteImpl *object;
1988 HRESULT hr;
1989 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1991 /* Create the new object */
1992 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1993 if(!object) {
1994 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1995 return E_OUTOFMEMORY;
1998 object->lpVtbl = &IWineD3DPalette_Vtbl;
1999 object->ref = 1;
2000 object->Flags = Flags;
2001 object->parent = Parent;
2002 object->wineD3DDevice = This;
2003 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2005 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2007 if(!object->hpal) {
2008 HeapFree( GetProcessHeap(), 0, object);
2009 return E_OUTOFMEMORY;
2012 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2013 if(FAILED(hr)) {
2014 IWineD3DPalette_Release((IWineD3DPalette *) object);
2015 return hr;
2018 *Palette = (IWineD3DPalette *) object;
2020 return WINED3D_OK;
2023 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2025 IWineD3DSwapChainImpl *swapchain;
2027 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2028 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2030 /* TODO: Test if OpenGL is compiled in and loaded */
2032 /* Setup the implicit swapchain */
2033 TRACE("Creating implicit swapchain\n");
2034 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2035 WARN("Failed to create implicit swapchain\n");
2036 return WINED3DERR_INVALIDCALL;
2039 This->NumberOfSwapChains = 1;
2040 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2041 if(!This->swapchains) {
2042 ERR("Out of memory!\n");
2043 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2044 return E_OUTOFMEMORY;
2046 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2048 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2049 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2050 This->renderTarget = swapchain->backBuffer[0];
2052 else {
2053 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2054 This->renderTarget = swapchain->frontBuffer;
2056 IWineD3DSurface_AddRef(This->renderTarget);
2057 /* Depth Stencil support */
2058 This->stencilBufferTarget = This->depthStencilBuffer;
2059 if (NULL != This->stencilBufferTarget) {
2060 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2063 /* Set up some starting GL setup */
2064 ENTER_GL();
2066 * Initialize openGL extension related variables
2067 * with Default values
2070 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2071 /* Setup all the devices defaults */
2072 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2073 #if 0
2074 IWineD3DImpl_CheckGraphicsMemory();
2075 #endif
2076 LEAVE_GL();
2078 /* Initialize our list of GLSL programs */
2079 list_init(&This->glsl_shader_progs);
2081 { /* Set a default viewport */
2082 D3DVIEWPORT9 vp;
2083 vp.X = 0;
2084 vp.Y = 0;
2085 vp.Width = *(pPresentationParameters->BackBufferWidth);
2086 vp.Height = *(pPresentationParameters->BackBufferHeight);
2087 vp.MinZ = 0.0f;
2088 vp.MaxZ = 1.0f;
2089 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2092 /* Initialize the current view state */
2093 This->modelview_valid = 1;
2094 This->proj_valid = 0;
2095 This->view_ident = 1;
2096 This->last_was_rhw = 0;
2097 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2098 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2100 /* Clear the screen */
2101 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2103 This->d3d_initialized = TRUE;
2104 return WINED3D_OK;
2107 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2109 int sampler;
2110 IUnknown* stencilBufferParent;
2111 IUnknown* swapChainParent;
2112 uint i;
2113 TRACE("(%p)\n", This);
2115 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2117 /* Delete the mouse cursor texture */
2118 if(This->cursorTexture) {
2119 ENTER_GL();
2120 glDeleteTextures(1, &This->cursorTexture);
2121 LEAVE_GL();
2122 This->cursorTexture = 0;
2125 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2126 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2129 /* Release the buffers (with sanity checks)*/
2130 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2131 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2132 if(This->depthStencilBuffer != This->stencilBufferTarget)
2133 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2135 This->stencilBufferTarget = NULL;
2137 TRACE("Releasing the render target at %p\n", This->renderTarget);
2138 if(IWineD3DSurface_Release(This->renderTarget) >0){
2139 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2141 TRACE("Setting rendertarget to NULL\n");
2142 This->renderTarget = NULL;
2144 if (This->depthStencilBuffer) {
2145 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2146 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2147 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2148 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2150 This->depthStencilBuffer = NULL;
2153 for(i=0; i < This->NumberOfSwapChains; i++) {
2154 TRACE("Releasing the implicit swapchain %d\n", i);
2155 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2156 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2157 IUnknown_Release(swapChainParent); /* once for the get parent */
2158 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2159 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2163 HeapFree(GetProcessHeap(), 0, This->swapchains);
2164 This->swapchains = NULL;
2165 This->NumberOfSwapChains = 0;
2167 This->d3d_initialized = FALSE;
2168 return WINED3D_OK;
2171 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2174 DEVMODEW DevModeW;
2175 int i;
2176 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2178 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2180 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2181 /* Ignore some modes if a description was passed */
2182 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2183 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2184 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2186 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2188 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2189 return D3D_OK;
2192 return D3D_OK;
2195 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2196 DEVMODEW devmode;
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2198 LONG ret;
2199 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2201 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2203 /* Resize the screen even without a window:
2204 * The app could have unset it with SetCooperativeLevel, but not called
2205 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2206 * but we don't have any hwnd
2209 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2210 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2211 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2212 devmode.dmPelsWidth = pMode->Width;
2213 devmode.dmPelsHeight = pMode->Height;
2215 devmode.dmDisplayFrequency = pMode->RefreshRate;
2216 if (pMode->RefreshRate != 0) {
2217 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2220 /* Only change the mode if necessary */
2221 if( (This->ddraw_width == pMode->Width) &&
2222 (This->ddraw_height == pMode->Height) &&
2223 (This->ddraw_format == pMode->Format) &&
2224 (pMode->RefreshRate == 0) ) {
2225 return D3D_OK;
2228 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2229 if (ret != DISP_CHANGE_SUCCESSFUL) {
2230 if(devmode.dmDisplayFrequency != 0) {
2231 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2232 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2233 devmode.dmDisplayFrequency = 0;
2234 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2236 if(ret != DISP_CHANGE_SUCCESSFUL) {
2237 return DDERR_INVALIDMODE;
2241 /* Store the new values */
2242 This->ddraw_width = pMode->Width;
2243 This->ddraw_height = pMode->Height;
2244 This->ddraw_format = pMode->Format;
2246 /* Only do this with a window of course */
2247 if(This->ddraw_window)
2248 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2250 return WINED3D_OK;
2253 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 *ppD3D= This->wineD3D;
2256 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2257 IWineD3D_AddRef(*ppD3D);
2258 return WINED3D_OK;
2261 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2262 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2263 * Into the video ram as possible and seeing how many fit
2264 * you can also get the correct initial value from nvidia and ATI's driver via X
2265 * texture memory is video memory + AGP memory
2266 *******************/
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 static BOOL showfixmes = TRUE;
2269 if (showfixmes) {
2270 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2271 (wined3d_settings.emulated_textureram/(1024*1024)),
2272 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2273 showfixmes = FALSE;
2275 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2276 (wined3d_settings.emulated_textureram/(1024*1024)),
2277 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2278 /* return simulated texture memory left */
2279 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2284 /*****
2285 * Get / Set FVF
2286 *****/
2287 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2289 HRESULT hr = WINED3D_OK;
2291 /* Update the current state block */
2292 This->updateStateBlock->fvf = fvf;
2293 This->updateStateBlock->changed.fvf = TRUE;
2294 This->updateStateBlock->set.fvf = TRUE;
2296 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2297 return hr;
2301 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2304 *pfvf = This->stateBlock->fvf;
2305 return WINED3D_OK;
2308 /*****
2309 * Get / Set Stream Source
2310 *****/
2311 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 IWineD3DVertexBuffer *oldSrc;
2315 /**TODO: instance and index data, see
2316 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2318 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2319 **************/
2321 /* D3d9 only, but shouldn't hurt d3d8 */
2322 UINT streamFlags;
2324 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2325 if (streamFlags) {
2326 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2327 FIXME("stream index data not supported\n");
2329 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2330 FIXME("stream instance data not supported\n");
2334 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2336 if (StreamNumber >= MAX_STREAMS) {
2337 WARN("Stream out of range %d\n", StreamNumber);
2338 return WINED3DERR_INVALIDCALL;
2341 oldSrc = This->stateBlock->streamSource[StreamNumber];
2342 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2344 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2345 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2346 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2347 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2348 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2349 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2351 /* Handle recording of state blocks */
2352 if (This->isRecordingState) {
2353 TRACE("Recording... not performing anything\n");
2354 return WINED3D_OK;
2357 /* Same stream object: no action */
2358 if (oldSrc == pStreamData)
2359 return WINED3D_OK;
2361 /* Need to do a getParent and pass the reffs up */
2362 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2363 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2364 so for now, just count internally */
2365 if (pStreamData != NULL) {
2366 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2367 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2368 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2370 vbImpl->stream = StreamNumber;
2371 vbImpl->Flags |= VBFLAG_STREAM;
2372 IWineD3DVertexBuffer_AddRef(pStreamData);
2374 if (oldSrc != NULL) {
2375 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2376 IWineD3DVertexBuffer_Release(oldSrc);
2379 return WINED3D_OK;
2382 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 UINT streamFlags;
2386 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2387 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2390 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2391 if (streamFlags) {
2392 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2393 FIXME("stream index data not supported\n");
2395 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2396 FIXME("stream instance data not supported\n");
2400 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2402 if (StreamNumber >= MAX_STREAMS) {
2403 WARN("Stream out of range %d\n", StreamNumber);
2404 return WINED3DERR_INVALIDCALL;
2406 *pStream = This->stateBlock->streamSource[StreamNumber];
2407 *pStride = This->stateBlock->streamStride[StreamNumber];
2408 if (pOffset) {
2409 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2412 if (*pStream == NULL) {
2413 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2414 return WINED3DERR_INVALIDCALL;
2417 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2418 return WINED3D_OK;
2421 /*Should be quite easy, just an extension of vertexdata
2422 ref...
2423 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2425 The divider is a bit odd though
2427 VertexOffset = StartVertex / Divider * StreamStride +
2428 VertexIndex / Divider * StreamStride + StreamOffset
2431 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2434 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2435 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2437 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2438 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2439 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2441 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2442 FIXME("Stream indexing not fully supported\n");
2445 return WINED3D_OK;
2448 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2452 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2454 TRACE("(%p) : returning %d\n", This, *Divider);
2456 return WINED3D_OK;
2459 /*****
2460 * Get / Set & Multiply Transform
2461 *****/
2462 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 /* Most of this routine, comments included copied from ddraw tree initially: */
2466 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2468 /* Handle recording of state blocks */
2469 if (This->isRecordingState) {
2470 TRACE("Recording... not performing anything\n");
2471 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2472 This->updateStateBlock->set.transform[d3dts] = TRUE;
2473 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2474 return WINED3D_OK;
2478 * If the new matrix is the same as the current one,
2479 * we cut off any further processing. this seems to be a reasonable
2480 * optimization because as was noticed, some apps (warcraft3 for example)
2481 * tend towards setting the same matrix repeatedly for some reason.
2483 * From here on we assume that the new matrix is different, wherever it matters.
2485 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2486 TRACE("The app is setting the same matrix over again\n");
2487 return WINED3D_OK;
2488 } else {
2489 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2493 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2494 where ViewMat = Camera space, WorldMat = world space.
2496 In OpenGL, camera and world space is combined into GL_MODELVIEW
2497 matrix. The Projection matrix stay projection matrix.
2500 /* Capture the times we can just ignore the change for now */
2501 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2502 This->modelview_valid = FALSE;
2503 return WINED3D_OK;
2505 } else if (d3dts == WINED3DTS_PROJECTION) {
2506 This->proj_valid = FALSE;
2507 return WINED3D_OK;
2509 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2510 /* Indexed Vertex Blending Matrices 256 -> 511 */
2511 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2512 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2513 return WINED3D_OK;
2516 /* Now we really are going to have to change a matrix */
2517 ENTER_GL();
2519 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2520 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2521 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2522 unsigned int k;
2524 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2525 * NOTE: We have to reset the positions even if the light/plane is not currently
2526 * enabled, since the call to enable it will not reset the position.
2527 * NOTE2: Apparently texture transforms do NOT need reapplying
2530 PLIGHTINFOEL *lightChain = NULL;
2531 This->modelview_valid = FALSE;
2532 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2534 glMatrixMode(GL_MODELVIEW);
2535 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2536 glPushMatrix();
2537 glLoadMatrixf((float *)lpmatrix);
2538 checkGLcall("glLoadMatrixf(...)");
2540 /* Reset lights */
2541 lightChain = This->stateBlock->lights;
2542 while (lightChain && lightChain->glIndex != -1) {
2543 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2544 checkGLcall("glLightfv posn");
2545 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2546 checkGLcall("glLightfv dirn");
2547 lightChain = lightChain->next;
2550 /* Reset Clipping Planes if clipping is enabled */
2551 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2552 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2553 checkGLcall("glClipPlane");
2555 glPopMatrix();
2557 } else { /* What was requested!?? */
2558 WARN("invalid matrix specified: %i\n", d3dts);
2561 /* Release lock, all done */
2562 LEAVE_GL();
2563 return WINED3D_OK;
2566 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2569 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2570 return WINED3D_OK;
2573 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2574 D3DMATRIX *mat = NULL;
2575 D3DMATRIX temp;
2577 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2578 * below means it will be recorded in a state block change, but it
2579 * works regardless where it is recorded.
2580 * If this is found to be wrong, change to StateBlock.
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2585 if (State < HIGHEST_TRANSFORMSTATE)
2587 mat = &This->updateStateBlock->transforms[State];
2588 } else {
2589 FIXME("Unhandled transform state!!\n");
2592 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2594 /* Apply change via set transform - will reapply to eg. lights this way */
2595 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2598 /*****
2599 * Get / Set Light
2600 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2601 *****/
2602 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2603 you can reference any indexes you want as long as that number max are enabled at any
2604 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2605 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2606 but when recording, just build a chain pretty much of commands to be replayed. */
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2609 float rho;
2610 PLIGHTINFOEL *object, *temp;
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2615 /* If recording state block, just add to end of lights chain */
2616 if (This->isRecordingState) {
2617 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2618 if (NULL == object) {
2619 return WINED3DERR_OUTOFVIDEOMEMORY;
2621 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2622 object->OriginalIndex = Index;
2623 object->glIndex = -1;
2624 object->changed = TRUE;
2626 /* Add to the END of the chain of lights changes to be replayed */
2627 if (This->updateStateBlock->lights == NULL) {
2628 This->updateStateBlock->lights = object;
2629 } else {
2630 temp = This->updateStateBlock->lights;
2631 while (temp->next != NULL) temp=temp->next;
2632 temp->next = object;
2634 TRACE("Recording... not performing anything more\n");
2635 return WINED3D_OK;
2638 /* Ok, not recording any longer so do real work */
2639 object = This->stateBlock->lights;
2640 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2642 /* If we didn't find it in the list of lights, time to add it */
2643 if (object == NULL) {
2644 PLIGHTINFOEL *insertAt,*prevPos;
2646 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2647 if (NULL == object) {
2648 return WINED3DERR_OUTOFVIDEOMEMORY;
2650 object->OriginalIndex = Index;
2651 object->glIndex = -1;
2653 /* Add it to the front of list with the idea that lights will be changed as needed
2654 BUT after any lights currently assigned GL indexes */
2655 insertAt = This->stateBlock->lights;
2656 prevPos = NULL;
2657 while (insertAt != NULL && insertAt->glIndex != -1) {
2658 prevPos = insertAt;
2659 insertAt = insertAt->next;
2662 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2663 This->stateBlock->lights = object;
2664 } else if (insertAt == NULL) { /* End of list */
2665 prevPos->next = object;
2666 object->prev = prevPos;
2667 } else { /* Middle of chain */
2668 if (prevPos == NULL) {
2669 This->stateBlock->lights = object;
2670 } else {
2671 prevPos->next = object;
2673 object->prev = prevPos;
2674 object->next = insertAt;
2675 insertAt->prev = object;
2679 /* Initialize the object */
2680 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,
2681 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2682 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2683 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2684 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2685 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2686 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2688 /* Save away the information */
2689 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2691 switch (pLight->Type) {
2692 case D3DLIGHT_POINT:
2693 /* Position */
2694 object->lightPosn[0] = pLight->Position.x;
2695 object->lightPosn[1] = pLight->Position.y;
2696 object->lightPosn[2] = pLight->Position.z;
2697 object->lightPosn[3] = 1.0f;
2698 object->cutoff = 180.0f;
2699 /* FIXME: Range */
2700 break;
2702 case D3DLIGHT_DIRECTIONAL:
2703 /* Direction */
2704 object->lightPosn[0] = -pLight->Direction.x;
2705 object->lightPosn[1] = -pLight->Direction.y;
2706 object->lightPosn[2] = -pLight->Direction.z;
2707 object->lightPosn[3] = 0.0;
2708 object->exponent = 0.0f;
2709 object->cutoff = 180.0f;
2710 break;
2712 case D3DLIGHT_SPOT:
2713 /* Position */
2714 object->lightPosn[0] = pLight->Position.x;
2715 object->lightPosn[1] = pLight->Position.y;
2716 object->lightPosn[2] = pLight->Position.z;
2717 object->lightPosn[3] = 1.0;
2719 /* Direction */
2720 object->lightDirn[0] = pLight->Direction.x;
2721 object->lightDirn[1] = pLight->Direction.y;
2722 object->lightDirn[2] = pLight->Direction.z;
2723 object->lightDirn[3] = 1.0;
2726 * opengl-ish and d3d-ish spot lights use too different models for the
2727 * light "intensity" as a function of the angle towards the main light direction,
2728 * so we only can approximate very roughly.
2729 * however spot lights are rather rarely used in games (if ever used at all).
2730 * furthermore if still used, probably nobody pays attention to such details.
2732 if (pLight->Falloff == 0) {
2733 rho = 6.28f;
2734 } else {
2735 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2737 if (rho < 0.0001) rho = 0.0001f;
2738 object->exponent = -0.3/log(cos(rho/2));
2739 object->cutoff = pLight->Phi*90/M_PI;
2741 /* FIXME: Range */
2742 break;
2744 default:
2745 FIXME("Unrecognized light type %d\n", pLight->Type);
2748 /* Update the live definitions if the light is currently assigned a glIndex */
2749 if (object->glIndex != -1) {
2750 setup_light(iface, object->glIndex, object);
2752 return WINED3D_OK;
2755 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2756 PLIGHTINFOEL *lightInfo = NULL;
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2760 /* Locate the light in the live lights */
2761 lightInfo = This->stateBlock->lights;
2762 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2764 if (lightInfo == NULL) {
2765 TRACE("Light information requested but light not defined\n");
2766 return WINED3DERR_INVALIDCALL;
2769 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2770 return WINED3D_OK;
2773 /*****
2774 * Get / Set Light Enable
2775 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2776 *****/
2777 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2778 PLIGHTINFOEL *lightInfo = NULL;
2779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2782 /* Tests show true = 128...not clear why */
2784 Enable = Enable? 128: 0;
2786 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2787 if (This->isRecordingState) {
2788 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2789 if (NULL == lightInfo) {
2790 return WINED3DERR_OUTOFVIDEOMEMORY;
2792 lightInfo->OriginalIndex = Index;
2793 lightInfo->glIndex = -1;
2794 lightInfo->enabledChanged = TRUE;
2795 lightInfo->lightEnabled = Enable;
2797 /* Add to the END of the chain of lights changes to be replayed */
2798 if (This->updateStateBlock->lights == NULL) {
2799 This->updateStateBlock->lights = lightInfo;
2800 } else {
2801 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2802 while (temp->next != NULL) temp=temp->next;
2803 temp->next = lightInfo;
2805 TRACE("Recording... not performing anything more\n");
2806 return WINED3D_OK;
2809 /* Not recording... So, locate the light in the live lights */
2810 lightInfo = This->stateBlock->lights;
2811 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2813 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2814 if (lightInfo == NULL) {
2816 TRACE("Light enabled requested but light not defined, so defining one!\n");
2817 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2819 /* Search for it again! Should be fairly quick as near head of list */
2820 lightInfo = This->stateBlock->lights;
2821 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2822 if (lightInfo == NULL) {
2823 FIXME("Adding default lights has failed dismally\n");
2824 return WINED3DERR_INVALIDCALL;
2828 /* OK, we now have a light... */
2829 if (Enable == FALSE) {
2831 /* If we are disabling it, check it was enabled, and
2832 still only do something if it has assigned a glIndex (which it should have!) */
2833 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2834 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2835 ENTER_GL();
2836 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2837 checkGLcall("glDisable GL_LIGHT0+Index");
2838 LEAVE_GL();
2839 } else {
2840 TRACE("Nothing to do as light was not enabled\n");
2842 lightInfo->lightEnabled = Enable;
2843 } else {
2845 /* We are enabling it. If it is enabled, it's really simple */
2846 if (lightInfo->lightEnabled) {
2847 /* nop */
2848 TRACE("Nothing to do as light was enabled\n");
2850 /* If it already has a glIndex, it's still simple */
2851 } else if (lightInfo->glIndex != -1) {
2852 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2853 lightInfo->lightEnabled = Enable;
2854 ENTER_GL();
2855 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2856 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2857 LEAVE_GL();
2859 /* Otherwise got to find space - lights are ordered gl indexes first */
2860 } else {
2861 PLIGHTINFOEL *bsf = NULL;
2862 PLIGHTINFOEL *pos = This->stateBlock->lights;
2863 PLIGHTINFOEL *prev = NULL;
2864 int Index= 0;
2865 int glIndex = -1;
2867 /* Try to minimize changes as much as possible */
2868 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2870 /* Try to remember which index can be replaced if necessary */
2871 if (bsf==NULL && pos->lightEnabled == FALSE) {
2872 /* Found a light we can replace, save as best replacement */
2873 bsf = pos;
2876 /* Step to next space */
2877 prev = pos;
2878 pos = pos->next;
2879 Index ++;
2882 /* If we have too many active lights, fail the call */
2883 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2884 FIXME("Program requests too many concurrent lights\n");
2885 return WINED3DERR_INVALIDCALL;
2887 /* If we have allocated all lights, but not all are enabled,
2888 reuse one which is not enabled */
2889 } else if (Index == This->maxConcurrentLights) {
2890 /* use bsf - Simply swap the new light and the BSF one */
2891 PLIGHTINFOEL *bsfNext = bsf->next;
2892 PLIGHTINFOEL *bsfPrev = bsf->prev;
2894 /* Sort out ends */
2895 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2896 if (bsf->prev != NULL) {
2897 bsf->prev->next = lightInfo;
2898 } else {
2899 This->stateBlock->lights = lightInfo;
2902 /* If not side by side, lots of chains to update */
2903 if (bsf->next != lightInfo) {
2904 lightInfo->prev->next = bsf;
2905 bsf->next->prev = lightInfo;
2906 bsf->next = lightInfo->next;
2907 bsf->prev = lightInfo->prev;
2908 lightInfo->next = bsfNext;
2909 lightInfo->prev = bsfPrev;
2911 } else {
2912 /* Simple swaps */
2913 bsf->prev = lightInfo;
2914 bsf->next = lightInfo->next;
2915 lightInfo->next = bsf;
2916 lightInfo->prev = bsfPrev;
2920 /* Update states */
2921 glIndex = bsf->glIndex;
2922 bsf->glIndex = -1;
2923 lightInfo->glIndex = glIndex;
2924 lightInfo->lightEnabled = Enable;
2926 /* Finally set up the light in gl itself */
2927 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2928 ENTER_GL();
2929 setup_light(iface, glIndex, lightInfo);
2930 glEnable(GL_LIGHT0 + glIndex);
2931 checkGLcall("glEnable GL_LIGHT0 new setup");
2932 LEAVE_GL();
2934 /* If we reached the end of the allocated lights, with space in the
2935 gl lights, setup a new light */
2936 } else if (pos->glIndex == -1) {
2938 /* We reached the end of the allocated gl lights, so already
2939 know the index of the next one! */
2940 glIndex = Index;
2941 lightInfo->glIndex = glIndex;
2942 lightInfo->lightEnabled = Enable;
2944 /* In an ideal world, it's already in the right place */
2945 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2946 /* No need to move it */
2947 } else {
2948 /* Remove this light from the list */
2949 lightInfo->prev->next = lightInfo->next;
2950 if (lightInfo->next != NULL) {
2951 lightInfo->next->prev = lightInfo->prev;
2954 /* Add in at appropriate place (inbetween prev and pos) */
2955 lightInfo->prev = prev;
2956 lightInfo->next = pos;
2957 if (prev == NULL) {
2958 This->stateBlock->lights = lightInfo;
2959 } else {
2960 prev->next = lightInfo;
2962 if (pos != NULL) {
2963 pos->prev = lightInfo;
2967 /* Finally set up the light in gl itself */
2968 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2969 ENTER_GL();
2970 setup_light(iface, glIndex, lightInfo);
2971 glEnable(GL_LIGHT0 + glIndex);
2972 checkGLcall("glEnable GL_LIGHT0 new setup");
2973 LEAVE_GL();
2978 return WINED3D_OK;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2983 PLIGHTINFOEL *lightInfo = NULL;
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 TRACE("(%p) : for idx(%ld)\n", This, Index);
2987 /* Locate the light in the live lights */
2988 lightInfo = This->stateBlock->lights;
2989 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2991 if (lightInfo == NULL) {
2992 TRACE("Light enabled state requested but light not defined\n");
2993 return WINED3DERR_INVALIDCALL;
2995 *pEnable = lightInfo->lightEnabled;
2996 return WINED3D_OK;
2999 /*****
3000 * Get / Set Clip Planes
3001 *****/
3002 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3006 /* Validate Index */
3007 if (Index >= GL_LIMITS(clipplanes)) {
3008 TRACE("Application has requested clipplane this device doesn't support\n");
3009 return WINED3DERR_INVALIDCALL;
3012 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3013 This->updateStateBlock->set.clipplane[Index] = TRUE;
3014 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3015 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3016 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3017 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3019 /* Handle recording of state blocks */
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3025 /* Apply it */
3027 ENTER_GL();
3029 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3030 glMatrixMode(GL_MODELVIEW);
3031 glPushMatrix();
3032 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3034 TRACE("Clipplane [%f,%f,%f,%f]\n",
3035 This->updateStateBlock->clipplane[Index][0],
3036 This->updateStateBlock->clipplane[Index][1],
3037 This->updateStateBlock->clipplane[Index][2],
3038 This->updateStateBlock->clipplane[Index][3]);
3039 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3040 checkGLcall("glClipPlane");
3042 glPopMatrix();
3043 LEAVE_GL();
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 TRACE("(%p) : for idx %ld\n", This, Index);
3052 /* Validate Index */
3053 if (Index >= GL_LIMITS(clipplanes)) {
3054 TRACE("Application has requested clipplane this device doesn't support\n");
3055 return WINED3DERR_INVALIDCALL;
3058 pPlane[0] = This->stateBlock->clipplane[Index][0];
3059 pPlane[1] = This->stateBlock->clipplane[Index][1];
3060 pPlane[2] = This->stateBlock->clipplane[Index][2];
3061 pPlane[3] = This->stateBlock->clipplane[Index][3];
3062 return WINED3D_OK;
3065 /*****
3066 * Get / Set Clip Plane Status
3067 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3068 *****/
3069 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 FIXME("(%p) : stub\n", This);
3072 if (NULL == pClipStatus) {
3073 return WINED3DERR_INVALIDCALL;
3075 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3076 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 FIXME("(%p) : stub\n", This);
3083 if (NULL == pClipStatus) {
3084 return WINED3DERR_INVALIDCALL;
3086 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3087 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3088 return WINED3D_OK;
3091 /*****
3092 * Get / Set Material
3093 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3094 *****/
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 This->updateStateBlock->changed.material = TRUE;
3099 This->updateStateBlock->set.material = TRUE;
3100 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3102 /* Handle recording of state blocks */
3103 if (This->isRecordingState) {
3104 TRACE("Recording... not performing anything\n");
3105 return WINED3D_OK;
3108 ENTER_GL();
3109 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3110 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3111 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3112 pMaterial->Ambient.b, pMaterial->Ambient.a);
3113 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3114 pMaterial->Specular.b, pMaterial->Specular.a);
3115 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3116 pMaterial->Emissive.b, pMaterial->Emissive.a);
3117 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3119 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3120 checkGLcall("glMaterialfv(GL_AMBIENT)");
3121 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3122 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3124 /* Only change material color if specular is enabled, otherwise it is set to black */
3125 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3126 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3127 checkGLcall("glMaterialfv(GL_SPECULAR");
3128 } else {
3129 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3130 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3131 checkGLcall("glMaterialfv(GL_SPECULAR");
3133 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3134 checkGLcall("glMaterialfv(GL_EMISSION)");
3135 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3136 checkGLcall("glMaterialf(GL_SHININESS");
3138 LEAVE_GL();
3139 return WINED3D_OK;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3145 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3146 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3147 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3148 pMaterial->Ambient.b, pMaterial->Ambient.a);
3149 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3150 pMaterial->Specular.b, pMaterial->Specular.a);
3151 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3152 pMaterial->Emissive.b, pMaterial->Emissive.a);
3153 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3155 return WINED3D_OK;
3158 /*****
3159 * Get / Set Indices
3160 *****/
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3162 UINT BaseVertexIndex) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 IWineD3DIndexBuffer *oldIdxs;
3166 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3167 oldIdxs = This->updateStateBlock->pIndexData;
3169 This->updateStateBlock->changed.indices = TRUE;
3170 This->updateStateBlock->set.indices = TRUE;
3171 This->updateStateBlock->pIndexData = pIndexData;
3172 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3174 /* Handle recording of state blocks */
3175 if (This->isRecordingState) {
3176 TRACE("Recording... not performing anything\n");
3177 return WINED3D_OK;
3180 if (NULL != pIndexData) {
3181 IWineD3DIndexBuffer_AddRef(pIndexData);
3183 if (NULL != oldIdxs) {
3184 IWineD3DIndexBuffer_Release(oldIdxs);
3186 return WINED3D_OK;
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 *ppIndexData = This->stateBlock->pIndexData;
3194 /* up ref count on ppindexdata */
3195 if (*ppIndexData) {
3196 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3197 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3198 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3199 }else{
3200 TRACE("(%p) No index data set\n", This);
3202 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3204 return WINED3D_OK;
3207 /*****
3208 * Get / Set Viewports
3209 *****/
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 TRACE("(%p)\n", This);
3214 This->updateStateBlock->changed.viewport = TRUE;
3215 This->updateStateBlock->set.viewport = TRUE;
3216 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3218 /* Handle recording of state blocks */
3219 if (This->isRecordingState) {
3220 TRACE("Recording... not performing anything\n");
3221 return WINED3D_OK;
3223 This->viewport_changed = TRUE;
3225 ENTER_GL();
3227 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3228 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3230 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3231 checkGLcall("glDepthRange");
3232 /* Note: GL requires lower left, DirectX supplies upper left */
3233 /* TODO: replace usage of renderTarget with context management */
3234 glViewport(pViewport->X,
3235 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3236 pViewport->Width, pViewport->Height);
3238 checkGLcall("glViewport");
3240 LEAVE_GL();
3242 return WINED3D_OK;
3246 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 TRACE("(%p)\n", This);
3249 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3250 return WINED3D_OK;
3253 static void renderstate_stencil_twosided(
3254 IWineD3DDeviceImpl *This,
3255 GLint face,
3256 GLint func,
3257 GLint ref,
3258 GLuint mask,
3259 GLint stencilFail,
3260 GLint depthFail,
3261 GLint stencilPass ) {
3262 #if 0 /* Don't use OpenGL 2.0 calls for now */
3263 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3264 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3265 checkGLcall("glStencilFuncSeparate(...)");
3266 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3267 checkGLcall("glStencilOpSeparate(...)");
3269 else
3270 #endif
3271 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3272 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3273 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3274 GL_EXTCALL(glActiveStencilFaceEXT(face));
3275 checkGLcall("glActiveStencilFaceEXT(...)");
3276 glStencilFunc(func, ref, mask);
3277 checkGLcall("glStencilFunc(...)");
3278 glStencilOp(stencilFail, depthFail, stencilPass);
3279 checkGLcall("glStencilOp(...)");
3280 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3281 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3282 checkGLcall("glStencilFuncSeparateATI(...)");
3283 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3284 checkGLcall("glStencilOpSeparateATI(...)");
3285 } else {
3286 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3290 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3291 DWORD onesided_enable = FALSE;
3292 DWORD twosided_enable = FALSE;
3293 GLint func = GL_ALWAYS;
3294 GLint func_ccw = GL_ALWAYS;
3295 GLint ref = 0;
3296 GLuint mask = 0;
3297 GLint stencilFail = GL_KEEP;
3298 GLint depthFail = GL_KEEP;
3299 GLint stencilPass = GL_KEEP;
3300 GLint stencilFail_ccw = GL_KEEP;
3301 GLint depthFail_ccw = GL_KEEP;
3302 GLint stencilPass_ccw = GL_KEEP;
3304 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3305 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3306 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3307 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3308 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3309 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3310 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3311 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3312 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3313 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3314 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3315 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3316 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3317 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3318 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3319 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3320 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3321 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3322 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3323 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3324 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3325 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3326 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3327 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3329 switch(State) {
3330 case WINED3DRS_STENCILENABLE :
3331 onesided_enable = Value;
3332 break;
3333 case WINED3DRS_TWOSIDEDSTENCILMODE :
3334 twosided_enable = Value;
3335 break;
3336 case WINED3DRS_STENCILFUNC :
3337 func = StencilFunc(Value);
3338 break;
3339 case WINED3DRS_CCW_STENCILFUNC :
3340 func_ccw = StencilFunc(Value);
3341 break;
3342 case WINED3DRS_STENCILREF :
3343 ref = Value;
3344 break;
3345 case WINED3DRS_STENCILMASK :
3346 mask = Value;
3347 break;
3348 case WINED3DRS_STENCILFAIL :
3349 stencilFail = StencilOp(Value);
3350 break;
3351 case WINED3DRS_STENCILZFAIL :
3352 depthFail = StencilOp(Value);
3353 break;
3354 case WINED3DRS_STENCILPASS :
3355 stencilPass = StencilOp(Value);
3356 break;
3357 case WINED3DRS_CCW_STENCILFAIL :
3358 stencilFail_ccw = StencilOp(Value);
3359 break;
3360 case WINED3DRS_CCW_STENCILZFAIL :
3361 depthFail_ccw = StencilOp(Value);
3362 break;
3363 case WINED3DRS_CCW_STENCILPASS :
3364 stencilPass_ccw = StencilOp(Value);
3365 break;
3366 default :
3367 ERR("This should not happen!");
3370 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3371 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3372 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3373 onesided_enable, twosided_enable, ref, mask,
3374 func, stencilFail, depthFail, stencilPass,
3375 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3377 if (twosided_enable) {
3378 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3379 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3380 } else {
3381 if (onesided_enable) {
3382 glEnable(GL_STENCIL_TEST);
3383 checkGLcall("glEnable GL_STENCIL_TEST");
3384 glStencilFunc(func, ref, mask);
3385 checkGLcall("glStencilFunc(...)");
3386 glStencilOp(stencilFail, depthFail, stencilPass);
3387 checkGLcall("glStencilOp(...)");
3388 } else {
3389 glDisable(GL_STENCIL_TEST);
3390 checkGLcall("glDisable GL_STENCIL_TEST");
3395 /*****
3396 * Get / Set Render States
3397 * TODO: Verify against dx9 definitions
3398 *****/
3399 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3402 DWORD OldValue = This->stateBlock->renderState[State];
3404 /* Simple way of referring to either a DWORD or a 4 byte float */
3405 union {
3406 DWORD d;
3407 float f;
3408 } tmpvalue;
3410 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3411 This->updateStateBlock->changed.renderState[State] = TRUE;
3412 This->updateStateBlock->set.renderState[State] = TRUE;
3413 This->updateStateBlock->renderState[State] = Value;
3415 /* Handle recording of state blocks */
3416 if (This->isRecordingState) {
3417 TRACE("Recording... not performing anything\n");
3418 return WINED3D_OK;
3421 ENTER_GL();
3423 switch (State) {
3424 case WINED3DRS_FILLMODE :
3425 switch ((D3DFILLMODE) Value) {
3426 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3427 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3428 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3429 default:
3430 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3432 checkGLcall("glPolygonMode (fillmode)");
3433 break;
3435 case WINED3DRS_LIGHTING :
3436 if (Value) {
3437 glEnable(GL_LIGHTING);
3438 checkGLcall("glEnable GL_LIGHTING");
3439 } else {
3440 glDisable(GL_LIGHTING);
3441 checkGLcall("glDisable GL_LIGHTING");
3443 break;
3445 case WINED3DRS_ZENABLE :
3446 switch ((D3DZBUFFERTYPE) Value) {
3447 case D3DZB_FALSE:
3448 glDisable(GL_DEPTH_TEST);
3449 checkGLcall("glDisable GL_DEPTH_TEST");
3450 break;
3451 case D3DZB_TRUE:
3452 glEnable(GL_DEPTH_TEST);
3453 checkGLcall("glEnable GL_DEPTH_TEST");
3454 break;
3455 case D3DZB_USEW:
3456 glEnable(GL_DEPTH_TEST);
3457 checkGLcall("glEnable GL_DEPTH_TEST");
3458 FIXME("W buffer is not well handled\n");
3459 break;
3460 default:
3461 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3463 break;
3465 case WINED3DRS_CULLMODE :
3467 /* If we are culling "back faces with clockwise vertices" then
3468 set front faces to be counter clockwise and enable culling
3469 of back faces */
3470 switch ((D3DCULL) Value) {
3471 case D3DCULL_NONE:
3472 glDisable(GL_CULL_FACE);
3473 checkGLcall("glDisable GL_CULL_FACE");
3474 break;
3475 case D3DCULL_CW:
3476 glEnable(GL_CULL_FACE);
3477 checkGLcall("glEnable GL_CULL_FACE");
3478 if (This->renderUpsideDown) {
3479 glFrontFace(GL_CW);
3480 checkGLcall("glFrontFace GL_CW");
3481 } else {
3482 glFrontFace(GL_CCW);
3483 checkGLcall("glFrontFace GL_CCW");
3485 glCullFace(GL_BACK);
3486 break;
3487 case D3DCULL_CCW:
3488 glEnable(GL_CULL_FACE);
3489 checkGLcall("glEnable GL_CULL_FACE");
3490 if (This->renderUpsideDown) {
3491 glFrontFace(GL_CCW);
3492 checkGLcall("glFrontFace GL_CCW");
3493 } else {
3494 glFrontFace(GL_CW);
3495 checkGLcall("glFrontFace GL_CW");
3497 glCullFace(GL_BACK);
3498 break;
3499 default:
3500 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3502 break;
3504 case WINED3DRS_SHADEMODE :
3505 switch ((D3DSHADEMODE) Value) {
3506 case D3DSHADE_FLAT:
3507 glShadeModel(GL_FLAT);
3508 checkGLcall("glShadeModel");
3509 break;
3510 case D3DSHADE_GOURAUD:
3511 glShadeModel(GL_SMOOTH);
3512 checkGLcall("glShadeModel");
3513 break;
3514 case D3DSHADE_PHONG:
3515 FIXME("D3DSHADE_PHONG isn't supported\n");
3516 break;
3517 default:
3518 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3520 break;
3522 case WINED3DRS_DITHERENABLE :
3523 if (Value) {
3524 glEnable(GL_DITHER);
3525 checkGLcall("glEnable GL_DITHER");
3526 } else {
3527 glDisable(GL_DITHER);
3528 checkGLcall("glDisable GL_DITHER");
3530 break;
3532 case WINED3DRS_ZWRITEENABLE :
3533 if (Value) {
3534 glDepthMask(1);
3535 checkGLcall("glDepthMask");
3536 } else {
3537 glDepthMask(0);
3538 checkGLcall("glDepthMask");
3540 break;
3542 case WINED3DRS_ZFUNC :
3544 int glParm = GL_LESS;
3546 switch ((D3DCMPFUNC) Value) {
3547 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3548 case D3DCMP_LESS: glParm=GL_LESS; break;
3549 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3550 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3551 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3552 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3553 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3554 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3555 default:
3556 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3558 glDepthFunc(glParm);
3559 checkGLcall("glDepthFunc");
3561 break;
3563 case WINED3DRS_AMBIENT :
3565 float col[4];
3566 D3DCOLORTOGLFLOAT4(Value, col);
3567 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3568 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3569 checkGLcall("glLightModel for MODEL_AMBIENT");
3572 break;
3574 case WINED3DRS_ALPHABLENDENABLE :
3575 if (Value) {
3576 glEnable(GL_BLEND);
3577 checkGLcall("glEnable GL_BLEND");
3578 } else {
3579 glDisable(GL_BLEND);
3580 checkGLcall("glDisable GL_BLEND");
3582 break;
3584 case WINED3DRS_SRCBLEND :
3585 case WINED3DRS_DESTBLEND :
3587 int newVal = GL_ZERO;
3588 switch (Value) {
3589 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3590 case D3DBLEND_ONE : newVal = GL_ONE; break;
3591 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3592 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3593 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3594 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3595 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3596 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3597 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3598 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3599 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3601 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3602 This->srcBlend = newVal;
3603 This->dstBlend = newVal;
3604 break;
3606 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3607 This->srcBlend = newVal;
3608 This->dstBlend = newVal;
3609 break;
3610 default:
3611 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3614 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3615 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3616 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3617 glBlendFunc(This->srcBlend, This->dstBlend);
3619 checkGLcall("glBlendFunc");
3621 break;
3623 case WINED3DRS_ALPHATESTENABLE :
3624 case WINED3DRS_ALPHAFUNC :
3625 case WINED3DRS_ALPHAREF :
3626 case WINED3DRS_COLORKEYENABLE :
3628 int glParm = 0.0;
3629 float ref = GL_LESS;
3630 BOOL enable_ckey = FALSE;
3632 IWineD3DSurfaceImpl *surf;
3634 /* Find out if the texture on the first stage has a ckey set */
3635 if(This->stateBlock->textures[0]) {
3636 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3637 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3640 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3641 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3642 glEnable(GL_ALPHA_TEST);
3643 checkGLcall("glEnable GL_ALPHA_TEST");
3644 } else {
3645 glDisable(GL_ALPHA_TEST);
3646 checkGLcall("glDisable GL_ALPHA_TEST");
3647 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3648 * enable call
3650 break;
3653 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3654 glParm = GL_NOTEQUAL;
3655 ref = 0.0;
3656 } else {
3657 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3659 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3660 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3661 case D3DCMP_LESS: glParm = GL_LESS; break;
3662 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3663 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3664 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3665 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3666 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3667 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3668 default:
3669 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3672 This->alphafunc = glParm;
3673 glAlphaFunc(glParm, ref);
3674 checkGLcall("glAlphaFunc");
3676 break;
3678 case WINED3DRS_CLIPPLANEENABLE :
3679 case WINED3DRS_CLIPPING :
3681 /* Ensure we only do the changed clip planes */
3682 DWORD enable = 0xFFFFFFFF;
3683 DWORD disable = 0x00000000;
3685 /* If enabling / disabling all */
3686 if (State == WINED3DRS_CLIPPING) {
3687 if (Value) {
3688 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3689 disable = 0x00;
3690 } else {
3691 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3692 enable = 0x00;
3694 } else {
3695 enable = Value & ~OldValue;
3696 disable = ~Value & OldValue;
3699 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3700 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3701 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3702 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3703 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3704 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3706 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3707 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3708 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3709 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3710 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3711 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3713 /** update clipping status */
3714 if (enable) {
3715 This->stateBlock->clip_status.ClipUnion = 0;
3716 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3717 } else {
3718 This->stateBlock->clip_status.ClipUnion = 0;
3719 This->stateBlock->clip_status.ClipIntersection = 0;
3722 break;
3724 case WINED3DRS_BLENDOP :
3726 int glParm = GL_FUNC_ADD;
3728 switch ((D3DBLENDOP) Value) {
3729 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3730 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3731 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3732 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3733 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3734 default:
3735 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3738 if(GL_SUPPORT(ARB_IMAGING)) {
3739 TRACE("glBlendEquation(%x)\n", glParm);
3740 GL_EXTCALL(glBlendEquation(glParm));
3741 checkGLcall("glBlendEquation");
3742 } else {
3743 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3746 break;
3748 case WINED3DRS_TEXTUREFACTOR :
3750 unsigned int i;
3752 /* Note the texture color applies to all textures whereas
3753 GL_TEXTURE_ENV_COLOR applies to active only */
3754 float col[4];
3755 D3DCOLORTOGLFLOAT4(Value, col);
3756 /* Set the default alpha blend color */
3757 if (GL_SUPPORT(ARB_IMAGING)) {
3758 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3759 checkGLcall("glBlendColor");
3760 } else {
3761 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3764 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3765 /* And now the default texture color as well */
3766 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3767 /* Note the D3DRS value applies to all textures, but GL has one
3768 per texture, so apply it now ready to be used! */
3769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3770 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3771 checkGLcall("glActiveTextureARB");
3772 } else if (i>0) {
3773 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3776 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3777 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3781 break;
3783 case WINED3DRS_SPECULARENABLE :
3785 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3786 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3787 specular color. This is wrong:
3788 Separate specular color means the specular colour is maintained separately, whereas
3789 single color means it is merged in. However in both cases they are being used to
3790 some extent.
3791 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3792 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3793 running 1.4 yet!
3796 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3797 * Instead, we need to setup the FinalCombiner properly.
3799 * The default setup for the FinalCombiner is:
3801 * <variable> <input> <mapping> <usage>
3802 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3803 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3804 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3805 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3806 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3807 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3808 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3810 * That's pretty much fine as it is, except for variable B, which needs to take
3811 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3812 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3815 if (Value) {
3816 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3817 checkGLcall("glMaterialfv");
3818 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3819 glEnable(GL_COLOR_SUM_EXT);
3820 } else {
3821 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3823 checkGLcall("glEnable(GL_COLOR_SUM)");
3825 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3826 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3827 checkGLcall("glFinalCombinerInputNV()");
3829 } else {
3830 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3832 /* for the case of enabled lighting: */
3833 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3834 checkGLcall("glMaterialfv");
3836 /* for the case of disabled lighting: */
3837 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3838 glDisable(GL_COLOR_SUM_EXT);
3839 } else {
3840 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3842 checkGLcall("glDisable(GL_COLOR_SUM)");
3844 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3845 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3846 checkGLcall("glFinalCombinerInputNV()");
3850 break;
3852 case WINED3DRS_STENCILENABLE :
3853 case WINED3DRS_TWOSIDEDSTENCILMODE :
3854 case WINED3DRS_STENCILFUNC :
3855 case WINED3DRS_CCW_STENCILFUNC :
3856 case WINED3DRS_STENCILREF :
3857 case WINED3DRS_STENCILMASK :
3858 case WINED3DRS_STENCILFAIL :
3859 case WINED3DRS_STENCILZFAIL :
3860 case WINED3DRS_STENCILPASS :
3861 case WINED3DRS_CCW_STENCILFAIL :
3862 case WINED3DRS_CCW_STENCILZFAIL :
3863 case WINED3DRS_CCW_STENCILPASS :
3864 renderstate_stencil(This, State, Value);
3865 break;
3866 case WINED3DRS_STENCILWRITEMASK :
3868 glStencilMask(Value);
3869 TRACE("glStencilMask(%lu)\n", Value);
3870 checkGLcall("glStencilMask");
3872 break;
3874 case WINED3DRS_FOGENABLE :
3876 if (Value) {
3877 glEnable(GL_FOG);
3878 checkGLcall("glEnable GL_FOG");
3879 } else {
3880 glDisable(GL_FOG);
3881 checkGLcall("glDisable GL_FOG");
3884 break;
3886 case WINED3DRS_RANGEFOGENABLE :
3888 if (Value) {
3889 TRACE("Enabled RANGEFOG\n");
3890 } else {
3891 TRACE("Disabled RANGEFOG\n");
3894 break;
3896 case WINED3DRS_FOGCOLOR :
3898 float col[4];
3899 D3DCOLORTOGLFLOAT4(Value, col);
3900 /* Set the default alpha blend color */
3901 glFogfv(GL_FOG_COLOR, &col[0]);
3902 checkGLcall("glFog GL_FOG_COLOR");
3904 break;
3906 case WINED3DRS_FOGTABLEMODE :
3907 case WINED3DRS_FOGVERTEXMODE :
3909 /* 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." */
3910 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3911 glHint(GL_FOG_HINT, GL_FASTEST);
3912 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3913 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3914 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3915 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3917 case D3DFOG_EXP: {
3918 if(!This->last_was_rhw) {
3919 glFogi(GL_FOG_MODE, GL_EXP);
3920 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3921 if(GL_SUPPORT(EXT_FOG_COORD)) {
3922 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3923 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3924 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3925 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3927 break;
3930 case D3DFOG_EXP2: {
3931 if(!This->last_was_rhw) {
3932 glFogi(GL_FOG_MODE, GL_EXP2);
3933 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3934 if(GL_SUPPORT(EXT_FOG_COORD)) {
3935 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3936 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3937 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3938 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3940 break;
3943 case D3DFOG_LINEAR: {
3944 if(!This->last_was_rhw) {
3945 glFogi(GL_FOG_MODE, GL_LINEAR);
3946 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3947 if(GL_SUPPORT(EXT_FOG_COORD)) {
3948 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3949 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3950 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3951 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3953 break;
3956 case D3DFOG_NONE: {
3957 /* Both are none? According to msdn the alpha channel of the specular
3958 * color contains a fog factor. Set it in drawStridedSlow.
3959 * Same happens with Vertexfog on transformed vertices
3961 if(GL_SUPPORT(EXT_FOG_COORD)) {
3962 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3963 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3964 glFogi(GL_FOG_MODE, GL_LINEAR);
3965 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3966 glFogf(GL_FOG_START, (float) 0xff);
3967 checkGLcall("glFogfv GL_FOG_START");
3968 glFogf(GL_FOG_END, 0.0);
3969 checkGLcall("glFogfv GL_FOG_END");
3970 } else {
3971 /* Disable GL fog, handle this in software in drawStridedSlow */
3972 glDisable(GL_FOG);
3973 checkGLcall("glDisable(GL_FOG)");
3975 break;
3977 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3979 } else {
3980 glHint(GL_FOG_HINT, GL_NICEST);
3981 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3982 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3983 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3984 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3985 if(GL_SUPPORT(EXT_FOG_COORD)) {
3986 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3987 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3989 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3991 break;
3992 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3993 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3994 if(GL_SUPPORT(EXT_FOG_COORD)) {
3995 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3996 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3997 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3998 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4000 break;
4001 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4002 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4003 if(GL_SUPPORT(EXT_FOG_COORD)) {
4004 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4005 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4006 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4007 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4009 break;
4010 case D3DFOG_NONE: /* Won't happen */
4011 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4014 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4015 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4018 break;
4020 case WINED3DRS_FOGSTART :
4022 tmpvalue.d = Value;
4023 glFogfv(GL_FOG_START, &tmpvalue.f);
4024 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4025 TRACE("Fog Start == %f\n", tmpvalue.f);
4027 break;
4029 case WINED3DRS_FOGEND :
4031 tmpvalue.d = Value;
4032 glFogfv(GL_FOG_END, &tmpvalue.f);
4033 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4034 TRACE("Fog End == %f\n", tmpvalue.f);
4036 break;
4038 case WINED3DRS_FOGDENSITY :
4040 tmpvalue.d = Value;
4041 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4042 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4044 break;
4046 case WINED3DRS_VERTEXBLEND :
4048 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4049 TRACE("Vertex Blending state to %ld\n", Value);
4051 break;
4053 case WINED3DRS_TWEENFACTOR :
4055 tmpvalue.d = Value;
4056 This->updateStateBlock->tween_factor = tmpvalue.f;
4057 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4059 break;
4061 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4063 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4065 break;
4067 case WINED3DRS_COLORVERTEX :
4068 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4069 case WINED3DRS_SPECULARMATERIALSOURCE :
4070 case WINED3DRS_AMBIENTMATERIALSOURCE :
4071 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4073 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4075 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4076 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4077 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4078 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4079 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4080 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4082 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4083 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4084 Parm = GL_AMBIENT_AND_DIFFUSE;
4085 } else {
4086 Parm = GL_DIFFUSE;
4088 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4089 Parm = GL_AMBIENT;
4090 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4091 Parm = GL_EMISSION;
4092 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4093 Parm = GL_SPECULAR;
4094 } else {
4095 Parm = -1;
4098 if (Parm == -1) {
4099 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4100 } else {
4101 This->tracking_color = NEEDS_TRACKING;
4102 This->tracking_parm = Parm;
4105 } else {
4106 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4109 break;
4111 case WINED3DRS_LINEPATTERN :
4113 union {
4114 DWORD d;
4115 D3DLINEPATTERN lp;
4116 } tmppattern;
4117 tmppattern.d = Value;
4119 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4121 if (tmppattern.lp.wRepeatFactor) {
4122 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4123 checkGLcall("glLineStipple(repeat, linepattern)");
4124 glEnable(GL_LINE_STIPPLE);
4125 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4126 } else {
4127 glDisable(GL_LINE_STIPPLE);
4128 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4131 break;
4133 case WINED3DRS_ZBIAS : /* D3D8 only */
4135 if (Value) {
4136 tmpvalue.d = Value;
4137 TRACE("ZBias value %f\n", tmpvalue.f);
4138 glPolygonOffset(0, -tmpvalue.f);
4139 checkGLcall("glPolygonOffset(0, -Value)");
4140 glEnable(GL_POLYGON_OFFSET_FILL);
4141 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4142 glEnable(GL_POLYGON_OFFSET_LINE);
4143 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4144 glEnable(GL_POLYGON_OFFSET_POINT);
4145 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4146 } else {
4147 glDisable(GL_POLYGON_OFFSET_FILL);
4148 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4149 glDisable(GL_POLYGON_OFFSET_LINE);
4150 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4151 glDisable(GL_POLYGON_OFFSET_POINT);
4152 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4155 break;
4157 case WINED3DRS_NORMALIZENORMALS :
4158 if (Value) {
4159 glEnable(GL_NORMALIZE);
4160 checkGLcall("glEnable(GL_NORMALIZE);");
4161 } else {
4162 glDisable(GL_NORMALIZE);
4163 checkGLcall("glDisable(GL_NORMALIZE);");
4165 break;
4167 case WINED3DRS_POINTSIZE :
4168 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4169 tmpvalue.d = Value;
4170 TRACE("Set point size to %f\n", tmpvalue.f);
4171 glPointSize(tmpvalue.f);
4172 checkGLcall("glPointSize(...);");
4173 break;
4175 case WINED3DRS_POINTSIZE_MIN :
4176 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4177 tmpvalue.d = Value;
4178 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4179 checkGLcall("glPointParameterfEXT(...);");
4180 } else {
4181 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4183 break;
4185 case WINED3DRS_POINTSIZE_MAX :
4186 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4187 tmpvalue.d = Value;
4188 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4189 checkGLcall("glPointParameterfEXT(...);");
4190 } else {
4191 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4193 break;
4195 case WINED3DRS_POINTSCALE_A :
4196 case WINED3DRS_POINTSCALE_B :
4197 case WINED3DRS_POINTSCALE_C :
4198 case WINED3DRS_POINTSCALEENABLE :
4201 * POINTSCALEENABLE controls how point size value is treated. If set to
4202 * true, the point size is scaled with respect to height of viewport.
4203 * When set to false point size is in pixels.
4205 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4208 /* Default values */
4209 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4212 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4213 * This means that OpenGL will clamp really small point sizes to 1.0f.
4214 * To correct for this we need to multiply by the scale factor when sizes
4215 * are less than 1.0f. scale_factor = 1.0f / point_size.
4217 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4218 if(pointSize > 0.0f) {
4219 GLfloat scaleFactor;
4221 if(pointSize < 1.0f) {
4222 scaleFactor = pointSize * pointSize;
4223 } else {
4224 scaleFactor = 1.0f;
4227 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4228 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4229 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4230 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4231 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4232 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4233 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4237 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4238 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4239 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4241 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4242 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4243 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4244 } else {
4245 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4247 break;
4249 case WINED3DRS_COLORWRITEENABLE :
4251 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4252 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4253 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4254 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4255 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4256 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4257 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4258 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4259 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4260 checkGLcall("glColorMask(...)");
4262 break;
4264 case WINED3DRS_LOCALVIEWER :
4266 GLint state = (Value) ? 1 : 0;
4267 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4268 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4270 break;
4272 case WINED3DRS_LASTPIXEL :
4274 if (Value) {
4275 TRACE("Last Pixel Drawing Enabled\n");
4276 } else {
4277 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4280 break;
4282 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4284 if (Value) {
4285 TRACE("Software Processing Enabled\n");
4286 } else {
4287 TRACE("Software Processing Disabled\n");
4290 break;
4292 /** not supported */
4293 case WINED3DRS_ZVISIBLE :
4295 LEAVE_GL();
4296 return WINED3DERR_INVALIDCALL;
4298 case WINED3DRS_POINTSPRITEENABLE :
4300 /* TODO: NV_POINT_SPRITE */
4301 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4302 TRACE("Point sprites not supported\n");
4303 break;
4307 * Point sprites are always enabled. Value controls texture coordinate
4308 * replacement mode. Must be set true for point sprites to use
4309 * textures.
4311 glEnable(GL_POINT_SPRITE_ARB);
4312 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4314 if (Value) {
4315 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4316 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4317 } else {
4318 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4319 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4321 break;
4323 case WINED3DRS_EDGEANTIALIAS :
4325 if(Value) {
4326 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4327 glEnable(GL_BLEND);
4328 checkGLcall("glEnable(GL_BLEND)");
4329 glEnable(GL_LINE_SMOOTH);
4330 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4331 } else {
4332 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4333 glDisable(GL_BLEND);
4334 checkGLcall("glDisable(GL_BLEND)");
4336 glDisable(GL_LINE_SMOOTH);
4337 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4339 break;
4341 case WINED3DRS_WRAP0 :
4342 case WINED3DRS_WRAP1 :
4343 case WINED3DRS_WRAP2 :
4344 case WINED3DRS_WRAP3 :
4345 case WINED3DRS_WRAP4 :
4346 case WINED3DRS_WRAP5 :
4347 case WINED3DRS_WRAP6 :
4348 case WINED3DRS_WRAP7 :
4349 case WINED3DRS_WRAP8 :
4350 case WINED3DRS_WRAP9 :
4351 case WINED3DRS_WRAP10 :
4352 case WINED3DRS_WRAP11 :
4353 case WINED3DRS_WRAP12 :
4354 case WINED3DRS_WRAP13 :
4355 case WINED3DRS_WRAP14 :
4356 case WINED3DRS_WRAP15 :
4358 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4359 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4360 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4361 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4362 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4364 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4367 if(Value) {
4368 ERR("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4370 break;
4373 case WINED3DRS_MULTISAMPLEANTIALIAS :
4375 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4376 if(Value) {
4377 glEnable(GL_MULTISAMPLE_ARB);
4378 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4379 } else {
4380 glDisable(GL_MULTISAMPLE_ARB);
4381 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4383 } else {
4384 if(Value) {
4385 ERR("Multisample antialiasing not supported by gl\n");
4388 break;
4391 case WINED3DRS_SCISSORTESTENABLE :
4393 if(Value) {
4394 glEnable(GL_SCISSOR_TEST);
4395 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4396 } else {
4397 glDisable(GL_SCISSOR_TEST);
4398 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4400 break;
4402 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4404 if(Value) {
4405 tmpvalue.d = Value;
4406 glEnable(GL_POLYGON_OFFSET_FILL);
4407 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4408 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4409 checkGLcall("glPolygonOffset(...)");
4410 } else {
4411 glDisable(GL_POLYGON_OFFSET_FILL);
4412 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4414 break;
4416 case WINED3DRS_ANTIALIASEDLINEENABLE :
4418 if(Value) {
4419 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4420 glEnable(GL_BLEND);
4421 checkGLcall("glEnable(GL_BLEND)");
4422 glEnable(GL_LINE_SMOOTH);
4423 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4424 } else {
4425 glDisable(GL_BLEND);
4426 checkGLcall("glDisable(GL_BLEND)");
4427 glDisable(GL_LINE_SMOOTH);
4428 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4430 break;
4432 case WINED3DRS_DEPTHBIAS :
4434 if(Value) {
4435 tmpvalue.d = Value;
4436 glEnable(GL_POLYGON_OFFSET_FILL);
4437 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4438 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4439 checkGLcall("glPolygonOffset(...)");
4440 } else {
4441 glDisable(GL_POLYGON_OFFSET_FILL);
4442 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4444 break;
4447 case WINED3DRS_TEXTUREPERSPECTIVE :
4449 if (Value)
4450 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4451 else
4452 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4453 break;
4456 case WINED3DRS_STIPPLEDALPHA :
4458 if (Value)
4459 ERR(" Stippled Alpha not supported yet.\n");
4460 break;
4462 case WINED3DRS_ANTIALIAS :
4464 if (Value)
4465 ERR(" Antialias not supported yet.\n");
4466 break;
4468 default:
4469 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4472 LEAVE_GL();
4474 return WINED3D_OK;
4477 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4479 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4480 *pValue = This->stateBlock->renderState[State];
4481 return WINED3D_OK;
4484 /*****
4485 * Get / Set Sampler States
4486 * TODO: Verify against dx9 definitions
4487 *****/
4489 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4492 * SetSampler is designed to allow for more than the standard up to 8 textures
4493 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4494 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4496 * http://developer.nvidia.com/object/General_FAQ.html#t6
4498 * There are two new settings for GForce
4499 * the sampler one:
4500 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4501 * and the texture one:
4502 * GL_MAX_TEXTURE_COORDS_ARB.
4503 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4504 ******************/
4505 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4506 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4507 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4508 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4509 return WINED3DERR_INVALIDCALL;
4512 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4513 debug_d3dsamplerstate(Type), Type, Value);
4514 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4515 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4516 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4518 /* Handle recording of state blocks */
4519 if (This->isRecordingState) {
4520 TRACE("Recording... not performing anything\n");
4521 return WINED3D_OK;
4524 return WINED3D_OK;
4527 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 /** TODO: check that sampler is in range **/
4530 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4531 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4533 return WINED3D_OK;
4536 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 ENTER_GL();
4540 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4541 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4542 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4543 LEAVE_GL();
4545 return WINED3D_OK;
4548 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4550 GLint scissorBox[4];
4552 ENTER_GL();
4553 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4554 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4555 pRect->left = scissorBox[0];
4556 pRect->top = scissorBox[1];
4557 pRect->right = scissorBox[0] + scissorBox[2];
4558 pRect->bottom = scissorBox[1] + scissorBox[3];
4559 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4560 LEAVE_GL();
4561 return WINED3D_OK;
4564 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4566 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4568 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4570 This->updateStateBlock->vertexDecl = pDecl;
4571 This->updateStateBlock->changed.vertexDecl = TRUE;
4572 This->updateStateBlock->set.vertexDecl = TRUE;
4574 if (This->isRecordingState) {
4575 TRACE("Recording... not performing anything\n");
4578 if (NULL != pDecl) {
4579 IWineD3DVertexDeclaration_AddRef(pDecl);
4581 if (NULL != oldDecl) {
4582 IWineD3DVertexDeclaration_Release(oldDecl);
4584 return WINED3D_OK;
4587 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4592 *ppDecl = This->stateBlock->vertexDecl;
4593 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4594 return WINED3D_OK;
4597 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4599 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4601 This->updateStateBlock->vertexShader = pShader;
4602 This->updateStateBlock->changed.vertexShader = TRUE;
4603 This->updateStateBlock->set.vertexShader = TRUE;
4605 if (This->isRecordingState) {
4606 TRACE("Recording... not performing anything\n");
4609 if (NULL != pShader) {
4610 IWineD3DVertexShader_AddRef(pShader);
4612 if (NULL != oldShader) {
4613 IWineD3DVertexShader_Release(oldShader);
4616 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4618 * TODO: merge HAL shaders context switching from prototype
4620 return WINED3D_OK;
4623 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 if (NULL == ppShader) {
4627 return WINED3DERR_INVALIDCALL;
4629 *ppShader = This->stateBlock->vertexShader;
4630 if( NULL != *ppShader)
4631 IWineD3DVertexShader_AddRef(*ppShader);
4633 TRACE("(%p) : returning %p\n", This, *ppShader);
4634 return WINED3D_OK;
4637 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4638 IWineD3DDevice *iface,
4639 UINT start,
4640 CONST BOOL *srcData,
4641 UINT count) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 int i, cnt = min(count, MAX_CONST_B - start);
4646 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4647 iface, srcData, start, count);
4649 if (srcData == NULL || cnt < 0)
4650 return WINED3DERR_INVALIDCALL;
4652 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4653 for (i = 0; i < cnt; i++)
4654 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4656 for (i = start; i < cnt + start; ++i) {
4657 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4658 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4661 return WINED3D_OK;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4665 IWineD3DDevice *iface,
4666 UINT start,
4667 BOOL *dstData,
4668 UINT count) {
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 int cnt = min(count, MAX_CONST_B - start);
4673 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4674 iface, dstData, start, count);
4676 if (dstData == NULL || cnt < 0)
4677 return WINED3DERR_INVALIDCALL;
4679 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4680 return WINED3D_OK;
4683 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4684 IWineD3DDevice *iface,
4685 UINT start,
4686 CONST int *srcData,
4687 UINT count) {
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4690 int i, cnt = min(count, MAX_CONST_I - start);
4692 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4693 iface, srcData, start, count);
4695 if (srcData == NULL || cnt < 0)
4696 return WINED3DERR_INVALIDCALL;
4698 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4699 for (i = 0; i < cnt; i++)
4700 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4701 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4703 for (i = start; i < cnt + start; ++i) {
4704 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4705 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4708 return WINED3D_OK;
4711 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4712 IWineD3DDevice *iface,
4713 UINT start,
4714 int *dstData,
4715 UINT count) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 int cnt = min(count, MAX_CONST_I - start);
4720 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4721 iface, dstData, start, count);
4723 if (dstData == NULL || cnt < 0)
4724 return WINED3DERR_INVALIDCALL;
4726 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4727 return WINED3D_OK;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4731 IWineD3DDevice *iface,
4732 UINT start,
4733 CONST float *srcData,
4734 UINT count) {
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4739 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4740 iface, srcData, start, count);
4742 if (srcData == NULL || cnt < 0)
4743 return WINED3DERR_INVALIDCALL;
4745 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4746 for (i = 0; i < cnt; i++)
4747 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4748 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4750 for (i = start; i < cnt + start; ++i) {
4751 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4752 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4755 return WINED3D_OK;
4758 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4759 IWineD3DDevice *iface,
4760 UINT start,
4761 float *dstData,
4762 UINT count) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4767 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4768 iface, dstData, start, count);
4770 if (dstData == NULL || cnt < 0)
4771 return WINED3DERR_INVALIDCALL;
4773 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4774 return WINED3D_OK;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4780 This->updateStateBlock->pixelShader = pShader;
4781 This->updateStateBlock->changed.pixelShader = TRUE;
4782 This->updateStateBlock->set.pixelShader = TRUE;
4784 /* Handle recording of state blocks */
4785 if (This->isRecordingState) {
4786 TRACE("Recording... not performing anything\n");
4789 if (NULL != pShader) {
4790 IWineD3DPixelShader_AddRef(pShader);
4792 if (NULL != oldShader) {
4793 IWineD3DPixelShader_Release(oldShader);
4796 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4798 * TODO: merge HAL shaders context switching from prototype
4800 return WINED3D_OK;
4803 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 if (NULL == ppShader) {
4807 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4808 return WINED3DERR_INVALIDCALL;
4811 *ppShader = This->stateBlock->pixelShader;
4812 if (NULL != *ppShader) {
4813 IWineD3DPixelShader_AddRef(*ppShader);
4815 TRACE("(%p) : returning %p\n", This, *ppShader);
4816 return WINED3D_OK;
4819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4820 IWineD3DDevice *iface,
4821 UINT start,
4822 CONST BOOL *srcData,
4823 UINT count) {
4825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4826 int i, cnt = min(count, MAX_CONST_B - start);
4828 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4829 iface, srcData, start, count);
4831 if (srcData == NULL || cnt < 0)
4832 return WINED3DERR_INVALIDCALL;
4834 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4835 for (i = 0; i < cnt; i++)
4836 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4838 for (i = start; i < cnt + start; ++i) {
4839 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4840 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4843 return WINED3D_OK;
4846 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4847 IWineD3DDevice *iface,
4848 UINT start,
4849 BOOL *dstData,
4850 UINT count) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 int cnt = min(count, MAX_CONST_B - start);
4855 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4856 iface, dstData, start, count);
4858 if (dstData == NULL || cnt < 0)
4859 return WINED3DERR_INVALIDCALL;
4861 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4862 return WINED3D_OK;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4866 IWineD3DDevice *iface,
4867 UINT start,
4868 CONST int *srcData,
4869 UINT count) {
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4872 int i, cnt = min(count, MAX_CONST_I - start);
4874 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4875 iface, srcData, start, count);
4877 if (srcData == NULL || cnt < 0)
4878 return WINED3DERR_INVALIDCALL;
4880 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4881 for (i = 0; i < cnt; i++)
4882 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4883 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4885 for (i = start; i < cnt + start; ++i) {
4886 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4887 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4890 return WINED3D_OK;
4893 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4894 IWineD3DDevice *iface,
4895 UINT start,
4896 int *dstData,
4897 UINT count) {
4899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 int cnt = min(count, MAX_CONST_I - start);
4902 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4903 iface, dstData, start, count);
4905 if (dstData == NULL || cnt < 0)
4906 return WINED3DERR_INVALIDCALL;
4908 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4909 return WINED3D_OK;
4912 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4913 IWineD3DDevice *iface,
4914 UINT start,
4915 CONST float *srcData,
4916 UINT count) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4921 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4922 iface, srcData, start, count);
4924 if (srcData == NULL || cnt < 0)
4925 return WINED3DERR_INVALIDCALL;
4927 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4928 for (i = 0; i < cnt; i++)
4929 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4930 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4932 for (i = start; i < cnt + start; ++i) {
4933 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4934 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4937 return WINED3D_OK;
4940 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4941 IWineD3DDevice *iface,
4942 UINT start,
4943 float *dstData,
4944 UINT count) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4950 iface, dstData, start, count);
4952 if (dstData == NULL || cnt < 0)
4953 return WINED3DERR_INVALIDCALL;
4955 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4956 return WINED3D_OK;
4959 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4960 static HRESULT
4961 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4962 char *dest_ptr, *dest_conv = NULL;
4963 unsigned int i;
4964 DWORD DestFVF = dest->fvf;
4965 D3DVIEWPORT9 vp;
4966 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4967 BOOL doClip;
4968 int numTextures;
4970 if (SrcFVF & D3DFVF_NORMAL) {
4971 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4974 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4975 ERR("Source has no position mask\n");
4976 return WINED3DERR_INVALIDCALL;
4979 /* We might access VBOs from this code, so hold the lock */
4980 ENTER_GL();
4982 if (dest->resource.allocatedMemory == NULL) {
4983 /* This may happen if we do direct locking into a vbo. Unlikely,
4984 * but theoretically possible(ddraw processvertices test)
4986 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4987 if(!dest->resource.allocatedMemory) {
4988 LEAVE_GL();
4989 ERR("Out of memory\n");
4990 return E_OUTOFMEMORY;
4992 if(dest->vbo) {
4993 void *src;
4994 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4995 checkGLcall("glBindBufferARB");
4996 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4997 if(src) {
4998 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5000 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5001 checkGLcall("glUnmapBufferARB");
5005 /* Get a pointer into the destination vbo(create one if none exists) and
5006 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5008 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5009 CreateVBO(dest);
5012 if(dest->vbo) {
5013 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5014 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5015 if(!dest_conv) {
5016 ERR("glMapBuffer failed\n");
5017 /* Continue without storing converted vertices */
5021 /* Should I clip?
5022 * a) D3DRS_CLIPPING is enabled
5023 * b) WINED3DVOP_CLIP is passed
5025 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5026 static BOOL warned = FALSE;
5028 * The clipping code is not quite correct. Some things need
5029 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5030 * so disable clipping for now.
5031 * (The graphics in Half-Life are broken, and my processvertices
5032 * test crashes with IDirect3DDevice3)
5033 doClip = TRUE;
5035 doClip = FALSE;
5036 if(!warned) {
5037 warned = TRUE;
5038 FIXME("Clipping is broken and disabled for now\n");
5040 } else doClip = FALSE;
5041 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5042 if(dest_conv) {
5043 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5046 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5047 WINED3DTS_VIEW,
5048 &view_mat);
5049 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5050 WINED3DTS_PROJECTION,
5051 &proj_mat);
5052 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5053 WINED3DTS_WORLDMATRIX(0),
5054 &world_mat);
5056 TRACE("View mat:\n");
5057 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); \
5058 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); \
5059 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); \
5060 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); \
5062 TRACE("Proj mat:\n");
5063 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); \
5064 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); \
5065 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); \
5066 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); \
5068 TRACE("World mat:\n");
5069 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); \
5070 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); \
5071 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); \
5072 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); \
5074 /* Get the viewport */
5075 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5076 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5077 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5079 multiply_matrix(&mat,&view_mat,&world_mat);
5080 multiply_matrix(&mat,&proj_mat,&mat);
5082 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5084 for (i = 0; i < dwCount; i+= 1) {
5085 unsigned int tex_index;
5087 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5088 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5089 /* The position first */
5090 float *p =
5091 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5092 float x, y, z, rhw;
5093 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5095 /* Multiplication with world, view and projection matrix */
5096 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);
5097 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);
5098 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);
5099 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);
5101 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5103 /* WARNING: The following things are taken from d3d7 and were not yet checked
5104 * against d3d8 or d3d9!
5107 /* Clipping conditions: From
5108 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5110 * A vertex is clipped if it does not match the following requirements
5111 * -rhw < x <= rhw
5112 * -rhw < y <= rhw
5113 * 0 < z <= rhw
5114 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5116 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5117 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5121 if( doClip == FALSE ||
5122 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5123 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5124 ( rhw > eps ) ) ) {
5126 /* "Normal" viewport transformation (not clipped)
5127 * 1) The values are divided by rhw
5128 * 2) The y axis is negative, so multiply it with -1
5129 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5130 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5131 * 4) Multiply x with Width/2 and add Width/2
5132 * 5) The same for the height
5133 * 6) Add the viewpoint X and Y to the 2D coordinates and
5134 * The minimum Z value to z
5135 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5137 * Well, basically it's simply a linear transformation into viewport
5138 * coordinates
5141 x /= rhw;
5142 y /= rhw;
5143 z /= rhw;
5145 y *= -1;
5147 x *= vp.Width / 2;
5148 y *= vp.Height / 2;
5149 z *= vp.MaxZ - vp.MinZ;
5151 x += vp.Width / 2 + vp.X;
5152 y += vp.Height / 2 + vp.Y;
5153 z += vp.MinZ;
5155 rhw = 1 / rhw;
5156 } else {
5157 /* That vertex got clipped
5158 * Contrary to OpenGL it is not dropped completely, it just
5159 * undergoes a different calculation.
5161 TRACE("Vertex got clipped\n");
5162 x += rhw;
5163 y += rhw;
5165 x /= 2;
5166 y /= 2;
5168 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5169 * outside of the main vertex buffer memory. That needs some more
5170 * investigation...
5174 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5177 ( (float *) dest_ptr)[0] = x;
5178 ( (float *) dest_ptr)[1] = y;
5179 ( (float *) dest_ptr)[2] = z;
5180 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5182 dest_ptr += 3 * sizeof(float);
5184 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5185 dest_ptr += sizeof(float);
5188 if(dest_conv) {
5189 float w = 1 / rhw;
5190 ( (float *) dest_conv)[0] = x * w;
5191 ( (float *) dest_conv)[1] = y * w;
5192 ( (float *) dest_conv)[2] = z * w;
5193 ( (float *) dest_conv)[3] = w;
5195 dest_conv += 3 * sizeof(float);
5197 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5198 dest_conv += sizeof(float);
5202 if (DestFVF & D3DFVF_PSIZE) {
5203 dest_ptr += sizeof(DWORD);
5204 if(dest_conv) dest_conv += sizeof(DWORD);
5206 if (DestFVF & D3DFVF_NORMAL) {
5207 float *normal =
5208 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5209 /* AFAIK this should go into the lighting information */
5210 FIXME("Didn't expect the destination to have a normal\n");
5211 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5212 if(dest_conv) {
5213 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5217 if (DestFVF & D3DFVF_DIFFUSE) {
5218 DWORD *color_d =
5219 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5220 if(!color_d) {
5221 static BOOL warned = FALSE;
5223 if(warned == FALSE) {
5224 ERR("No diffuse color in source, but destination has one\n");
5225 warned = TRUE;
5228 *( (DWORD *) dest_ptr) = 0xffffffff;
5229 dest_ptr += sizeof(DWORD);
5231 if(dest_conv) {
5232 *( (DWORD *) dest_conv) = 0xffffffff;
5233 dest_conv += sizeof(DWORD);
5236 else {
5237 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5238 if(dest_conv) {
5239 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5240 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5241 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5242 dest_conv += sizeof(DWORD);
5247 if (DestFVF & D3DFVF_SPECULAR) {
5248 /* What's the color value in the feedback buffer? */
5249 DWORD *color_s =
5250 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5251 if(!color_s) {
5252 static BOOL warned = FALSE;
5254 if(warned == FALSE) {
5255 ERR("No specular color in source, but destination has one\n");
5256 warned = TRUE;
5259 *( (DWORD *) dest_ptr) = 0xFF000000;
5260 dest_ptr += sizeof(DWORD);
5262 if(dest_conv) {
5263 *( (DWORD *) dest_conv) = 0xFF000000;
5264 dest_conv += sizeof(DWORD);
5267 else {
5268 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5269 if(dest_conv) {
5270 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5271 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5272 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5273 dest_conv += sizeof(DWORD);
5278 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5279 float *tex_coord =
5280 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5281 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5282 if(!tex_coord) {
5283 ERR("No source texture, but destination requests one\n");
5284 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5285 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5287 else {
5288 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5289 if(dest_conv) {
5290 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5296 if(dest_conv) {
5297 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5298 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5301 LEAVE_GL();
5303 return WINED3D_OK;
5305 #undef copy_and_next
5307 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5310 WineDirect3DVertexStridedData strided;
5311 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5313 /* We don't need the source vbo because this buffer is only used as
5314 * a source for ProcessVertices. Avoid wasting resources by converting the
5315 * buffer and loading the VBO
5317 if(SrcImpl->vbo) {
5318 TRACE("Releaseing the source vbo, it won't be needed\n");
5320 if(!SrcImpl->resource.allocatedMemory) {
5321 /* Rescue the data from the buffer */
5322 void *src;
5323 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5324 if(!SrcImpl->resource.allocatedMemory) {
5325 ERR("Out of memory\n");
5326 return E_OUTOFMEMORY;
5329 ENTER_GL();
5330 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5331 checkGLcall("glBindBufferARB");
5333 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5334 if(src) {
5335 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5338 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5339 checkGLcall("glUnmapBufferARB");
5340 } else {
5341 ENTER_GL();
5344 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5345 checkGLcall("glBindBufferARB");
5346 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5347 checkGLcall("glDeleteBuffersARB");
5348 LEAVE_GL();
5350 SrcImpl->vbo = 0;
5353 memset(&strided, 0, sizeof(strided));
5354 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5356 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5359 /*****
5360 * Apply / Get / Set Texture Stage States
5361 * TODO: Verify against dx9 definitions
5362 *****/
5364 /* 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 */
5365 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5368 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5370 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5372 /* Check that the stage is within limits */
5373 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5374 TRACE("Attempt to access invalid texture rejected\n");
5375 return;
5378 ENTER_GL();
5380 switch (Type) {
5381 case WINED3DTSS_ALPHAOP :
5382 case WINED3DTSS_COLOROP :
5383 /* nothing to do as moved to drawprim for now */
5384 break;
5385 case WINED3DTSS_ADDRESSW :
5386 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5387 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5388 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5390 } else {
5391 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5392 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5393 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5394 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5396 #endif
5397 case WINED3DTSS_TEXCOORDINDEX :
5399 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5401 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5402 one flag, you can still specify an index value, which the system uses to
5403 determine the texture wrapping mode.
5404 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5405 means use the vertex position (camera-space) as the input texture coordinates
5406 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5407 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5408 to the TEXCOORDINDEX value */
5411 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5413 switch (Value & 0xFFFF0000) {
5414 case D3DTSS_TCI_PASSTHRU:
5415 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5416 glDisable(GL_TEXTURE_GEN_S);
5417 glDisable(GL_TEXTURE_GEN_T);
5418 glDisable(GL_TEXTURE_GEN_R);
5419 glDisable(GL_TEXTURE_GEN_Q);
5420 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5421 break;
5423 case D3DTSS_TCI_CAMERASPACEPOSITION:
5424 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5425 as the input texture coordinates for this stage's texture transformation. This
5426 equates roughly to EYE_LINEAR */
5428 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5429 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5430 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5431 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5432 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5434 glMatrixMode(GL_MODELVIEW);
5435 glPushMatrix();
5436 glLoadIdentity();
5437 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5438 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5439 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5440 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5441 glPopMatrix();
5443 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5444 glEnable(GL_TEXTURE_GEN_S);
5445 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5446 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5447 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5448 glEnable(GL_TEXTURE_GEN_T);
5449 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5450 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5451 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5452 glEnable(GL_TEXTURE_GEN_R);
5453 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5454 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5455 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5457 break;
5459 case D3DTSS_TCI_CAMERASPACENORMAL:
5461 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5462 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5463 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5464 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5465 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5466 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5468 glMatrixMode(GL_MODELVIEW);
5469 glPushMatrix();
5470 glLoadIdentity();
5471 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5472 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5473 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5474 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5475 glPopMatrix();
5477 glEnable(GL_TEXTURE_GEN_S);
5478 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5479 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5480 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5481 glEnable(GL_TEXTURE_GEN_T);
5482 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5483 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5484 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5485 glEnable(GL_TEXTURE_GEN_R);
5486 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5487 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5488 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5491 break;
5493 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5495 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5496 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5497 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5498 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5499 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5500 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5502 glMatrixMode(GL_MODELVIEW);
5503 glPushMatrix();
5504 glLoadIdentity();
5505 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5506 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5507 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5508 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5509 glPopMatrix();
5511 glEnable(GL_TEXTURE_GEN_S);
5512 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5513 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5514 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5515 glEnable(GL_TEXTURE_GEN_T);
5516 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5517 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5518 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5519 glEnable(GL_TEXTURE_GEN_R);
5520 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5521 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5522 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5525 break;
5527 /* Unhandled types: */
5528 default:
5529 /* Todo: */
5530 /* ? disable GL_TEXTURE_GEN_n ? */
5531 glDisable(GL_TEXTURE_GEN_S);
5532 glDisable(GL_TEXTURE_GEN_T);
5533 glDisable(GL_TEXTURE_GEN_R);
5534 glDisable(GL_TEXTURE_GEN_Q);
5535 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5536 break;
5539 break;
5541 /* Unhandled */
5542 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5543 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5544 break;
5546 case WINED3DTSS_BUMPENVMAT00 :
5547 case WINED3DTSS_BUMPENVMAT01 :
5548 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5549 break;
5550 case WINED3DTSS_BUMPENVMAT10 :
5551 case WINED3DTSS_BUMPENVMAT11 :
5552 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5553 break;
5555 case WINED3DTSS_BUMPENVLSCALE :
5556 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5557 break;
5559 case WINED3DTSS_BUMPENVLOFFSET :
5560 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5561 break;
5563 case WINED3DTSS_RESULTARG :
5564 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5565 break;
5567 default:
5568 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5569 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5572 LEAVE_GL();
5574 return;
5577 /*****
5578 * Get / Set Texture Stage States
5579 * TODO: Verify against dx9 definitions
5580 *****/
5581 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5584 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5586 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5588 /* Reject invalid texture units */
5589 if (Stage >= GL_LIMITS(texture_stages)) {
5590 TRACE("Attempt to access invalid texture rejected\n");
5591 return WINED3DERR_INVALIDCALL;
5594 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5595 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5596 This->updateStateBlock->textureState[Stage][Type] = Value;
5598 return WINED3D_OK;
5601 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5604 *pValue = This->updateStateBlock->textureState[Stage][Type];
5605 return WINED3D_OK;
5608 /*****
5609 * Get / Set Texture
5610 *****/
5611 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 IWineD3DBaseTexture *oldTexture;
5616 oldTexture = This->updateStateBlock->textures[Stage];
5617 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5619 #if 0 /* TODO: check so vertex textures */
5620 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5621 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5622 return WINED3D_OK;
5624 #endif
5626 /* Reject invalid texture units */
5627 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5628 WARN("Attempt to access invalid texture rejected\n");
5629 return WINED3DERR_INVALIDCALL;
5632 if(pTexture != NULL) {
5633 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5635 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5636 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5637 return WINED3DERR_INVALIDCALL;
5641 oldTexture = This->updateStateBlock->textures[Stage];
5642 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5643 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5645 This->updateStateBlock->set.textures[Stage] = TRUE;
5646 This->updateStateBlock->changed.textures[Stage] = TRUE;
5647 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5648 This->updateStateBlock->textures[Stage] = pTexture;
5650 /* Handle recording of state blocks */
5651 if (This->isRecordingState) {
5652 TRACE("Recording... not performing anything\n");
5653 return WINED3D_OK;
5656 /** NOTE: MSDN says that setTexture increases the reference count,
5657 * and the the application nust set the texture back to null (or have a leaky application),
5658 * This means we should pass the refcount up to the parent
5659 *******************************/
5660 if (NULL != This->updateStateBlock->textures[Stage]) {
5661 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5664 if (NULL != oldTexture) {
5665 IWineD3DBaseTexture_Release(oldTexture);
5668 /* Reset color keying */
5669 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5670 BOOL enable_ckey = FALSE;
5672 if(pTexture) {
5673 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5674 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5677 if(enable_ckey) {
5678 glAlphaFunc(GL_NOTEQUAL, 0.0);
5679 checkGLcall("glAlphaFunc");
5683 return WINED3D_OK;
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5688 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5690 /* Reject invalid texture units */
5691 if (Stage >= GL_LIMITS(sampler_stages)) {
5692 TRACE("Attempt to access invalid texture rejected\n");
5693 return WINED3DERR_INVALIDCALL;
5695 *ppTexture=This->updateStateBlock->textures[Stage];
5696 if (*ppTexture)
5697 IWineD3DBaseTexture_AddRef(*ppTexture);
5698 else
5699 return WINED3DERR_INVALIDCALL;
5700 return WINED3D_OK;
5703 /*****
5704 * Get Back Buffer
5705 *****/
5706 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5707 IWineD3DSurface **ppBackBuffer) {
5708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5709 IWineD3DSwapChain *swapChain;
5710 HRESULT hr;
5712 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5714 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5715 if (hr == WINED3D_OK) {
5716 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5717 IWineD3DSwapChain_Release(swapChain);
5718 } else {
5719 *ppBackBuffer = NULL;
5721 return hr;
5724 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5726 WARN("(%p) : stub, calling idirect3d for now\n", This);
5727 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5730 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5732 IWineD3DSwapChain *swapChain;
5733 HRESULT hr;
5735 if(iSwapChain > 0) {
5736 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5737 if (hr == WINED3D_OK) {
5738 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5739 IWineD3DSwapChain_Release(swapChain);
5740 } else {
5741 FIXME("(%p) Error getting display mode\n", This);
5743 } else {
5744 /* Don't read the real display mode,
5745 but return the stored mode instead. X11 can't change the color
5746 depth, and some apps are pretty angry if they SetDisplayMode from
5747 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5749 Also don't relay to the swapchain because with ddraw it's possible
5750 that there isn't a swapchain at all */
5751 pMode->Width = This->ddraw_width;
5752 pMode->Height = This->ddraw_height;
5753 pMode->Format = This->ddraw_format;
5754 pMode->RefreshRate = 0;
5755 hr = WINED3D_OK;
5758 return hr;
5761 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 TRACE("(%p)->(%p)\n", This, hWnd);
5765 This->ddraw_window = hWnd;
5766 return WINED3D_OK;
5769 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5771 TRACE("(%p)->(%p)\n", This, hWnd);
5773 *hWnd = This->ddraw_window;
5774 return WINED3D_OK;
5777 /*****
5778 * Stateblock related functions
5779 *****/
5781 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5783 IWineD3DStateBlockImpl *object;
5784 HRESULT temp_result;
5786 TRACE("(%p)", This);
5788 if (This->isRecordingState) {
5789 return WINED3DERR_INVALIDCALL;
5792 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5793 if (NULL == object ) {
5794 FIXME("(%p)Error allocating memory for stateblock\n", This);
5795 return E_OUTOFMEMORY;
5797 TRACE("(%p) created object %p\n", This, object);
5798 object->wineD3DDevice= This;
5799 /** FIXME: object->parent = parent; **/
5800 object->parent = NULL;
5801 object->blockType = WINED3DSBT_ALL;
5802 object->ref = 1;
5803 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5805 temp_result = allocate_shader_constants(object);
5806 if (WINED3D_OK != temp_result)
5807 return temp_result;
5809 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5810 This->updateStateBlock = object;
5811 This->isRecordingState = TRUE;
5813 TRACE("(%p) recording stateblock %p\n",This , object);
5814 return WINED3D_OK;
5817 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5820 if (!This->isRecordingState) {
5821 FIXME("(%p) not recording! returning error\n", This);
5822 *ppStateBlock = NULL;
5823 return WINED3DERR_INVALIDCALL;
5826 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5827 This->isRecordingState = FALSE;
5828 This->updateStateBlock = This->stateBlock;
5829 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5830 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5831 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5832 return WINED3D_OK;
5835 /*****
5836 * Scene related functions
5837 *****/
5838 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5839 /* At the moment we have no need for any functionality at the beginning
5840 of a scene */
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 TRACE("(%p) : stub\n", This);
5843 return WINED3D_OK;
5846 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5848 TRACE("(%p)\n", This);
5849 ENTER_GL();
5850 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5851 glFlush();
5852 checkGLcall("glFlush");
5854 TRACE("End Scene\n");
5855 if(This->renderTarget != NULL) {
5857 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5858 IUnknown *targetContainer = NULL;
5859 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5860 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5861 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5862 /** always dirtify for now. we must find a better way to see that surface have been modified
5863 (Modifications should will only occur via draw-primitive, but we do need better locking
5864 switching to render-to-texture should remove the overhead though.
5866 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5867 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5868 IWineD3DSurface_PreLoad(This->renderTarget);
5869 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5870 IUnknown_Release(targetContainer);
5873 This->sceneEnded = TRUE;
5874 LEAVE_GL();
5875 return WINED3D_OK;
5878 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5879 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5880 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5882 IWineD3DSwapChain *swapChain = NULL;
5883 int i;
5884 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5886 TRACE("(%p) Presenting the frame\n", This);
5888 for(i = 0 ; i < swapchains ; i ++) {
5890 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5891 TRACE("presentinng chain %d, %p\n", i, swapChain);
5892 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5893 IWineD3DSwapChain_Release(swapChain);
5896 return WINED3D_OK;
5899 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5900 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5903 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5904 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5905 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5906 GLbitfield glMask = 0;
5907 GLboolean old_ztest;
5908 GLfloat old_z_clear_value;
5909 GLint old_stencil_clear_value;
5910 GLfloat old_color_clear_value[4];
5911 unsigned int i;
5912 CONST D3DRECT* curRect;
5914 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5915 Count, pRects, Flags, Z, Stencil);
5917 ENTER_GL();
5919 glEnable(GL_SCISSOR_TEST);
5920 checkGLcall("glEnable GL_SCISSOR_TEST");
5922 if (Count > 0 && pRects) {
5923 curRect = pRects;
5924 } else {
5925 curRect = NULL;
5928 /* Only set the values up once, as they are not changing */
5929 if (Flags & D3DCLEAR_STENCIL) {
5930 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5931 glClearStencil(Stencil);
5932 checkGLcall("glClearStencil");
5933 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5934 glStencilMask(0xFFFFFFFF);
5937 if (Flags & D3DCLEAR_ZBUFFER) {
5938 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5939 glDepthMask(GL_TRUE);
5940 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5941 glClearDepth(Z);
5942 checkGLcall("glClearDepth");
5943 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5946 if (Flags & D3DCLEAR_TARGET) {
5947 TRACE("Clearing screen with glClear to color %lx\n", Color);
5948 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5949 glClearColor(D3DCOLOR_R(Color),
5950 D3DCOLOR_G(Color),
5951 D3DCOLOR_B(Color),
5952 D3DCOLOR_A(Color));
5953 checkGLcall("glClearColor");
5955 /* Clear ALL colors! */
5956 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5957 glMask = glMask | GL_COLOR_BUFFER_BIT;
5960 /* Now process each rect in turn */
5961 for (i = 0; i < Count || i == 0; i++) {
5963 if (curRect) {
5964 /* Note gl uses lower left, width/height */
5965 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5966 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5967 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5968 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5969 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5970 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5971 checkGLcall("glScissor");
5972 } else {
5973 glScissor(This->stateBlock->viewport.X,
5974 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5975 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5976 This->stateBlock->viewport.Width,
5977 This->stateBlock->viewport.Height);
5978 checkGLcall("glScissor");
5981 /* Clear the selected rectangle (or full screen) */
5982 glClear(glMask);
5983 checkGLcall("glClear");
5985 /* Step to the next rectangle */
5986 if (curRect) curRect = curRect + sizeof(D3DRECT);
5989 /* Restore the old values (why..?) */
5990 if (Flags & D3DCLEAR_STENCIL) {
5991 glClearStencil(old_stencil_clear_value);
5992 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5994 if (Flags & D3DCLEAR_ZBUFFER) {
5995 glDepthMask(old_ztest);
5996 glClearDepth(old_z_clear_value);
5998 if (Flags & D3DCLEAR_TARGET) {
5999 glClearColor(old_color_clear_value[0],
6000 old_color_clear_value[1],
6001 old_color_clear_value[2],
6002 old_color_clear_value[3]);
6003 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6004 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6005 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6006 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6009 glDisable(GL_SCISSOR_TEST);
6010 checkGLcall("glDisable");
6011 LEAVE_GL();
6013 return WINED3D_OK;
6016 /*****
6017 * Drawing functions
6018 *****/
6019 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6020 UINT PrimitiveCount) {
6022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6023 This->stateBlock->streamIsUP = FALSE;
6025 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6026 debug_d3dprimitivetype(PrimitiveType),
6027 StartVertex, PrimitiveCount);
6028 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6029 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6032 return WINED3D_OK;
6035 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6036 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6037 D3DPRIMITIVETYPE PrimitiveType,
6038 INT baseVIndex, UINT minIndex,
6039 UINT NumVertices, UINT startIndex, UINT primCount) {
6041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 UINT idxStride = 2;
6043 IWineD3DIndexBuffer *pIB;
6044 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6046 pIB = This->stateBlock->pIndexData;
6047 This->stateBlock->streamIsUP = FALSE;
6049 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6050 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6051 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6053 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6054 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6055 idxStride = 2;
6056 } else {
6057 idxStride = 4;
6060 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6061 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6063 return WINED3D_OK;
6066 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6067 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6068 UINT VertexStreamZeroStride) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6071 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6072 debug_d3dprimitivetype(PrimitiveType),
6073 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6075 /* release the stream source */
6076 if (This->stateBlock->streamSource[0] != NULL) {
6077 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6080 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6081 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6082 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6083 This->stateBlock->streamIsUP = TRUE;
6085 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6086 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6088 /* MSDN specifies stream zero settings must be set to NULL */
6089 This->stateBlock->streamStride[0] = 0;
6090 This->stateBlock->streamSource[0] = NULL;
6092 /*stream zero settings set to null at end, as per the msdn */
6093 return WINED3D_OK;
6096 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6097 UINT MinVertexIndex, UINT NumVertices,
6098 UINT PrimitiveCount, CONST void* pIndexData,
6099 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6100 UINT VertexStreamZeroStride) {
6101 int idxStride;
6102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6104 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6105 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6106 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6107 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6109 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6110 idxStride = 2;
6111 } else {
6112 idxStride = 4;
6115 /* release the stream and index data */
6116 if (This->stateBlock->streamSource[0] != NULL) {
6117 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6119 if (This->stateBlock->pIndexData) {
6120 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6123 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6124 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6125 This->stateBlock->streamIsUP = TRUE;
6126 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6128 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6130 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6131 This->stateBlock->streamSource[0] = NULL;
6132 This->stateBlock->streamStride[0] = 0;
6133 This->stateBlock->pIndexData = NULL;
6135 return WINED3D_OK;
6138 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6140 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6141 return WINED3D_OK;
6143 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6144 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6146 HRESULT hr = WINED3D_OK;
6147 WINED3DRESOURCETYPE sourceType;
6148 WINED3DRESOURCETYPE destinationType;
6149 int i ,levels;
6151 /* TODO: think about moving the code into IWineD3DBaseTexture */
6153 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6155 /* verify that the source and destination textures aren't NULL */
6156 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6157 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6158 This, pSourceTexture, pDestinationTexture);
6159 hr = WINED3DERR_INVALIDCALL;
6162 if (pSourceTexture == pDestinationTexture) {
6163 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6164 This, pSourceTexture, pDestinationTexture);
6165 hr = WINED3DERR_INVALIDCALL;
6167 /* Verify that the source and destination textures are the same type */
6168 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6169 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6171 if (sourceType != destinationType) {
6172 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6173 This);
6174 hr = WINED3DERR_INVALIDCALL;
6177 /* check that both textures have the identical numbers of levels */
6178 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6179 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6180 hr = WINED3DERR_INVALIDCALL;
6183 if (WINED3D_OK == hr) {
6185 /* Make sure that the destination texture is loaded */
6186 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6188 /* Update every surface level of the texture */
6189 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6191 switch (sourceType) {
6192 case WINED3DRTYPE_TEXTURE:
6194 IWineD3DSurface *srcSurface;
6195 IWineD3DSurface *destSurface;
6197 for (i = 0 ; i < levels ; ++i) {
6198 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6199 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6200 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6201 IWineD3DSurface_Release(srcSurface);
6202 IWineD3DSurface_Release(destSurface);
6203 if (WINED3D_OK != hr) {
6204 WARN("(%p) : Call to update surface failed\n", This);
6205 return hr;
6209 break;
6210 case WINED3DRTYPE_CUBETEXTURE:
6212 IWineD3DSurface *srcSurface;
6213 IWineD3DSurface *destSurface;
6214 WINED3DCUBEMAP_FACES faceType;
6216 for (i = 0 ; i < levels ; ++i) {
6217 /* Update each cube face */
6218 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6219 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6220 if (WINED3D_OK != hr) {
6221 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6222 } else {
6223 TRACE("Got srcSurface %p\n", srcSurface);
6225 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6226 if (WINED3D_OK != hr) {
6227 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6228 } else {
6229 TRACE("Got desrSurface %p\n", destSurface);
6231 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6232 IWineD3DSurface_Release(srcSurface);
6233 IWineD3DSurface_Release(destSurface);
6234 if (WINED3D_OK != hr) {
6235 WARN("(%p) : Call to update surface failed\n", This);
6236 return hr;
6241 break;
6242 #if 0 /* TODO: Add support for volume textures */
6243 case WINED3DRTYPE_VOLUMETEXTURE:
6245 IWineD3DVolume srcVolume = NULL;
6246 IWineD3DSurface destVolume = NULL;
6248 for (i = 0 ; i < levels ; ++i) {
6249 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6250 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6251 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6252 IWineD3DVolume_Release(srcSurface);
6253 IWineD3DVolume_Release(destSurface);
6254 if (WINED3D_OK != hr) {
6255 WARN("(%p) : Call to update volume failed\n", This);
6256 return hr;
6260 break;
6261 #endif
6262 default:
6263 FIXME("(%p) : Unsupported source and destination type\n", This);
6264 hr = WINED3DERR_INVALIDCALL;
6268 return hr;
6271 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6272 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6273 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6276 TRACE("(%p) : stub\n", This);
6277 return WINED3D_OK;
6279 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6281 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6282 * NOTE It may be best to move the code into surface to occomplish this
6283 ****************************************/
6285 WINED3DSURFACE_DESC surfaceDesc;
6286 unsigned int surfaceWidth, surfaceHeight;
6287 glDescriptor *targetGlDescription = NULL;
6288 glDescriptor *surfaceGlDescription = NULL;
6289 IWineD3DSwapChainImpl *container = NULL;
6291 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6292 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6293 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6295 surfaceDesc.Width = &surfaceWidth;
6296 surfaceDesc.Height = &surfaceHeight;
6297 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6298 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6300 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6301 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6302 ENTER_GL();
6303 /* TODO: opengl Context switching for swapchains etc... */
6304 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6305 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6306 glReadBuffer(GL_BACK);
6307 vcheckGLcall("glReadBuffer(GL_BACK)");
6308 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6309 glReadBuffer(GL_FRONT);
6310 vcheckGLcall("glReadBuffer(GL_FRONT)");
6311 } else if (pRenderTarget == This->depthStencilBuffer) {
6312 FIXME("Reading of depthstencil not yet supported\n");
6315 glReadPixels(surfaceGlDescription->target,
6316 surfaceGlDescription->level,
6317 surfaceWidth,
6318 surfaceHeight,
6319 surfaceGlDescription->glFormat,
6320 surfaceGlDescription->glType,
6321 (void *)IWineD3DSurface_GetData(pSurface));
6322 vcheckGLcall("glReadPixels(...)");
6323 if(NULL != container ){
6324 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6326 } else {
6327 IWineD3DBaseTexture *container;
6328 GLenum textureDimensions = GL_TEXTURE_2D;
6330 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6331 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6332 IWineD3DBaseTexture_Release(container);
6334 /* TODO: 2D -> Cube surface coppies etc.. */
6335 if (surfaceGlDescription->target != textureDimensions) {
6336 FIXME("(%p) : Texture dimension mismatch\n", This);
6338 glEnable(textureDimensions);
6339 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6340 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6341 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6342 vcheckGLcall("glBindTexture");
6343 glGetTexImage(surfaceGlDescription->target,
6344 surfaceGlDescription->level,
6345 surfaceGlDescription->glFormat,
6346 surfaceGlDescription->glType,
6347 (void *)IWineD3DSurface_GetData(pSurface));
6348 glDisable(textureDimensions);
6349 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6352 LEAVE_GL();
6353 return WINED3D_OK;
6356 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6357 IWineD3DSwapChain *swapChain;
6358 HRESULT hr;
6359 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6360 if(hr == WINED3D_OK) {
6361 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6362 IWineD3DSwapChain_Release(swapChain);
6364 return hr;
6367 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6369 /* return a sensible default */
6370 *pNumPasses = 1;
6371 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6372 FIXME("(%p) : stub\n", This);
6373 return WINED3D_OK;
6376 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6378 int j;
6379 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6380 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6381 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6382 return WINED3DERR_INVALIDCALL;
6384 for (j = 0; j < 256; ++j) {
6385 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6386 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6387 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6388 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6390 TRACE("(%p) : returning\n", This);
6391 return WINED3D_OK;
6394 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6396 int j;
6397 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6398 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6399 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6400 return WINED3DERR_INVALIDCALL;
6402 for (j = 0; j < 256; ++j) {
6403 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6404 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6405 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6406 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6408 TRACE("(%p) : returning\n", This);
6409 return WINED3D_OK;
6412 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6414 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6415 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6416 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6417 return WINED3DERR_INVALIDCALL;
6419 /*TODO: stateblocks */
6420 This->currentPalette = PaletteNumber;
6421 TRACE("(%p) : returning\n", This);
6422 return WINED3D_OK;
6425 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6427 if (PaletteNumber == NULL) {
6428 WARN("(%p) : returning Invalid Call\n", This);
6429 return WINED3DERR_INVALIDCALL;
6431 /*TODO: stateblocks */
6432 *PaletteNumber = This->currentPalette;
6433 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6434 return WINED3D_OK;
6437 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6439 static BOOL showFixmes = TRUE;
6440 if (showFixmes) {
6441 FIXME("(%p) : stub\n", This);
6442 showFixmes = FALSE;
6445 This->softwareVertexProcessing = bSoftware;
6446 return WINED3D_OK;
6450 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6452 static BOOL showFixmes = TRUE;
6453 if (showFixmes) {
6454 FIXME("(%p) : stub\n", This);
6455 showFixmes = FALSE;
6457 return This->softwareVertexProcessing;
6461 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6463 IWineD3DSwapChain *swapChain;
6464 HRESULT hr;
6466 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6468 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6469 if(hr == WINED3D_OK){
6470 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6471 IWineD3DSwapChain_Release(swapChain);
6472 }else{
6473 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6475 return hr;
6479 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 static BOOL showfixmes = TRUE;
6482 if(nSegments != 0.0f) {
6483 if( showfixmes) {
6484 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6485 showfixmes = FALSE;
6488 return WINED3D_OK;
6491 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6493 static BOOL showfixmes = TRUE;
6494 if( showfixmes) {
6495 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6496 showfixmes = FALSE;
6498 return 0.0f;
6501 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6503 /** TODO: remove casts to IWineD3DSurfaceImpl
6504 * NOTE: move code to surface to accomplish this
6505 ****************************************/
6506 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6507 int srcWidth, srcHeight;
6508 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6509 WINED3DFORMAT destFormat, srcFormat;
6510 UINT destSize;
6511 int destLeft, destTop;
6512 WINED3DPOOL srcPool, destPool;
6513 int offset = 0;
6514 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6515 glDescriptor *glDescription = NULL;
6516 GLenum textureDimensions = GL_TEXTURE_2D;
6517 IWineD3DBaseTexture *baseTexture;
6519 WINED3DSURFACE_DESC winedesc;
6521 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6522 memset(&winedesc, 0, sizeof(winedesc));
6523 winedesc.Width = &srcSurfaceWidth;
6524 winedesc.Height = &srcSurfaceHeight;
6525 winedesc.Pool = &srcPool;
6526 winedesc.Format = &srcFormat;
6528 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6530 winedesc.Width = &destSurfaceWidth;
6531 winedesc.Height = &destSurfaceHeight;
6532 winedesc.Pool = &destPool;
6533 winedesc.Format = &destFormat;
6534 winedesc.Size = &destSize;
6536 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6538 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6539 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6540 return WINED3DERR_INVALIDCALL;
6543 if (destFormat == WINED3DFMT_UNKNOWN) {
6544 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6545 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6547 /* Get the update surface description */
6548 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6551 /* Make sure the surface is loaded and up to date */
6552 IWineD3DSurface_PreLoad(pDestinationSurface);
6554 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6556 ENTER_GL();
6558 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6559 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6560 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6561 destLeft = pDestPoint ? pDestPoint->x : 0;
6562 destTop = pDestPoint ? pDestPoint->y : 0;
6565 /* This function doesn't support compressed textures
6566 the pitch is just bytesPerPixel * width */
6567 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6568 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6569 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6570 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6572 /* TODO DXT formats */
6574 if(pSourceRect != NULL && pSourceRect->top != 0){
6575 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6577 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6578 ,This
6579 ,glDescription->level
6580 ,destLeft
6581 ,destTop
6582 ,srcWidth
6583 ,srcHeight
6584 ,glDescription->glFormat
6585 ,glDescription->glType
6586 ,IWineD3DSurface_GetData(pSourceSurface)
6589 /* Sanity check */
6590 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6592 /* need to lock the surface to get the data */
6593 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6596 /* TODO: Cube and volume support */
6597 if(rowoffset != 0){
6598 /* not a whole row so we have to do it a line at a time */
6599 int j;
6601 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6602 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6604 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6606 glTexSubImage2D(glDescription->target
6607 ,glDescription->level
6608 ,destLeft
6610 ,srcWidth
6612 ,glDescription->glFormat
6613 ,glDescription->glType
6614 ,data /* could be quicker using */
6616 data += rowoffset;
6619 } else { /* Full width, so just write out the whole texture */
6621 if (WINED3DFMT_DXT1 == destFormat ||
6622 WINED3DFMT_DXT2 == destFormat ||
6623 WINED3DFMT_DXT3 == destFormat ||
6624 WINED3DFMT_DXT4 == destFormat ||
6625 WINED3DFMT_DXT5 == destFormat) {
6626 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6627 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6628 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6629 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6630 } if (destFormat != srcFormat) {
6631 FIXME("Updating mixed format compressed texture is not curretly support\n");
6632 } else {
6633 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6634 glDescription->level,
6635 glDescription->glFormatInternal,
6636 srcWidth,
6637 srcHeight,
6639 destSize,
6640 IWineD3DSurface_GetData(pSourceSurface));
6642 } else {
6643 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6647 } else {
6648 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6650 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6651 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6652 data returned by GetData non-power2 width/height with hardware non-power2
6653 pow2Width/height are set to surface width height, repacking isn't needed so it
6654 doesn't matter which function gets called. */
6655 glTexSubImage2D(glDescription->target
6656 ,glDescription->level
6657 ,destLeft
6658 ,destTop
6659 ,srcWidth
6660 ,srcHeight
6661 ,glDescription->glFormat
6662 ,glDescription->glType
6663 ,IWineD3DSurface_GetData(pSourceSurface)
6665 } else {
6667 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6668 glTexSubImage2D(glDescription->target
6669 ,glDescription->level
6670 ,destLeft
6671 ,destTop
6672 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6673 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6674 ,glDescription->glFormat
6675 ,glDescription->glType
6676 ,IWineD3DSurface_GetData(pSourceSurface)
6682 checkGLcall("glTexSubImage2D");
6684 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6685 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6686 * surface bigger than it needs to be hmm.. */
6687 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6688 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6689 IWineD3DBaseTexture_Release(baseTexture);
6692 glDisable(textureDimensions); /* This needs to be managed better.... */
6693 LEAVE_GL();
6695 return WINED3D_OK;
6698 /* Used by DirectX 8 */
6699 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6700 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6701 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6704 HRESULT hr = WINED3D_OK;
6705 WINED3DFORMAT srcFormat, destFormat;
6706 UINT srcWidth, destWidth;
6707 UINT srcHeight, destHeight;
6708 UINT srcSize;
6709 WINED3DSURFACE_DESC winedesc;
6711 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6712 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6715 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6716 memset(&winedesc, 0, sizeof(winedesc));
6718 winedesc.Format = &srcFormat;
6719 winedesc.Width = &srcWidth;
6720 winedesc.Height = &srcHeight;
6721 winedesc.Size = &srcSize;
6722 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6724 winedesc.Format = &destFormat;
6725 winedesc.Width = &destWidth;
6726 winedesc.Height = &destHeight;
6727 winedesc.Size = NULL;
6728 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6730 /* Check that the source and destination formats match */
6731 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6732 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6733 return WINED3DERR_INVALIDCALL;
6734 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6735 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6736 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6737 destFormat = srcFormat;
6740 /* Quick if complete copy ... */
6741 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6743 if (srcWidth == destWidth && srcHeight == destHeight) {
6744 WINED3DLOCKED_RECT lrSrc;
6745 WINED3DLOCKED_RECT lrDst;
6746 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6747 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6748 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6750 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6752 IWineD3DSurface_UnlockRect(pSourceSurface);
6753 IWineD3DSurface_UnlockRect(pDestinationSurface);
6754 TRACE("Unlocked src and dst\n");
6756 } else {
6758 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6759 hr = WINED3DERR_INVALIDCALL;
6762 } else {
6764 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6766 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6767 unsigned int i;
6769 /* Copy rect by rect */
6770 for (i = 0; i < cRects; ++i) {
6771 CONST RECT* r = &pSourceRectsArray[i];
6772 CONST POINT* p = &pDestPointsArray[i];
6773 int copyperline;
6774 int j;
6775 WINED3DLOCKED_RECT lrSrc;
6776 WINED3DLOCKED_RECT lrDst;
6777 RECT dest_rect;
6779 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6780 if (srcFormat == WINED3DFMT_DXT1) {
6781 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6782 } else {
6783 copyperline = ((r->right - r->left) * bytesPerPixel);
6786 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6787 dest_rect.left = p->x;
6788 dest_rect.top = p->y;
6789 dest_rect.right = p->x + (r->right - r->left);
6790 dest_rect.bottom= p->y + (r->bottom - r->top);
6791 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6792 TRACE("Locked src and dst\n");
6794 /* Find where to start */
6795 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6796 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6798 IWineD3DSurface_UnlockRect(pSourceSurface);
6799 IWineD3DSurface_UnlockRect(pDestinationSurface);
6800 TRACE("Unlocked src and dst\n");
6802 } else {
6803 unsigned int i;
6804 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6805 int copyperline;
6806 int j;
6807 WINED3DLOCKED_RECT lrSrc;
6808 WINED3DLOCKED_RECT lrDst;
6809 RECT dest_rect;
6811 for(i=0; i < cRects; i++) {
6812 CONST RECT* r = &pSourceRectsArray[i];
6814 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6815 if (srcFormat == WINED3DFMT_DXT1) {
6816 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6817 } else {
6818 copyperline = ((r->right - r->left) * bytesPerPixel);
6820 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6821 dest_rect.left = 0;
6822 dest_rect.top = 0;
6823 dest_rect.right = r->right - r->left;
6824 dest_rect.bottom= r->bottom - r->top;
6825 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6826 TRACE("Locked src and dst\n");
6827 /* Find where to start */
6828 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6829 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6831 IWineD3DSurface_UnlockRect(pSourceSurface);
6832 IWineD3DSurface_UnlockRect(pDestinationSurface);
6833 TRACE("Unlocked src and dst\n");
6838 return hr;
6841 /* Implementation details at http://developer.nvidia.com/attach/6494
6843 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6844 hmm.. no longer supported use
6845 OpenGL evaluators or tessellate surfaces within your application.
6848 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6849 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6851 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6852 FIXME("(%p) : Stub\n", This);
6853 return WINED3D_OK;
6857 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6858 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6860 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6861 FIXME("(%p) : Stub\n", This);
6862 return WINED3D_OK;
6865 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6867 TRACE("(%p) Handle(%d)\n", This, Handle);
6868 FIXME("(%p) : Stub\n", This);
6869 return WINED3D_OK;
6872 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6874 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6875 DDBLTFX BltFx;
6876 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6878 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6879 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6880 return WINED3DERR_INVALIDCALL;
6883 /* Just forward this to the DirectDraw blitting engine */
6884 memset(&BltFx, 0, sizeof(BltFx));
6885 BltFx.dwSize = sizeof(BltFx);
6886 BltFx.u5.dwFillColor = color;
6887 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6890 /* rendertarget and deptth stencil functions */
6891 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6894 /* FIXME: Implelent RenderTargetIndex >0 */
6895 if(RenderTargetIndex > 0)
6896 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6898 *ppRenderTarget = This->renderTarget;
6899 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6900 /* Note inc ref on returned surface */
6901 if(*ppRenderTarget != NULL)
6902 IWineD3DSurface_AddRef(*ppRenderTarget);
6903 return WINED3D_OK;
6906 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6908 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6909 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6910 IWineD3DSwapChainImpl *Swapchain;
6911 HRESULT hr;
6913 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6915 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6916 if(hr != WINED3D_OK) {
6917 ERR("Can't get the swapchain\n");
6918 return hr;
6921 /* Make sure to release the swapchain */
6922 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6924 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6925 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6926 return WINED3DERR_INVALIDCALL;
6928 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6929 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6930 return WINED3DERR_INVALIDCALL;
6933 if(Swapchain->frontBuffer != Front) {
6934 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6936 if(Swapchain->frontBuffer)
6937 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6938 Swapchain->frontBuffer = Front;
6940 if(Swapchain->frontBuffer) {
6941 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6945 if(Back && !Swapchain->backBuffer) {
6946 /* We need memory for the back buffer array - only one back buffer this way */
6947 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6948 if(!Swapchain->backBuffer) {
6949 ERR("Out of memory\n");
6950 return E_OUTOFMEMORY;
6954 if(Swapchain->backBuffer[0] != Back) {
6955 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6956 ENTER_GL();
6957 if(!Swapchain->backBuffer[0]) {
6958 /* GL was told to draw to the front buffer at creation,
6959 * undo that
6961 glDrawBuffer(GL_BACK);
6962 checkGLcall("glDrawBuffer(GL_BACK)");
6963 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6964 Swapchain->presentParms.BackBufferCount = 1;
6965 } else if (!Back) {
6966 /* That makes problems - disable for now */
6967 /* glDrawBuffer(GL_FRONT); */
6968 checkGLcall("glDrawBuffer(GL_FRONT)");
6969 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6970 Swapchain->presentParms.BackBufferCount = 0;
6972 LEAVE_GL();
6974 if(Swapchain->backBuffer[0])
6975 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6976 Swapchain->backBuffer[0] = Back;
6978 if(Swapchain->backBuffer[0]) {
6979 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6980 } else {
6981 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6986 return WINED3D_OK;
6989 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6991 *ppZStencilSurface = This->depthStencilBuffer;
6992 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6994 if(*ppZStencilSurface != NULL) {
6995 /* Note inc ref on returned surface */
6996 IWineD3DSurface_AddRef(*ppZStencilSurface);
6998 return WINED3D_OK;
7001 /* internal static helper functions */
7002 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7003 IWineD3DSurface *RenderSurface);
7005 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7007 HRESULT hr = WINED3D_OK;
7008 WINED3DVIEWPORT viewport;
7010 TRACE("(%p) Swapping rendertarget\n",This);
7011 if (RenderTargetIndex > 0) {
7012 FIXME("(%p) Render targets other than the first are not supported\n",This);
7013 RenderTargetIndex = 0;
7016 /* MSDN says that null disables the render target
7017 but a device must always be associated with a render target
7018 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7020 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7021 for more details
7023 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7024 FIXME("Trying to set render target 0 to NULL\n");
7025 return WINED3DERR_INVALIDCALL;
7027 /* TODO: replace Impl* usage with interface usage */
7028 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7029 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);
7030 return WINED3DERR_INVALIDCALL;
7032 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7033 * builds, but I think wine counts as a 'debug' build for now.
7034 ******************************/
7035 /* If we are trying to set what we already have, don't bother */
7036 if (pRenderTarget == This->renderTarget) {
7037 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7038 } else {
7039 /* Otherwise, set the render target up */
7041 if (FALSE == This->sceneEnded) {
7042 IWineD3DDevice_EndScene(iface);
7044 TRACE("clearing renderer\n");
7045 /* IWineD3DDeviceImpl_CleanRender(iface); */
7046 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7047 depending on the renter target implementation being used.
7048 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7049 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7050 stencil buffer and incure an extra memory overhead */
7051 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7054 if (SUCCEEDED(hr)) {
7055 /* Finally, reset the viewport as the MSDN states. */
7056 /* TODO: Replace impl usage */
7057 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7058 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7059 viewport.X = 0;
7060 viewport.Y = 0;
7061 viewport.MaxZ = 1.0f;
7062 viewport.MinZ = 0.0f;
7063 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7064 } else {
7065 FIXME("Unknown error setting the render target\n");
7067 This->sceneEnded = FALSE;
7068 return hr;
7071 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7073 HRESULT hr = WINED3D_OK;
7074 IWineD3DSurface *tmp;
7076 TRACE("(%p) Swapping z-buffer\n",This);
7078 if (pNewZStencil == This->stencilBufferTarget) {
7079 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7080 } else {
7081 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7082 * depending on the renter target implementation being used.
7083 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7084 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7085 * stencil buffer and incure an extra memory overhead
7086 ******************************************************/
7089 tmp = This->stencilBufferTarget;
7090 This->stencilBufferTarget = pNewZStencil;
7091 /* should we be calling the parent or the wined3d surface? */
7092 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7093 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7094 hr = WINED3D_OK;
7095 /** TODO: glEnable/glDisable on depth/stencil depending on
7096 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7097 **********************************************************/
7100 return hr;
7104 #ifdef GL_VERSION_1_3
7105 /* Internal functions not in DirectX */
7106 /** TODO: move this off to the opengl context manager
7107 *(the swapchain doesn't need to know anything about offscreen rendering!)
7108 ****************************************************/
7110 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7114 TRACE("(%p), %p\n", This, swapchain);
7116 if (swapchain->win != swapchain->drawable) {
7117 /* Set everything back the way it ws */
7118 swapchain->render_ctx = swapchain->glCtx;
7119 swapchain->drawable = swapchain->win;
7121 return WINED3D_OK;
7124 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7125 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7127 int i;
7128 unsigned int width;
7129 unsigned int height;
7130 WINED3DFORMAT format;
7131 WINED3DSURFACE_DESC surfaceDesc;
7132 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7133 surfaceDesc.Width = &width;
7134 surfaceDesc.Height = &height;
7135 surfaceDesc.Format = &format;
7136 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7137 *context = NULL;
7138 /* I need a get width/height function (and should do something with the format) */
7139 for (i = 0; i < CONTEXT_CACHE; ++i) {
7140 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7141 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7142 the pSurface can be set to 0 allowing it to be reused from cache **/
7143 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7144 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7145 *context = &This->contextCache[i];
7146 break;
7148 if (This->contextCache[i].Width == 0) {
7149 This->contextCache[i].pSurface = pSurface;
7150 This->contextCache[i].Width = width;
7151 This->contextCache[i].Height = height;
7152 *context = &This->contextCache[i];
7153 break;
7156 if (i == CONTEXT_CACHE) {
7157 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7158 glContext *dropContext = 0;
7159 for (i = 0; i < CONTEXT_CACHE; i++) {
7160 if (This->contextCache[i].usedcount < minUsage) {
7161 dropContext = &This->contextCache[i];
7162 minUsage = This->contextCache[i].usedcount;
7165 /* clean up the context (this doesn't work for ATI at the moment */
7166 #if 0
7167 glXDestroyContext(swapchain->display, dropContext->context);
7168 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7169 #endif
7170 FIXME("Leak\n");
7171 dropContext->Width = 0;
7172 dropContext->pSurface = pSurface;
7173 *context = dropContext;
7174 } else {
7175 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7176 for (i = 0; i < CONTEXT_CACHE; i++) {
7177 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7181 if (*context != NULL)
7182 return WINED3D_OK;
7183 else
7184 return E_OUTOFMEMORY;
7186 #endif
7188 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7189 * the functionality needs splitting up so that we don't do more than we should do.
7190 * this only seems to impact performance a little.
7191 ******************************/
7192 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7193 IWineD3DSurface *RenderSurface) {
7194 HRESULT ret = WINED3DERR_INVALIDCALL;
7195 BOOL oldRecording;
7196 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7199 * Currently only active for GLX >= 1.3
7200 * for others versions we'll have to use GLXPixmaps
7202 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7203 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7204 * so only check OpenGL version
7205 * ..........................
7206 * I don't believe that it is a problem with NVidia headers,
7207 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7208 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7209 * ATI Note:
7210 * Your application will report GLX version 1.2 on glXQueryVersion.
7211 * However, it is safe to call the GLX 1.3 functions as described below.
7213 #if defined(GL_VERSION_1_3)
7215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7216 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7217 IWineD3DSurface *tmp;
7218 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7219 GLXFBConfig* cfgs = NULL;
7220 int nCfgs = 0;
7221 int attribs[256];
7222 int nAttribs = 0;
7223 IWineD3DSwapChain *currentSwapchain;
7224 IWineD3DSwapChainImpl *swapchain;
7225 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7226 * but switch them off if the StencilSurface is set to NULL
7227 ** *********************************************************/
7228 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7229 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7231 /**TODO:
7232 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7233 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7236 #define PUSH1(att) attribs[nAttribs++] = (att);
7237 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7239 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7241 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7242 IWineD3DSwapChainImpl *impSwapChain;
7243 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7244 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7245 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7248 ENTER_GL();
7250 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7251 PUSH2(GLX_X_RENDERABLE, TRUE);
7252 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7253 TRACE("calling makeglcfg\n");
7254 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7255 PUSH1(None);
7257 TRACE("calling chooseFGConfig\n");
7258 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7259 attribs, &nCfgs);
7261 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7262 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7263 why we failed and only show this message once! */
7264 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"); /**/
7265 nAttribs = 0;
7266 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7267 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7268 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7269 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7270 TRACE("calling makeglcfg\n");
7271 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7272 PUSH1(None);
7273 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7274 attribs, &nCfgs);
7277 if (NULL != cfgs) {
7278 #ifdef EXTRA_TRACES
7279 int i;
7280 for (i = 0; i < nCfgs; ++i) {
7281 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7282 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7283 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7286 if (NULL != This->renderTarget) {
7287 glFlush();
7288 vcheckGLcall("glFlush");
7289 /** This is only useful if the old render target was a swapchain,
7290 * we need to supercede this with a function that displays
7291 * the current buffer on the screen. This is easy to do in glx1.3 but
7292 * we need to do copy-write pixels in glx 1.2.
7293 ************************************************/
7294 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7296 printf("Hit Enter to get next frame ...\n");
7297 getchar();
7299 #endif
7302 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7303 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7304 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7308 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7309 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7310 **********************************************************************/
7311 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7312 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7313 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7314 TRACE("making swapchain active\n");
7315 if (RenderSurface != This->renderTarget) {
7316 BOOL backbuf = FALSE;
7317 int i;
7319 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7320 if(RenderSurface == swapchain->backBuffer[i]) {
7321 backbuf = TRUE;
7322 break;
7326 if (backbuf) {
7327 } else {
7328 /* This could be flagged so that some operations work directly with the front buffer */
7329 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7331 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7332 == False) {
7333 TRACE("Error in setting current context: context %p drawable %ld !\n",
7334 impSwapChain->glCtx, impSwapChain->win);
7337 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7339 checkGLcall("glXMakeContextCurrent");
7341 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7343 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7345 /** ********************************************************************
7346 * This is a quickly hacked out implementation of offscreen textures.
7347 * It will work in most cases but there may be problems if the client
7348 * modifies the texture directly, or expects the contents of the rendertarget
7349 * to be persistent.
7351 * There are some real speed vs compatibility issues here:
7352 * we should really use a new context for every texture, but that eats ram.
7353 * we should also be restoring the texture to the pbuffer but that eats CPU
7354 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7355 * but if this means reusing the display backbuffer then we need to make sure that
7356 * states are correctly preserved.
7357 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7358 * and gain a good performance increase at the cost of compatibility.
7359 * I would suggest that, when this is the case, a user configurable flag be made
7360 * available, allowing the user to choose the best emulated experience for them.
7361 *********************************************************************/
7363 XVisualInfo *visinfo;
7364 glContext *newContext;
7366 /* Here were using a shared context model */
7367 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7368 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7371 /* If the context doesn't exist then create a new one */
7372 /* TODO: This should really be part of findGlContext */
7373 if (NULL == newContext->context) {
7375 TRACE("making new buffer\n");
7376 nAttribs = 0;
7377 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7378 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7379 PUSH1(None);
7381 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7383 /** ****************************************
7384 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7385 *they note:
7386 * In future releases, we may provide the calls glXCreateNewContext,
7387 * glXQueryDrawable and glXMakeContextCurrent.
7388 * so until then we have to use glXGetVisualFromFBConfig &co..
7389 ********************************************/
7392 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7393 if (!visinfo) {
7394 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7395 } else {
7396 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7397 XFree(visinfo);
7400 if (NULL == newContext || NULL == newContext->context) {
7401 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7402 } else {
7403 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7404 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7405 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7408 /* Clean up the old context */
7409 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7410 /* Set the current context of the swapchain to the new context */
7411 impSwapChain->drawable = newContext->drawable;
7412 impSwapChain->render_ctx = newContext->context;
7416 /* Disable recording, and apply the stateblock to the new context
7417 * FIXME: This is a bit of a hack, each context should know it's own state,
7418 * the directX current directX state should then be applied to the context */
7419 oldUpdateStateBlock = This->updateStateBlock;
7420 oldRecording= This->isRecordingState;
7421 This->isRecordingState = FALSE;
7422 This->updateStateBlock = This->stateBlock;
7423 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7425 /* clean up the current rendertargets swapchain (if it belonged to one) */
7426 if (currentSwapchain != NULL) {
7427 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7430 /* Were done with the opengl context management, setup the rendertargets */
7432 tmp = This->renderTarget;
7433 This->renderTarget = RenderSurface;
7434 IWineD3DSurface_AddRef(This->renderTarget);
7435 IWineD3DSurface_Release(tmp);
7438 DWORD value;
7440 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7441 /* Check that the container is not a swapchain member */
7443 IWineD3DSwapChain *tmpSwapChain;
7444 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7445 This->renderUpsideDown = TRUE;
7446 }else{
7447 This->renderUpsideDown = FALSE;
7448 IWineD3DSwapChain_Release(tmpSwapChain);
7450 /* Force updating the cull mode */
7451 TRACE("setting render state\n");
7452 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7453 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7455 /* Force updating projection matrix */
7456 This->last_was_rhw = FALSE;
7457 This->proj_valid = FALSE;
7460 /* Restore recording state */
7461 This->isRecordingState = oldRecording;
7462 This->updateStateBlock = oldUpdateStateBlock;
7464 ret = WINED3D_OK;
7466 if (cfgs != NULL) {
7467 XFree(cfgs);
7468 } else {
7469 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7470 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7473 #undef PUSH1
7474 #undef PUSH2
7475 if ( NULL != impSwapChain) {
7476 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7478 LEAVE_GL();
7480 #endif
7481 return ret;
7484 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7485 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7487 /* TODO: the use of Impl is deprecated. */
7488 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7490 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7492 /* some basic validation checks */
7493 if(This->cursorTexture) {
7494 ENTER_GL();
7495 glDeleteTextures(1, &This->cursorTexture);
7496 LEAVE_GL();
7497 This->cursorTexture = 0;
7500 if(pCursorBitmap) {
7501 /* MSDN: Cursor must be A8R8G8B8 */
7502 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7503 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7504 return WINED3DERR_INVALIDCALL;
7507 /* MSDN: Cursor must be smaller than the display mode */
7508 if(pSur->currentDesc.Width > This->ddraw_width ||
7509 pSur->currentDesc.Height > This->ddraw_height) {
7510 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %ldx%ld\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7511 return WINED3DERR_INVALIDCALL;
7514 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7515 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7516 * Texture and Blitting code to draw the cursor
7518 pSur->Flags |= SFLAG_FORCELOAD;
7519 IWineD3DSurface_PreLoad(pCursorBitmap);
7520 pSur->Flags &= ~SFLAG_FORCELOAD;
7521 /* Do not store the surface's pointer because the application may release
7522 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7523 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7525 This->cursorTexture = pSur->glDescription.textureName;
7526 This->cursorWidth = pSur->currentDesc.Width;
7527 This->cursorHeight = pSur->currentDesc.Height;
7528 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7531 This->xHotSpot = XHotSpot;
7532 This->yHotSpot = YHotSpot;
7533 return WINED3D_OK;
7536 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7538 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7540 This->xScreenSpace = XScreenSpace;
7541 This->yScreenSpace = YScreenSpace;
7543 return;
7547 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7549 TRACE("(%p) : visible(%d)\n", This, bShow);
7551 This->bCursorVisible = bShow;
7553 return WINED3D_OK;
7556 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7558 TRACE("(%p) : state (%lu)\n", This, This->state);
7559 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7560 switch (This->state) {
7561 case WINED3D_OK:
7562 return WINED3D_OK;
7563 case WINED3DERR_DEVICELOST:
7565 ResourceList *resourceList = This->resources;
7566 while (NULL != resourceList) {
7567 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7568 return WINED3DERR_DEVICENOTRESET;
7569 resourceList = resourceList->next;
7571 return WINED3DERR_DEVICELOST;
7573 case WINED3DERR_DRIVERINTERNALERROR:
7574 return WINED3DERR_DRIVERINTERNALERROR;
7577 /* Unknown state */
7578 return WINED3DERR_DRIVERINTERNALERROR;
7582 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7584 /** FIXME: Resource tracking needs to be done,
7585 * The closes we can do to this is set the priorities of all managed textures low
7586 * and then reset them.
7587 ***********************************************************/
7588 FIXME("(%p) : stub\n", This);
7589 return WINED3D_OK;
7592 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7594 /** FIXME: Resource trascking needs to be done.
7595 * in effect this pulls all non only default
7596 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7597 * and should clear down the context and set it up according to pPresentationParameters
7598 ***********************************************************/
7599 FIXME("(%p) : stub\n", This);
7600 return WINED3D_OK;
7603 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7605 /** FIXME: always true at the moment **/
7606 if(bEnableDialogs == FALSE) {
7607 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7609 return WINED3D_OK;
7613 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7615 TRACE("(%p) : pParameters %p\n", This, pParameters);
7617 *pParameters = This->createParms;
7618 return WINED3D_OK;
7621 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7622 IWineD3DSwapChain *swapchain;
7623 HRESULT hrc = WINED3D_OK;
7625 TRACE("Relaying to swapchain\n");
7627 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7628 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7629 IWineD3DSwapChain_Release(swapchain);
7631 return;
7634 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7635 IWineD3DSwapChain *swapchain;
7636 HRESULT hrc = WINED3D_OK;
7638 TRACE("Relaying to swapchain\n");
7640 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7641 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7642 IWineD3DSwapChain_Release(swapchain);
7644 return;
7648 /** ********************************************************
7649 * Notification functions
7650 ** ********************************************************/
7651 /** This function must be called in the release of a resource when ref == 0,
7652 * the contents of resource must still be correct,
7653 * any handels to other resource held by the caller must be closed
7654 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7655 *****************************************************/
7656 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7658 ResourceList* resourceList;
7660 TRACE("(%p) : resource %p\n", This, resource);
7661 #if 0
7662 EnterCriticalSection(&resourceStoreCriticalSection);
7663 #endif
7664 /* add a new texture to the frot of the linked list */
7665 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7666 resourceList->resource = resource;
7668 /* Get the old head */
7669 resourceList->next = This->resources;
7671 This->resources = resourceList;
7672 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7674 #if 0
7675 LeaveCriticalSection(&resourceStoreCriticalSection);
7676 #endif
7677 return;
7680 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7682 ResourceList* resourceList = NULL;
7683 ResourceList* previousResourceList = NULL;
7685 TRACE("(%p) : resource %p\n", This, resource);
7687 #if 0
7688 EnterCriticalSection(&resourceStoreCriticalSection);
7689 #endif
7690 resourceList = This->resources;
7692 while (resourceList != NULL) {
7693 if(resourceList->resource == resource) break;
7694 previousResourceList = resourceList;
7695 resourceList = resourceList->next;
7698 if (resourceList == NULL) {
7699 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7700 #if 0
7701 LeaveCriticalSection(&resourceStoreCriticalSection);
7702 #endif
7703 return;
7704 } else {
7705 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7707 /* make sure we don't leave a hole in the list */
7708 if (previousResourceList != NULL) {
7709 previousResourceList->next = resourceList->next;
7710 } else {
7711 This->resources = resourceList->next;
7714 #if 0
7715 LeaveCriticalSection(&resourceStoreCriticalSection);
7716 #endif
7717 return;
7721 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7723 int counter;
7725 TRACE("(%p) : resource %p\n", This, resource);
7726 switch(IWineD3DResource_GetType(resource)){
7727 case WINED3DRTYPE_SURFACE:
7728 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7729 break;
7730 case WINED3DRTYPE_TEXTURE:
7731 case WINED3DRTYPE_CUBETEXTURE:
7732 case WINED3DRTYPE_VOLUMETEXTURE:
7733 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7734 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7735 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7736 This->stateBlock->textures[counter] = NULL;
7738 if (This->updateStateBlock != This->stateBlock ){
7739 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7740 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7741 This->updateStateBlock->textures[counter] = NULL;
7745 break;
7746 case WINED3DRTYPE_VOLUME:
7747 /* TODO: nothing really? */
7748 break;
7749 case WINED3DRTYPE_VERTEXBUFFER:
7750 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7752 int streamNumber;
7753 TRACE("Cleaning up stream pointers\n");
7755 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7756 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7757 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7759 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7760 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7761 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7762 This->updateStateBlock->streamSource[streamNumber] = 0;
7763 /* Set changed flag? */
7766 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) */
7767 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7768 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7769 This->stateBlock->streamSource[streamNumber] = 0;
7772 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7773 else { /* This shouldn't happen */
7774 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7776 #endif
7780 break;
7781 case WINED3DRTYPE_INDEXBUFFER:
7782 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7783 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7784 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7785 This->updateStateBlock->pIndexData = NULL;
7788 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7789 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7790 This->stateBlock->pIndexData = NULL;
7794 break;
7795 default:
7796 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7797 break;
7801 /* Remove the resoruce from the resourceStore */
7802 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7804 TRACE("Resource released\n");
7808 /**********************************************************
7809 * IWineD3DDevice VTbl follows
7810 **********************************************************/
7812 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7814 /*** IUnknown methods ***/
7815 IWineD3DDeviceImpl_QueryInterface,
7816 IWineD3DDeviceImpl_AddRef,
7817 IWineD3DDeviceImpl_Release,
7818 /*** IWineD3DDevice methods ***/
7819 IWineD3DDeviceImpl_GetParent,
7820 /*** Creation methods**/
7821 IWineD3DDeviceImpl_CreateVertexBuffer,
7822 IWineD3DDeviceImpl_CreateIndexBuffer,
7823 IWineD3DDeviceImpl_CreateStateBlock,
7824 IWineD3DDeviceImpl_CreateSurface,
7825 IWineD3DDeviceImpl_CreateTexture,
7826 IWineD3DDeviceImpl_CreateVolumeTexture,
7827 IWineD3DDeviceImpl_CreateVolume,
7828 IWineD3DDeviceImpl_CreateCubeTexture,
7829 IWineD3DDeviceImpl_CreateQuery,
7830 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7831 IWineD3DDeviceImpl_CreateVertexDeclaration,
7832 IWineD3DDeviceImpl_CreateVertexShader,
7833 IWineD3DDeviceImpl_CreatePixelShader,
7834 IWineD3DDeviceImpl_CreatePalette,
7835 /*** Odd functions **/
7836 IWineD3DDeviceImpl_Init3D,
7837 IWineD3DDeviceImpl_Uninit3D,
7838 IWineD3DDeviceImpl_EnumDisplayModes,
7839 IWineD3DDeviceImpl_EvictManagedResources,
7840 IWineD3DDeviceImpl_GetAvailableTextureMem,
7841 IWineD3DDeviceImpl_GetBackBuffer,
7842 IWineD3DDeviceImpl_GetCreationParameters,
7843 IWineD3DDeviceImpl_GetDeviceCaps,
7844 IWineD3DDeviceImpl_GetDirect3D,
7845 IWineD3DDeviceImpl_GetDisplayMode,
7846 IWineD3DDeviceImpl_SetDisplayMode,
7847 IWineD3DDeviceImpl_GetHWND,
7848 IWineD3DDeviceImpl_SetHWND,
7849 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7850 IWineD3DDeviceImpl_GetRasterStatus,
7851 IWineD3DDeviceImpl_GetSwapChain,
7852 IWineD3DDeviceImpl_Reset,
7853 IWineD3DDeviceImpl_SetDialogBoxMode,
7854 IWineD3DDeviceImpl_SetCursorProperties,
7855 IWineD3DDeviceImpl_SetCursorPosition,
7856 IWineD3DDeviceImpl_ShowCursor,
7857 IWineD3DDeviceImpl_TestCooperativeLevel,
7858 /*** Getters and setters **/
7859 IWineD3DDeviceImpl_SetClipPlane,
7860 IWineD3DDeviceImpl_GetClipPlane,
7861 IWineD3DDeviceImpl_SetClipStatus,
7862 IWineD3DDeviceImpl_GetClipStatus,
7863 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7864 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7865 IWineD3DDeviceImpl_SetDepthStencilSurface,
7866 IWineD3DDeviceImpl_GetDepthStencilSurface,
7867 IWineD3DDeviceImpl_SetFVF,
7868 IWineD3DDeviceImpl_GetFVF,
7869 IWineD3DDeviceImpl_SetGammaRamp,
7870 IWineD3DDeviceImpl_GetGammaRamp,
7871 IWineD3DDeviceImpl_SetIndices,
7872 IWineD3DDeviceImpl_GetIndices,
7873 IWineD3DDeviceImpl_SetLight,
7874 IWineD3DDeviceImpl_GetLight,
7875 IWineD3DDeviceImpl_SetLightEnable,
7876 IWineD3DDeviceImpl_GetLightEnable,
7877 IWineD3DDeviceImpl_SetMaterial,
7878 IWineD3DDeviceImpl_GetMaterial,
7879 IWineD3DDeviceImpl_SetNPatchMode,
7880 IWineD3DDeviceImpl_GetNPatchMode,
7881 IWineD3DDeviceImpl_SetPaletteEntries,
7882 IWineD3DDeviceImpl_GetPaletteEntries,
7883 IWineD3DDeviceImpl_SetPixelShader,
7884 IWineD3DDeviceImpl_GetPixelShader,
7885 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7886 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7887 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7888 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7889 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7890 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7891 IWineD3DDeviceImpl_SetRenderState,
7892 IWineD3DDeviceImpl_GetRenderState,
7893 IWineD3DDeviceImpl_SetRenderTarget,
7894 IWineD3DDeviceImpl_GetRenderTarget,
7895 IWineD3DDeviceImpl_SetFrontBackBuffers,
7896 IWineD3DDeviceImpl_SetSamplerState,
7897 IWineD3DDeviceImpl_GetSamplerState,
7898 IWineD3DDeviceImpl_SetScissorRect,
7899 IWineD3DDeviceImpl_GetScissorRect,
7900 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7901 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7902 IWineD3DDeviceImpl_SetStreamSource,
7903 IWineD3DDeviceImpl_GetStreamSource,
7904 IWineD3DDeviceImpl_SetStreamSourceFreq,
7905 IWineD3DDeviceImpl_GetStreamSourceFreq,
7906 IWineD3DDeviceImpl_SetTexture,
7907 IWineD3DDeviceImpl_GetTexture,
7908 IWineD3DDeviceImpl_SetTextureStageState,
7909 IWineD3DDeviceImpl_GetTextureStageState,
7910 IWineD3DDeviceImpl_SetTransform,
7911 IWineD3DDeviceImpl_GetTransform,
7912 IWineD3DDeviceImpl_SetVertexDeclaration,
7913 IWineD3DDeviceImpl_GetVertexDeclaration,
7914 IWineD3DDeviceImpl_SetVertexShader,
7915 IWineD3DDeviceImpl_GetVertexShader,
7916 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7917 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7918 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7919 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7920 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7921 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7922 IWineD3DDeviceImpl_SetViewport,
7923 IWineD3DDeviceImpl_GetViewport,
7924 IWineD3DDeviceImpl_MultiplyTransform,
7925 IWineD3DDeviceImpl_ValidateDevice,
7926 IWineD3DDeviceImpl_ProcessVertices,
7927 /*** State block ***/
7928 IWineD3DDeviceImpl_BeginStateBlock,
7929 IWineD3DDeviceImpl_EndStateBlock,
7930 /*** Scene management ***/
7931 IWineD3DDeviceImpl_BeginScene,
7932 IWineD3DDeviceImpl_EndScene,
7933 IWineD3DDeviceImpl_Present,
7934 IWineD3DDeviceImpl_Clear,
7935 /*** Drawing ***/
7936 IWineD3DDeviceImpl_DrawPrimitive,
7937 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7938 IWineD3DDeviceImpl_DrawPrimitiveUP,
7939 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7940 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7941 IWineD3DDeviceImpl_DrawRectPatch,
7942 IWineD3DDeviceImpl_DrawTriPatch,
7943 IWineD3DDeviceImpl_DeletePatch,
7944 IWineD3DDeviceImpl_ColorFill,
7945 IWineD3DDeviceImpl_UpdateTexture,
7946 IWineD3DDeviceImpl_UpdateSurface,
7947 IWineD3DDeviceImpl_CopyRects,
7948 IWineD3DDeviceImpl_StretchRect,
7949 IWineD3DDeviceImpl_GetRenderTargetData,
7950 IWineD3DDeviceImpl_GetFrontBufferData,
7951 /*** Internal use IWineD3DDevice methods ***/
7952 IWineD3DDeviceImpl_SetupTextureStates,
7953 /*** object tracking ***/
7954 IWineD3DDeviceImpl_ResourceReleased
7958 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7959 WINED3DRS_ALPHABLENDENABLE ,
7960 WINED3DRS_ALPHAFUNC ,
7961 WINED3DRS_ALPHAREF ,
7962 WINED3DRS_ALPHATESTENABLE ,
7963 WINED3DRS_BLENDOP ,
7964 WINED3DRS_COLORWRITEENABLE ,
7965 WINED3DRS_DESTBLEND ,
7966 WINED3DRS_DITHERENABLE ,
7967 WINED3DRS_FILLMODE ,
7968 WINED3DRS_FOGDENSITY ,
7969 WINED3DRS_FOGEND ,
7970 WINED3DRS_FOGSTART ,
7971 WINED3DRS_LASTPIXEL ,
7972 WINED3DRS_SHADEMODE ,
7973 WINED3DRS_SRCBLEND ,
7974 WINED3DRS_STENCILENABLE ,
7975 WINED3DRS_STENCILFAIL ,
7976 WINED3DRS_STENCILFUNC ,
7977 WINED3DRS_STENCILMASK ,
7978 WINED3DRS_STENCILPASS ,
7979 WINED3DRS_STENCILREF ,
7980 WINED3DRS_STENCILWRITEMASK ,
7981 WINED3DRS_STENCILZFAIL ,
7982 WINED3DRS_TEXTUREFACTOR ,
7983 WINED3DRS_WRAP0 ,
7984 WINED3DRS_WRAP1 ,
7985 WINED3DRS_WRAP2 ,
7986 WINED3DRS_WRAP3 ,
7987 WINED3DRS_WRAP4 ,
7988 WINED3DRS_WRAP5 ,
7989 WINED3DRS_WRAP6 ,
7990 WINED3DRS_WRAP7 ,
7991 WINED3DRS_ZENABLE ,
7992 WINED3DRS_ZFUNC ,
7993 WINED3DRS_ZWRITEENABLE
7996 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7997 WINED3DTSS_ADDRESSW ,
7998 WINED3DTSS_ALPHAARG0 ,
7999 WINED3DTSS_ALPHAARG1 ,
8000 WINED3DTSS_ALPHAARG2 ,
8001 WINED3DTSS_ALPHAOP ,
8002 WINED3DTSS_BUMPENVLOFFSET ,
8003 WINED3DTSS_BUMPENVLSCALE ,
8004 WINED3DTSS_BUMPENVMAT00 ,
8005 WINED3DTSS_BUMPENVMAT01 ,
8006 WINED3DTSS_BUMPENVMAT10 ,
8007 WINED3DTSS_BUMPENVMAT11 ,
8008 WINED3DTSS_COLORARG0 ,
8009 WINED3DTSS_COLORARG1 ,
8010 WINED3DTSS_COLORARG2 ,
8011 WINED3DTSS_COLOROP ,
8012 WINED3DTSS_RESULTARG ,
8013 WINED3DTSS_TEXCOORDINDEX ,
8014 WINED3DTSS_TEXTURETRANSFORMFLAGS
8017 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8018 WINED3DSAMP_ADDRESSU ,
8019 WINED3DSAMP_ADDRESSV ,
8020 WINED3DSAMP_ADDRESSW ,
8021 WINED3DSAMP_BORDERCOLOR ,
8022 WINED3DSAMP_MAGFILTER ,
8023 WINED3DSAMP_MINFILTER ,
8024 WINED3DSAMP_MIPFILTER ,
8025 WINED3DSAMP_MIPMAPLODBIAS ,
8026 WINED3DSAMP_MAXMIPLEVEL ,
8027 WINED3DSAMP_MAXANISOTROPY ,
8028 WINED3DSAMP_SRGBTEXTURE ,
8029 WINED3DSAMP_ELEMENTINDEX
8032 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8033 WINED3DRS_AMBIENT ,
8034 WINED3DRS_AMBIENTMATERIALSOURCE ,
8035 WINED3DRS_CLIPPING ,
8036 WINED3DRS_CLIPPLANEENABLE ,
8037 WINED3DRS_COLORVERTEX ,
8038 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8039 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8040 WINED3DRS_FOGDENSITY ,
8041 WINED3DRS_FOGEND ,
8042 WINED3DRS_FOGSTART ,
8043 WINED3DRS_FOGTABLEMODE ,
8044 WINED3DRS_FOGVERTEXMODE ,
8045 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8046 WINED3DRS_LIGHTING ,
8047 WINED3DRS_LOCALVIEWER ,
8048 WINED3DRS_MULTISAMPLEANTIALIAS ,
8049 WINED3DRS_MULTISAMPLEMASK ,
8050 WINED3DRS_NORMALIZENORMALS ,
8051 WINED3DRS_PATCHEDGESTYLE ,
8052 WINED3DRS_POINTSCALE_A ,
8053 WINED3DRS_POINTSCALE_B ,
8054 WINED3DRS_POINTSCALE_C ,
8055 WINED3DRS_POINTSCALEENABLE ,
8056 WINED3DRS_POINTSIZE ,
8057 WINED3DRS_POINTSIZE_MAX ,
8058 WINED3DRS_POINTSIZE_MIN ,
8059 WINED3DRS_POINTSPRITEENABLE ,
8060 WINED3DRS_RANGEFOGENABLE ,
8061 WINED3DRS_SPECULARMATERIALSOURCE ,
8062 WINED3DRS_TWEENFACTOR ,
8063 WINED3DRS_VERTEXBLEND
8066 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8067 WINED3DTSS_TEXCOORDINDEX ,
8068 WINED3DTSS_TEXTURETRANSFORMFLAGS
8071 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8072 WINED3DSAMP_DMAPOFFSET