wined3d: Registry setting for the amount of simulated texture memory.
[wine/hacks.git] / dlls / wined3d / device.c
blob7af71515b5974fca1bc74bd439e5edf13c45aec3
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");
3890 } else {
3891 TRACE("Disabled RANGEFOG");
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,
4366 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4367 break;
4368 case WINED3DRS_MULTISAMPLEANTIALIAS :
4370 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4371 TRACE("Multisample antialiasing not supported\n");
4372 break;
4375 if(Value) {
4376 glEnable(GL_MULTISAMPLE_ARB);
4377 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4378 } else {
4379 glDisable(GL_MULTISAMPLE_ARB);
4380 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4382 break;
4384 case WINED3DRS_SCISSORTESTENABLE :
4386 if(Value) {
4387 glEnable(GL_SCISSOR_TEST);
4388 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4389 } else {
4390 glDisable(GL_SCISSOR_TEST);
4391 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4393 break;
4395 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4397 if(Value) {
4398 tmpvalue.d = Value;
4399 glEnable(GL_POLYGON_OFFSET_FILL);
4400 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4401 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4402 checkGLcall("glPolygonOffset(...)");
4403 } else {
4404 glDisable(GL_POLYGON_OFFSET_FILL);
4405 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4407 break;
4409 case WINED3DRS_ANTIALIASEDLINEENABLE :
4411 if(Value) {
4412 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4413 glEnable(GL_BLEND);
4414 checkGLcall("glEnable(GL_BLEND)");
4415 glEnable(GL_LINE_SMOOTH);
4416 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4417 } else {
4418 glDisable(GL_BLEND);
4419 checkGLcall("glDisable(GL_BLEND)");
4420 glDisable(GL_LINE_SMOOTH);
4421 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4423 break;
4425 case WINED3DRS_DEPTHBIAS :
4427 if(Value) {
4428 tmpvalue.d = Value;
4429 glEnable(GL_POLYGON_OFFSET_FILL);
4430 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4431 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4432 checkGLcall("glPolygonOffset(...)");
4433 } else {
4434 glDisable(GL_POLYGON_OFFSET_FILL);
4435 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4437 break;
4440 case WINED3DRS_TEXTUREPERSPECTIVE :
4442 if (Value)
4443 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4444 else
4445 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4446 break;
4449 case WINED3DRS_STIPPLEDALPHA :
4451 if (Value)
4452 ERR(" Stippled Alpha not supported yet.\n");
4453 break;
4455 case WINED3DRS_ANTIALIAS :
4457 if (Value)
4458 ERR(" Antialias not supported yet.\n");
4459 break;
4461 default:
4462 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4465 LEAVE_GL();
4467 return WINED3D_OK;
4470 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4473 *pValue = This->stateBlock->renderState[State];
4474 return WINED3D_OK;
4477 /*****
4478 * Get / Set Sampler States
4479 * TODO: Verify against dx9 definitions
4480 *****/
4482 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 * SetSampler is designed to allow for more than the standard up to 8 textures
4486 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4487 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4489 * http://developer.nvidia.com/object/General_FAQ.html#t6
4491 * There are two new settings for GForce
4492 * the sampler one:
4493 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4494 * and the texture one:
4495 * GL_MAX_TEXTURE_COORDS_ARB.
4496 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4497 ******************/
4498 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4499 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4500 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4501 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4502 return WINED3DERR_INVALIDCALL;
4505 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4506 debug_d3dsamplerstate(Type), Type, Value);
4507 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4508 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4509 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4511 /* Handle recording of state blocks */
4512 if (This->isRecordingState) {
4513 TRACE("Recording... not performing anything\n");
4514 return WINED3D_OK;
4517 return WINED3D_OK;
4520 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 /** TODO: check that sampler is in range **/
4523 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4524 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4526 return WINED3D_OK;
4529 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 ENTER_GL();
4533 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4534 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4535 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4536 LEAVE_GL();
4538 return WINED3D_OK;
4541 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 GLint scissorBox[4];
4545 ENTER_GL();
4546 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4547 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4548 pRect->left = scissorBox[0];
4549 pRect->top = scissorBox[1];
4550 pRect->right = scissorBox[0] + scissorBox[2];
4551 pRect->bottom = scissorBox[1] + scissorBox[3];
4552 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4553 LEAVE_GL();
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4559 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4561 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4563 This->updateStateBlock->vertexDecl = pDecl;
4564 This->updateStateBlock->changed.vertexDecl = TRUE;
4565 This->updateStateBlock->set.vertexDecl = TRUE;
4567 if (This->isRecordingState) {
4568 TRACE("Recording... not performing anything\n");
4571 if (NULL != pDecl) {
4572 IWineD3DVertexDeclaration_AddRef(pDecl);
4574 if (NULL != oldDecl) {
4575 IWineD3DVertexDeclaration_Release(oldDecl);
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4585 *ppDecl = This->stateBlock->vertexDecl;
4586 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4587 return WINED3D_OK;
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4594 This->updateStateBlock->vertexShader = pShader;
4595 This->updateStateBlock->changed.vertexShader = TRUE;
4596 This->updateStateBlock->set.vertexShader = TRUE;
4598 if (This->isRecordingState) {
4599 TRACE("Recording... not performing anything\n");
4602 if (NULL != pShader) {
4603 IWineD3DVertexShader_AddRef(pShader);
4605 if (NULL != oldShader) {
4606 IWineD3DVertexShader_Release(oldShader);
4609 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4611 * TODO: merge HAL shaders context switching from prototype
4613 return WINED3D_OK;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 if (NULL == ppShader) {
4620 return WINED3DERR_INVALIDCALL;
4622 *ppShader = This->stateBlock->vertexShader;
4623 if( NULL != *ppShader)
4624 IWineD3DVertexShader_AddRef(*ppShader);
4626 TRACE("(%p) : returning %p\n", This, *ppShader);
4627 return WINED3D_OK;
4630 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4631 IWineD3DDevice *iface,
4632 UINT start,
4633 CONST BOOL *srcData,
4634 UINT count) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 int i, cnt = min(count, MAX_CONST_B - start);
4639 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4640 iface, srcData, start, count);
4642 if (srcData == NULL || cnt < 0)
4643 return WINED3DERR_INVALIDCALL;
4645 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4646 for (i = 0; i < cnt; i++)
4647 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4649 for (i = start; i < cnt + start; ++i) {
4650 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4651 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4654 return WINED3D_OK;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4658 IWineD3DDevice *iface,
4659 UINT start,
4660 BOOL *dstData,
4661 UINT count) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 int cnt = min(count, MAX_CONST_B - start);
4666 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4667 iface, dstData, start, count);
4669 if (dstData == NULL || cnt < 0)
4670 return WINED3DERR_INVALIDCALL;
4672 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4673 return WINED3D_OK;
4676 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4677 IWineD3DDevice *iface,
4678 UINT start,
4679 CONST int *srcData,
4680 UINT count) {
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 int i, cnt = min(count, MAX_CONST_I - start);
4685 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4686 iface, srcData, start, count);
4688 if (srcData == NULL || cnt < 0)
4689 return WINED3DERR_INVALIDCALL;
4691 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4692 for (i = 0; i < cnt; i++)
4693 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4694 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4696 for (i = start; i < cnt + start; ++i) {
4697 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4698 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4705 IWineD3DDevice *iface,
4706 UINT start,
4707 int *dstData,
4708 UINT count) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 int cnt = min(count, MAX_CONST_I - start);
4713 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4714 iface, dstData, start, count);
4716 if (dstData == NULL || cnt < 0)
4717 return WINED3DERR_INVALIDCALL;
4719 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4724 IWineD3DDevice *iface,
4725 UINT start,
4726 CONST float *srcData,
4727 UINT count) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4732 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4733 iface, srcData, start, count);
4735 if (srcData == NULL || cnt < 0)
4736 return WINED3DERR_INVALIDCALL;
4738 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4739 for (i = 0; i < cnt; i++)
4740 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4741 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4743 for (i = start; i < cnt + start; ++i) {
4744 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4745 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4748 return WINED3D_OK;
4751 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4752 IWineD3DDevice *iface,
4753 UINT start,
4754 float *dstData,
4755 UINT count) {
4757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4758 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4760 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4761 iface, dstData, start, count);
4763 if (dstData == NULL || cnt < 0)
4764 return WINED3DERR_INVALIDCALL;
4766 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4767 return WINED3D_OK;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4773 This->updateStateBlock->pixelShader = pShader;
4774 This->updateStateBlock->changed.pixelShader = TRUE;
4775 This->updateStateBlock->set.pixelShader = TRUE;
4777 /* Handle recording of state blocks */
4778 if (This->isRecordingState) {
4779 TRACE("Recording... not performing anything\n");
4782 if (NULL != pShader) {
4783 IWineD3DPixelShader_AddRef(pShader);
4785 if (NULL != oldShader) {
4786 IWineD3DPixelShader_Release(oldShader);
4789 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4791 * TODO: merge HAL shaders context switching from prototype
4793 return WINED3D_OK;
4796 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4799 if (NULL == ppShader) {
4800 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4801 return WINED3DERR_INVALIDCALL;
4804 *ppShader = This->stateBlock->pixelShader;
4805 if (NULL != *ppShader) {
4806 IWineD3DPixelShader_AddRef(*ppShader);
4808 TRACE("(%p) : returning %p\n", This, *ppShader);
4809 return WINED3D_OK;
4812 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4813 IWineD3DDevice *iface,
4814 UINT start,
4815 CONST BOOL *srcData,
4816 UINT count) {
4818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4819 int i, cnt = min(count, MAX_CONST_B - start);
4821 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4822 iface, srcData, start, count);
4824 if (srcData == NULL || cnt < 0)
4825 return WINED3DERR_INVALIDCALL;
4827 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4828 for (i = 0; i < cnt; i++)
4829 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4831 for (i = start; i < cnt + start; ++i) {
4832 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4833 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4840 IWineD3DDevice *iface,
4841 UINT start,
4842 BOOL *dstData,
4843 UINT count) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 int cnt = min(count, MAX_CONST_B - start);
4848 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4849 iface, dstData, start, count);
4851 if (dstData == NULL || cnt < 0)
4852 return WINED3DERR_INVALIDCALL;
4854 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4855 return WINED3D_OK;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4859 IWineD3DDevice *iface,
4860 UINT start,
4861 CONST int *srcData,
4862 UINT count) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 int i, cnt = min(count, MAX_CONST_I - start);
4867 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4868 iface, srcData, start, count);
4870 if (srcData == NULL || cnt < 0)
4871 return WINED3DERR_INVALIDCALL;
4873 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4874 for (i = 0; i < cnt; i++)
4875 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4876 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4878 for (i = start; i < cnt + start; ++i) {
4879 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4880 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4887 IWineD3DDevice *iface,
4888 UINT start,
4889 int *dstData,
4890 UINT count) {
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 int cnt = min(count, MAX_CONST_I - start);
4895 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4896 iface, dstData, start, count);
4898 if (dstData == NULL || cnt < 0)
4899 return WINED3DERR_INVALIDCALL;
4901 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4902 return WINED3D_OK;
4905 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4906 IWineD3DDevice *iface,
4907 UINT start,
4908 CONST float *srcData,
4909 UINT count) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4912 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4914 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4915 iface, srcData, start, count);
4917 if (srcData == NULL || cnt < 0)
4918 return WINED3DERR_INVALIDCALL;
4920 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4921 for (i = 0; i < cnt; i++)
4922 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4923 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4925 for (i = start; i < cnt + start; ++i) {
4926 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4927 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4930 return WINED3D_OK;
4933 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4934 IWineD3DDevice *iface,
4935 UINT start,
4936 float *dstData,
4937 UINT count) {
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4942 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4943 iface, dstData, start, count);
4945 if (dstData == NULL || cnt < 0)
4946 return WINED3DERR_INVALIDCALL;
4948 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4949 return WINED3D_OK;
4952 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4953 static HRESULT
4954 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4955 char *dest_ptr, *dest_conv = NULL;
4956 unsigned int i;
4957 DWORD DestFVF = dest->fvf;
4958 D3DVIEWPORT9 vp;
4959 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4960 BOOL doClip;
4961 int numTextures;
4963 if (SrcFVF & D3DFVF_NORMAL) {
4964 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4967 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4968 ERR("Source has no position mask\n");
4969 return WINED3DERR_INVALIDCALL;
4972 /* We might access VBOs from this code, so hold the lock */
4973 ENTER_GL();
4975 if (dest->resource.allocatedMemory == NULL) {
4976 /* This may happen if we do direct locking into a vbo. Unlikely,
4977 * but theoretically possible(ddraw processvertices test)
4979 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4980 if(!dest->resource.allocatedMemory) {
4981 LEAVE_GL();
4982 ERR("Out of memory\n");
4983 return E_OUTOFMEMORY;
4985 if(dest->vbo) {
4986 void *src;
4987 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4988 checkGLcall("glBindBufferARB");
4989 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4990 if(src) {
4991 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4993 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4994 checkGLcall("glUnmapBufferARB");
4998 /* Get a pointer into the destination vbo(create one if none exists) and
4999 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5001 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5002 CreateVBO(dest);
5005 if(dest->vbo) {
5006 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5007 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5008 if(!dest_conv) {
5009 ERR("glMapBuffer failed\n");
5010 /* Continue without storing converted vertices */
5014 /* Should I clip?
5015 * a) D3DRS_CLIPPING is enabled
5016 * b) WINED3DVOP_CLIP is passed
5018 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5019 static BOOL warned = FALSE;
5021 * The clipping code is not quite correct. Some things need
5022 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5023 * so disable clipping for now.
5024 * (The graphics in Half-Life are broken, and my processvertices
5025 * test crashes with IDirect3DDevice3)
5026 doClip = TRUE;
5028 doClip = FALSE;
5029 if(!warned) {
5030 warned = TRUE;
5031 FIXME("Clipping is broken and disabled for now\n");
5033 } else doClip = FALSE;
5034 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5035 if(dest_conv) {
5036 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5039 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5040 WINED3DTS_VIEW,
5041 &view_mat);
5042 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5043 WINED3DTS_PROJECTION,
5044 &proj_mat);
5045 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5046 WINED3DTS_WORLDMATRIX(0),
5047 &world_mat);
5049 TRACE("View mat:\n");
5050 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); \
5051 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); \
5052 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); \
5053 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); \
5055 TRACE("Proj mat:\n");
5056 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); \
5057 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); \
5058 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); \
5059 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); \
5061 TRACE("World mat:\n");
5062 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); \
5063 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); \
5064 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); \
5065 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); \
5067 /* Get the viewport */
5068 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5069 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5070 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5072 multiply_matrix(&mat,&view_mat,&world_mat);
5073 multiply_matrix(&mat,&proj_mat,&mat);
5075 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5077 for (i = 0; i < dwCount; i+= 1) {
5078 unsigned int tex_index;
5080 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5081 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5082 /* The position first */
5083 float *p =
5084 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5085 float x, y, z, rhw;
5086 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5088 /* Multiplication with world, view and projection matrix */
5089 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);
5090 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);
5091 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);
5092 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);
5094 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5096 /* WARNING: The following things are taken from d3d7 and were not yet checked
5097 * against d3d8 or d3d9!
5100 /* Clipping conditions: From
5101 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5103 * A vertex is clipped if it does not match the following requirements
5104 * -rhw < x <= rhw
5105 * -rhw < y <= rhw
5106 * 0 < z <= rhw
5107 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5109 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5110 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5114 if( doClip == FALSE ||
5115 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5116 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5117 ( rhw > eps ) ) ) {
5119 /* "Normal" viewport transformation (not clipped)
5120 * 1) The values are divided by rhw
5121 * 2) The y axis is negative, so multiply it with -1
5122 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5123 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5124 * 4) Multiply x with Width/2 and add Width/2
5125 * 5) The same for the height
5126 * 6) Add the viewpoint X and Y to the 2D coordinates and
5127 * The minimum Z value to z
5128 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5130 * Well, basically it's simply a linear transformation into viewport
5131 * coordinates
5134 x /= rhw;
5135 y /= rhw;
5136 z /= rhw;
5138 y *= -1;
5140 x *= vp.Width / 2;
5141 y *= vp.Height / 2;
5142 z *= vp.MaxZ - vp.MinZ;
5144 x += vp.Width / 2 + vp.X;
5145 y += vp.Height / 2 + vp.Y;
5146 z += vp.MinZ;
5148 rhw = 1 / rhw;
5149 } else {
5150 /* That vertex got clipped
5151 * Contrary to OpenGL it is not dropped completely, it just
5152 * undergoes a different calculation.
5154 TRACE("Vertex got clipped\n");
5155 x += rhw;
5156 y += rhw;
5158 x /= 2;
5159 y /= 2;
5161 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5162 * outside of the main vertex buffer memory. That needs some more
5163 * investigation...
5167 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5170 ( (float *) dest_ptr)[0] = x;
5171 ( (float *) dest_ptr)[1] = y;
5172 ( (float *) dest_ptr)[2] = z;
5173 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5175 dest_ptr += 3 * sizeof(float);
5177 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5178 dest_ptr += sizeof(float);
5181 if(dest_conv) {
5182 float w = 1 / rhw;
5183 ( (float *) dest_conv)[0] = x * w;
5184 ( (float *) dest_conv)[1] = y * w;
5185 ( (float *) dest_conv)[2] = z * w;
5186 ( (float *) dest_conv)[3] = w;
5188 dest_conv += 3 * sizeof(float);
5190 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5191 dest_conv += sizeof(float);
5195 if (DestFVF & D3DFVF_PSIZE) {
5196 dest_ptr += sizeof(DWORD);
5197 if(dest_conv) dest_conv += sizeof(DWORD);
5199 if (DestFVF & D3DFVF_NORMAL) {
5200 float *normal =
5201 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5202 /* AFAIK this should go into the lighting information */
5203 FIXME("Didn't expect the destination to have a normal\n");
5204 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5205 if(dest_conv) {
5206 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5210 if (DestFVF & D3DFVF_DIFFUSE) {
5211 DWORD *color_d =
5212 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5213 if(!color_d) {
5214 static BOOL warned = FALSE;
5216 if(warned == FALSE) {
5217 ERR("No diffuse color in source, but destination has one\n");
5218 warned = TRUE;
5221 *( (DWORD *) dest_ptr) = 0xffffffff;
5222 dest_ptr += sizeof(DWORD);
5224 if(dest_conv) {
5225 *( (DWORD *) dest_conv) = 0xffffffff;
5226 dest_conv += sizeof(DWORD);
5229 else {
5230 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5231 if(dest_conv) {
5232 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5233 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5234 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5235 dest_conv += sizeof(DWORD);
5240 if (DestFVF & D3DFVF_SPECULAR) {
5241 /* What's the color value in the feedback buffer? */
5242 DWORD *color_s =
5243 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5244 if(!color_s) {
5245 static BOOL warned = FALSE;
5247 if(warned == FALSE) {
5248 ERR("No specular color in source, but destination has one\n");
5249 warned = TRUE;
5252 *( (DWORD *) dest_ptr) = 0xFF000000;
5253 dest_ptr += sizeof(DWORD);
5255 if(dest_conv) {
5256 *( (DWORD *) dest_conv) = 0xFF000000;
5257 dest_conv += sizeof(DWORD);
5260 else {
5261 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5262 if(dest_conv) {
5263 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5264 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5265 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5266 dest_conv += sizeof(DWORD);
5271 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5272 float *tex_coord =
5273 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5274 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5275 if(!tex_coord) {
5276 ERR("No source texture, but destination requests one\n");
5277 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5278 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5280 else {
5281 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5282 if(dest_conv) {
5283 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5289 if(dest_conv) {
5290 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5291 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5294 LEAVE_GL();
5296 return WINED3D_OK;
5298 #undef copy_and_next
5300 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5303 WineDirect3DVertexStridedData strided;
5304 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5306 /* We don't need the source vbo because this buffer is only used as
5307 * a source for ProcessVertices. Avoid wasting resources by converting the
5308 * buffer and loading the VBO
5310 if(SrcImpl->vbo) {
5311 TRACE("Releaseing the source vbo, it won't be needed\n");
5313 if(!SrcImpl->resource.allocatedMemory) {
5314 /* Rescue the data from the buffer */
5315 void *src;
5316 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5317 if(!SrcImpl->resource.allocatedMemory) {
5318 ERR("Out of memory\n");
5319 return E_OUTOFMEMORY;
5322 ENTER_GL();
5323 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5324 checkGLcall("glBindBufferARB");
5326 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5327 if(src) {
5328 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5331 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5332 checkGLcall("glUnmapBufferARB");
5333 } else {
5334 ENTER_GL();
5337 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5338 checkGLcall("glBindBufferARB");
5339 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5340 checkGLcall("glDeleteBuffersARB");
5341 LEAVE_GL();
5343 SrcImpl->vbo = 0;
5346 memset(&strided, 0, sizeof(strided));
5347 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5349 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5352 /*****
5353 * Apply / Get / Set Texture Stage States
5354 * TODO: Verify against dx9 definitions
5355 *****/
5357 /* 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 */
5358 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5360 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5361 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5363 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5365 /* Check that the stage is within limits */
5366 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5367 TRACE("Attempt to access invalid texture rejected\n");
5368 return;
5371 ENTER_GL();
5373 switch (Type) {
5374 case WINED3DTSS_ALPHAOP :
5375 case WINED3DTSS_COLOROP :
5376 /* nothing to do as moved to drawprim for now */
5377 break;
5378 case WINED3DTSS_ADDRESSW :
5379 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5380 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5381 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5383 } else {
5384 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5385 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5386 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5387 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5389 #endif
5390 case WINED3DTSS_TEXCOORDINDEX :
5392 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5394 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5395 one flag, you can still specify an index value, which the system uses to
5396 determine the texture wrapping mode.
5397 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5398 means use the vertex position (camera-space) as the input texture coordinates
5399 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5400 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5401 to the TEXCOORDINDEX value */
5404 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5406 switch (Value & 0xFFFF0000) {
5407 case D3DTSS_TCI_PASSTHRU:
5408 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5409 glDisable(GL_TEXTURE_GEN_S);
5410 glDisable(GL_TEXTURE_GEN_T);
5411 glDisable(GL_TEXTURE_GEN_R);
5412 glDisable(GL_TEXTURE_GEN_Q);
5413 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5414 break;
5416 case D3DTSS_TCI_CAMERASPACEPOSITION:
5417 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5418 as the input texture coordinates for this stage's texture transformation. This
5419 equates roughly to EYE_LINEAR */
5421 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5422 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5423 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5424 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5425 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5427 glMatrixMode(GL_MODELVIEW);
5428 glPushMatrix();
5429 glLoadIdentity();
5430 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5431 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5432 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5433 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5434 glPopMatrix();
5436 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5437 glEnable(GL_TEXTURE_GEN_S);
5438 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5439 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5440 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5441 glEnable(GL_TEXTURE_GEN_T);
5442 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5443 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5444 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5445 glEnable(GL_TEXTURE_GEN_R);
5446 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5447 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5448 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5450 break;
5452 case D3DTSS_TCI_CAMERASPACENORMAL:
5454 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5455 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5456 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5457 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5458 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5459 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5461 glMatrixMode(GL_MODELVIEW);
5462 glPushMatrix();
5463 glLoadIdentity();
5464 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5465 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5466 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5467 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5468 glPopMatrix();
5470 glEnable(GL_TEXTURE_GEN_S);
5471 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5472 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5473 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5474 glEnable(GL_TEXTURE_GEN_T);
5475 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5476 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5477 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5478 glEnable(GL_TEXTURE_GEN_R);
5479 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5480 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5481 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5484 break;
5486 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5488 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5489 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5490 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5491 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5492 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5493 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5495 glMatrixMode(GL_MODELVIEW);
5496 glPushMatrix();
5497 glLoadIdentity();
5498 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5499 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5500 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5501 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5502 glPopMatrix();
5504 glEnable(GL_TEXTURE_GEN_S);
5505 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5506 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5507 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5508 glEnable(GL_TEXTURE_GEN_T);
5509 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5510 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5511 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5512 glEnable(GL_TEXTURE_GEN_R);
5513 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5514 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5515 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5518 break;
5520 /* Unhandled types: */
5521 default:
5522 /* Todo: */
5523 /* ? disable GL_TEXTURE_GEN_n ? */
5524 glDisable(GL_TEXTURE_GEN_S);
5525 glDisable(GL_TEXTURE_GEN_T);
5526 glDisable(GL_TEXTURE_GEN_R);
5527 glDisable(GL_TEXTURE_GEN_Q);
5528 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5529 break;
5532 break;
5534 /* Unhandled */
5535 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5536 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);
5537 break;
5539 case WINED3DTSS_BUMPENVMAT00 :
5540 case WINED3DTSS_BUMPENVMAT01 :
5541 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5542 break;
5543 case WINED3DTSS_BUMPENVMAT10 :
5544 case WINED3DTSS_BUMPENVMAT11 :
5545 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5546 break;
5548 case WINED3DTSS_BUMPENVLSCALE :
5549 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5550 break;
5552 case WINED3DTSS_BUMPENVLOFFSET :
5553 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5554 break;
5556 case WINED3DTSS_RESULTARG :
5557 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5558 break;
5560 default:
5561 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5562 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5565 LEAVE_GL();
5567 return;
5570 /*****
5571 * Get / Set Texture Stage States
5572 * TODO: Verify against dx9 definitions
5573 *****/
5574 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5579 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5581 /* Reject invalid texture units */
5582 if (Stage >= GL_LIMITS(texture_stages)) {
5583 TRACE("Attempt to access invalid texture rejected\n");
5584 return WINED3DERR_INVALIDCALL;
5587 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5588 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5589 This->updateStateBlock->textureState[Stage][Type] = Value;
5591 return WINED3D_OK;
5594 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5597 *pValue = This->updateStateBlock->textureState[Stage][Type];
5598 return WINED3D_OK;
5601 /*****
5602 * Get / Set Texture
5603 *****/
5604 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5607 IWineD3DBaseTexture *oldTexture;
5609 oldTexture = This->updateStateBlock->textures[Stage];
5610 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5612 #if 0 /* TODO: check so vertex textures */
5613 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5614 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5615 return WINED3D_OK;
5617 #endif
5619 /* Reject invalid texture units */
5620 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5621 WARN("Attempt to access invalid texture rejected\n");
5622 return WINED3DERR_INVALIDCALL;
5625 if(pTexture != NULL) {
5626 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5628 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5629 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5630 return WINED3DERR_INVALIDCALL;
5634 oldTexture = This->updateStateBlock->textures[Stage];
5635 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5636 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5638 This->updateStateBlock->set.textures[Stage] = TRUE;
5639 This->updateStateBlock->changed.textures[Stage] = TRUE;
5640 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5641 This->updateStateBlock->textures[Stage] = pTexture;
5643 /* Handle recording of state blocks */
5644 if (This->isRecordingState) {
5645 TRACE("Recording... not performing anything\n");
5646 return WINED3D_OK;
5649 /** NOTE: MSDN says that setTexture increases the reference count,
5650 * and the the application nust set the texture back to null (or have a leaky application),
5651 * This means we should pass the refcount up to the parent
5652 *******************************/
5653 if (NULL != This->updateStateBlock->textures[Stage]) {
5654 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5657 if (NULL != oldTexture) {
5658 IWineD3DBaseTexture_Release(oldTexture);
5661 /* Reset color keying */
5662 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5663 BOOL enable_ckey = FALSE;
5665 if(pTexture) {
5666 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5667 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5670 if(enable_ckey) {
5671 glAlphaFunc(GL_NOTEQUAL, 0.0);
5672 checkGLcall("glAlphaFunc");
5676 return WINED3D_OK;
5679 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5683 /* Reject invalid texture units */
5684 if (Stage >= GL_LIMITS(sampler_stages)) {
5685 TRACE("Attempt to access invalid texture rejected\n");
5686 return WINED3DERR_INVALIDCALL;
5688 *ppTexture=This->updateStateBlock->textures[Stage];
5689 if (*ppTexture)
5690 IWineD3DBaseTexture_AddRef(*ppTexture);
5691 else
5692 return WINED3DERR_INVALIDCALL;
5693 return WINED3D_OK;
5696 /*****
5697 * Get Back Buffer
5698 *****/
5699 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5700 IWineD3DSurface **ppBackBuffer) {
5701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 IWineD3DSwapChain *swapChain;
5703 HRESULT hr;
5705 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5707 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5708 if (hr == WINED3D_OK) {
5709 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5710 IWineD3DSwapChain_Release(swapChain);
5711 } else {
5712 *ppBackBuffer = NULL;
5714 return hr;
5717 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5719 WARN("(%p) : stub, calling idirect3d for now\n", This);
5720 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5723 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 IWineD3DSwapChain *swapChain;
5726 HRESULT hr;
5728 if(iSwapChain > 0) {
5729 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5730 if (hr == WINED3D_OK) {
5731 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5732 IWineD3DSwapChain_Release(swapChain);
5733 } else {
5734 FIXME("(%p) Error getting display mode\n", This);
5736 } else {
5737 /* Don't read the real display mode,
5738 but return the stored mode instead. X11 can't change the color
5739 depth, and some apps are pretty angry if they SetDisplayMode from
5740 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5742 Also don't relay to the swapchain because with ddraw it's possible
5743 that there isn't a swapchain at all */
5744 pMode->Width = This->ddraw_width;
5745 pMode->Height = This->ddraw_height;
5746 pMode->Format = This->ddraw_format;
5747 pMode->RefreshRate = 0;
5748 hr = WINED3D_OK;
5751 return hr;
5754 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 TRACE("(%p)->(%p)\n", This, hWnd);
5758 This->ddraw_window = hWnd;
5759 return WINED3D_OK;
5762 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 TRACE("(%p)->(%p)\n", This, hWnd);
5766 *hWnd = This->ddraw_window;
5767 return WINED3D_OK;
5770 /*****
5771 * Stateblock related functions
5772 *****/
5774 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 IWineD3DStateBlockImpl *object;
5777 HRESULT temp_result;
5779 TRACE("(%p)", This);
5781 if (This->isRecordingState) {
5782 return WINED3DERR_INVALIDCALL;
5785 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5786 if (NULL == object ) {
5787 FIXME("(%p)Error allocating memory for stateblock\n", This);
5788 return E_OUTOFMEMORY;
5790 TRACE("(%p) created object %p\n", This, object);
5791 object->wineD3DDevice= This;
5792 /** FIXME: object->parent = parent; **/
5793 object->parent = NULL;
5794 object->blockType = WINED3DSBT_ALL;
5795 object->ref = 1;
5796 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5798 temp_result = allocate_shader_constants(object);
5799 if (WINED3D_OK != temp_result)
5800 return temp_result;
5802 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5803 This->updateStateBlock = object;
5804 This->isRecordingState = TRUE;
5806 TRACE("(%p) recording stateblock %p\n",This , object);
5807 return WINED3D_OK;
5810 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5813 if (!This->isRecordingState) {
5814 FIXME("(%p) not recording! returning error\n", This);
5815 *ppStateBlock = NULL;
5816 return WINED3DERR_INVALIDCALL;
5819 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5820 This->isRecordingState = FALSE;
5821 This->updateStateBlock = This->stateBlock;
5822 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5823 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5824 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5825 return WINED3D_OK;
5828 /*****
5829 * Scene related functions
5830 *****/
5831 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5832 /* At the moment we have no need for any functionality at the beginning
5833 of a scene */
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 TRACE("(%p) : stub\n", This);
5836 return WINED3D_OK;
5839 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5841 TRACE("(%p)\n", This);
5842 ENTER_GL();
5843 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5844 glFlush();
5845 checkGLcall("glFlush");
5847 TRACE("End Scene\n");
5848 if(This->renderTarget != NULL) {
5850 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5851 IUnknown *targetContainer = NULL;
5852 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5853 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5854 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5855 /** always dirtify for now. we must find a better way to see that surface have been modified
5856 (Modifications should will only occur via draw-primitive, but we do need better locking
5857 switching to render-to-texture should remove the overhead though.
5859 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5860 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5861 IWineD3DSurface_PreLoad(This->renderTarget);
5862 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5863 IUnknown_Release(targetContainer);
5866 This->sceneEnded = TRUE;
5867 LEAVE_GL();
5868 return WINED3D_OK;
5871 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5872 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5873 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5875 IWineD3DSwapChain *swapChain = NULL;
5876 int i;
5877 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5879 TRACE("(%p) Presenting the frame\n", This);
5881 for(i = 0 ; i < swapchains ; i ++) {
5883 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5884 TRACE("presentinng chain %d, %p\n", i, swapChain);
5885 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5886 IWineD3DSwapChain_Release(swapChain);
5889 return WINED3D_OK;
5892 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5893 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5897 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5898 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5899 GLbitfield glMask = 0;
5900 GLboolean old_ztest;
5901 GLfloat old_z_clear_value;
5902 GLint old_stencil_clear_value;
5903 GLfloat old_color_clear_value[4];
5904 unsigned int i;
5905 CONST D3DRECT* curRect;
5907 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5908 Count, pRects, Flags, Z, Stencil);
5910 ENTER_GL();
5912 glEnable(GL_SCISSOR_TEST);
5913 checkGLcall("glEnable GL_SCISSOR_TEST");
5915 if (Count > 0 && pRects) {
5916 curRect = pRects;
5917 } else {
5918 curRect = NULL;
5921 /* Only set the values up once, as they are not changing */
5922 if (Flags & D3DCLEAR_STENCIL) {
5923 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5924 glClearStencil(Stencil);
5925 checkGLcall("glClearStencil");
5926 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5927 glStencilMask(0xFFFFFFFF);
5930 if (Flags & D3DCLEAR_ZBUFFER) {
5931 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5932 glDepthMask(GL_TRUE);
5933 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5934 glClearDepth(Z);
5935 checkGLcall("glClearDepth");
5936 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5939 if (Flags & D3DCLEAR_TARGET) {
5940 TRACE("Clearing screen with glClear to color %lx\n", Color);
5941 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5942 glClearColor(D3DCOLOR_R(Color),
5943 D3DCOLOR_G(Color),
5944 D3DCOLOR_B(Color),
5945 D3DCOLOR_A(Color));
5946 checkGLcall("glClearColor");
5948 /* Clear ALL colors! */
5949 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5950 glMask = glMask | GL_COLOR_BUFFER_BIT;
5953 /* Now process each rect in turn */
5954 for (i = 0; i < Count || i == 0; i++) {
5956 if (curRect) {
5957 /* Note gl uses lower left, width/height */
5958 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5959 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5960 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5961 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5962 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5963 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5964 checkGLcall("glScissor");
5965 } else {
5966 glScissor(This->stateBlock->viewport.X,
5967 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5968 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5969 This->stateBlock->viewport.Width,
5970 This->stateBlock->viewport.Height);
5971 checkGLcall("glScissor");
5974 /* Clear the selected rectangle (or full screen) */
5975 glClear(glMask);
5976 checkGLcall("glClear");
5978 /* Step to the next rectangle */
5979 if (curRect) curRect = curRect + sizeof(D3DRECT);
5982 /* Restore the old values (why..?) */
5983 if (Flags & D3DCLEAR_STENCIL) {
5984 glClearStencil(old_stencil_clear_value);
5985 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5987 if (Flags & D3DCLEAR_ZBUFFER) {
5988 glDepthMask(old_ztest);
5989 glClearDepth(old_z_clear_value);
5991 if (Flags & D3DCLEAR_TARGET) {
5992 glClearColor(old_color_clear_value[0],
5993 old_color_clear_value[1],
5994 old_color_clear_value[2],
5995 old_color_clear_value[3]);
5996 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5997 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5998 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5999 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6002 glDisable(GL_SCISSOR_TEST);
6003 checkGLcall("glDisable");
6004 LEAVE_GL();
6006 return WINED3D_OK;
6009 /*****
6010 * Drawing functions
6011 *****/
6012 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6013 UINT PrimitiveCount) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 This->stateBlock->streamIsUP = FALSE;
6018 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6019 debug_d3dprimitivetype(PrimitiveType),
6020 StartVertex, PrimitiveCount);
6021 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6022 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6025 return WINED3D_OK;
6028 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6029 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6030 D3DPRIMITIVETYPE PrimitiveType,
6031 INT baseVIndex, UINT minIndex,
6032 UINT NumVertices, UINT startIndex, UINT primCount) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 UINT idxStride = 2;
6036 IWineD3DIndexBuffer *pIB;
6037 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6039 pIB = This->stateBlock->pIndexData;
6040 This->stateBlock->streamIsUP = FALSE;
6042 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6043 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6044 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6046 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6047 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6048 idxStride = 2;
6049 } else {
6050 idxStride = 4;
6053 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6054 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6056 return WINED3D_OK;
6059 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6060 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6061 UINT VertexStreamZeroStride) {
6062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6064 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6065 debug_d3dprimitivetype(PrimitiveType),
6066 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6068 /* release the stream source */
6069 if (This->stateBlock->streamSource[0] != NULL) {
6070 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6073 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6074 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6075 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6076 This->stateBlock->streamIsUP = TRUE;
6078 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6079 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6081 /* MSDN specifies stream zero settings must be set to NULL */
6082 This->stateBlock->streamStride[0] = 0;
6083 This->stateBlock->streamSource[0] = NULL;
6085 /*stream zero settings set to null at end, as per the msdn */
6086 return WINED3D_OK;
6089 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6090 UINT MinVertexIndex, UINT NumVertices,
6091 UINT PrimitiveCount, CONST void* pIndexData,
6092 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6093 UINT VertexStreamZeroStride) {
6094 int idxStride;
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6097 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6098 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6099 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6100 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6102 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6103 idxStride = 2;
6104 } else {
6105 idxStride = 4;
6108 /* release the stream and index data */
6109 if (This->stateBlock->streamSource[0] != NULL) {
6110 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6112 if (This->stateBlock->pIndexData) {
6113 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6116 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6117 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6118 This->stateBlock->streamIsUP = TRUE;
6119 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6121 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6123 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6124 This->stateBlock->streamSource[0] = NULL;
6125 This->stateBlock->streamStride[0] = 0;
6126 This->stateBlock->pIndexData = NULL;
6128 return WINED3D_OK;
6131 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6133 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6134 return WINED3D_OK;
6136 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6137 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 HRESULT hr = WINED3D_OK;
6140 WINED3DRESOURCETYPE sourceType;
6141 WINED3DRESOURCETYPE destinationType;
6142 int i ,levels;
6144 /* TODO: think about moving the code into IWineD3DBaseTexture */
6146 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6148 /* verify that the source and destination textures aren't NULL */
6149 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6150 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6151 This, pSourceTexture, pDestinationTexture);
6152 hr = WINED3DERR_INVALIDCALL;
6155 if (pSourceTexture == pDestinationTexture) {
6156 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6157 This, pSourceTexture, pDestinationTexture);
6158 hr = WINED3DERR_INVALIDCALL;
6160 /* Verify that the source and destination textures are the same type */
6161 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6162 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6164 if (sourceType != destinationType) {
6165 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6166 This);
6167 hr = WINED3DERR_INVALIDCALL;
6170 /* check that both textures have the identical numbers of levels */
6171 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6172 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6173 hr = WINED3DERR_INVALIDCALL;
6176 if (WINED3D_OK == hr) {
6178 /* Make sure that the destination texture is loaded */
6179 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6181 /* Update every surface level of the texture */
6182 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6184 switch (sourceType) {
6185 case WINED3DRTYPE_TEXTURE:
6187 IWineD3DSurface *srcSurface;
6188 IWineD3DSurface *destSurface;
6190 for (i = 0 ; i < levels ; ++i) {
6191 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6192 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6193 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6194 IWineD3DSurface_Release(srcSurface);
6195 IWineD3DSurface_Release(destSurface);
6196 if (WINED3D_OK != hr) {
6197 WARN("(%p) : Call to update surface failed\n", This);
6198 return hr;
6202 break;
6203 case WINED3DRTYPE_CUBETEXTURE:
6205 IWineD3DSurface *srcSurface;
6206 IWineD3DSurface *destSurface;
6207 WINED3DCUBEMAP_FACES faceType;
6209 for (i = 0 ; i < levels ; ++i) {
6210 /* Update each cube face */
6211 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6212 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6213 if (WINED3D_OK != hr) {
6214 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6215 } else {
6216 TRACE("Got srcSurface %p\n", srcSurface);
6218 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6219 if (WINED3D_OK != hr) {
6220 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6221 } else {
6222 TRACE("Got desrSurface %p\n", destSurface);
6224 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6225 IWineD3DSurface_Release(srcSurface);
6226 IWineD3DSurface_Release(destSurface);
6227 if (WINED3D_OK != hr) {
6228 WARN("(%p) : Call to update surface failed\n", This);
6229 return hr;
6234 break;
6235 #if 0 /* TODO: Add support for volume textures */
6236 case WINED3DRTYPE_VOLUMETEXTURE:
6238 IWineD3DVolume srcVolume = NULL;
6239 IWineD3DSurface destVolume = NULL;
6241 for (i = 0 ; i < levels ; ++i) {
6242 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6243 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6244 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6245 IWineD3DVolume_Release(srcSurface);
6246 IWineD3DVolume_Release(destSurface);
6247 if (WINED3D_OK != hr) {
6248 WARN("(%p) : Call to update volume failed\n", This);
6249 return hr;
6253 break;
6254 #endif
6255 default:
6256 FIXME("(%p) : Unsupported source and destination type\n", This);
6257 hr = WINED3DERR_INVALIDCALL;
6261 return hr;
6264 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6265 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6266 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6269 TRACE("(%p) : stub\n", This);
6270 return WINED3D_OK;
6272 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6274 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6275 * NOTE It may be best to move the code into surface to occomplish this
6276 ****************************************/
6278 WINED3DSURFACE_DESC surfaceDesc;
6279 unsigned int surfaceWidth, surfaceHeight;
6280 glDescriptor *targetGlDescription = NULL;
6281 glDescriptor *surfaceGlDescription = NULL;
6282 IWineD3DSwapChainImpl *container = NULL;
6284 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6285 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6286 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6288 surfaceDesc.Width = &surfaceWidth;
6289 surfaceDesc.Height = &surfaceHeight;
6290 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6291 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6293 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6294 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6295 ENTER_GL();
6296 /* TODO: opengl Context switching for swapchains etc... */
6297 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6298 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6299 glReadBuffer(GL_BACK);
6300 vcheckGLcall("glReadBuffer(GL_BACK)");
6301 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6302 glReadBuffer(GL_FRONT);
6303 vcheckGLcall("glReadBuffer(GL_FRONT)");
6304 } else if (pRenderTarget == This->depthStencilBuffer) {
6305 FIXME("Reading of depthstencil not yet supported\n");
6308 glReadPixels(surfaceGlDescription->target,
6309 surfaceGlDescription->level,
6310 surfaceWidth,
6311 surfaceHeight,
6312 surfaceGlDescription->glFormat,
6313 surfaceGlDescription->glType,
6314 (void *)IWineD3DSurface_GetData(pSurface));
6315 vcheckGLcall("glReadPixels(...)");
6316 if(NULL != container ){
6317 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6319 } else {
6320 IWineD3DBaseTexture *container;
6321 GLenum textureDimensions = GL_TEXTURE_2D;
6323 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6324 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6325 IWineD3DBaseTexture_Release(container);
6327 /* TODO: 2D -> Cube surface coppies etc.. */
6328 if (surfaceGlDescription->target != textureDimensions) {
6329 FIXME("(%p) : Texture dimension mismatch\n", This);
6331 glEnable(textureDimensions);
6332 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6333 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6334 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6335 vcheckGLcall("glBindTexture");
6336 glGetTexImage(surfaceGlDescription->target,
6337 surfaceGlDescription->level,
6338 surfaceGlDescription->glFormat,
6339 surfaceGlDescription->glType,
6340 (void *)IWineD3DSurface_GetData(pSurface));
6341 glDisable(textureDimensions);
6342 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6345 LEAVE_GL();
6346 return WINED3D_OK;
6349 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6350 IWineD3DSwapChain *swapChain;
6351 HRESULT hr;
6352 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6353 if(hr == WINED3D_OK) {
6354 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6355 IWineD3DSwapChain_Release(swapChain);
6357 return hr;
6360 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6362 /* return a sensible default */
6363 *pNumPasses = 1;
6364 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6365 FIXME("(%p) : stub\n", This);
6366 return WINED3D_OK;
6369 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6371 int j;
6372 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6373 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6374 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6375 return WINED3DERR_INVALIDCALL;
6377 for (j = 0; j < 256; ++j) {
6378 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6379 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6380 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6381 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6383 TRACE("(%p) : returning\n", This);
6384 return WINED3D_OK;
6387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6389 int j;
6390 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6391 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6392 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6393 return WINED3DERR_INVALIDCALL;
6395 for (j = 0; j < 256; ++j) {
6396 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6397 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6398 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6399 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6401 TRACE("(%p) : returning\n", This);
6402 return WINED3D_OK;
6405 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6407 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6408 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6409 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6410 return WINED3DERR_INVALIDCALL;
6412 /*TODO: stateblocks */
6413 This->currentPalette = PaletteNumber;
6414 TRACE("(%p) : returning\n", This);
6415 return WINED3D_OK;
6418 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 if (PaletteNumber == NULL) {
6421 WARN("(%p) : returning Invalid Call\n", This);
6422 return WINED3DERR_INVALIDCALL;
6424 /*TODO: stateblocks */
6425 *PaletteNumber = This->currentPalette;
6426 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6427 return WINED3D_OK;
6430 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 static BOOL showFixmes = TRUE;
6433 if (showFixmes) {
6434 FIXME("(%p) : stub\n", This);
6435 showFixmes = FALSE;
6438 This->softwareVertexProcessing = bSoftware;
6439 return WINED3D_OK;
6443 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6445 static BOOL showFixmes = TRUE;
6446 if (showFixmes) {
6447 FIXME("(%p) : stub\n", This);
6448 showFixmes = FALSE;
6450 return This->softwareVertexProcessing;
6454 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6456 IWineD3DSwapChain *swapChain;
6457 HRESULT hr;
6459 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6461 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6462 if(hr == WINED3D_OK){
6463 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6464 IWineD3DSwapChain_Release(swapChain);
6465 }else{
6466 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6468 return hr;
6472 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 static BOOL showfixmes = TRUE;
6475 if(nSegments != 0.0f) {
6476 if( showfixmes) {
6477 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6478 showfixmes = FALSE;
6481 return WINED3D_OK;
6484 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6486 static BOOL showfixmes = TRUE;
6487 if( showfixmes) {
6488 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6489 showfixmes = FALSE;
6491 return 0.0f;
6494 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6496 /** TODO: remove casts to IWineD3DSurfaceImpl
6497 * NOTE: move code to surface to accomplish this
6498 ****************************************/
6499 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6500 int srcWidth, srcHeight;
6501 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6502 WINED3DFORMAT destFormat, srcFormat;
6503 UINT destSize;
6504 int destLeft, destTop;
6505 WINED3DPOOL srcPool, destPool;
6506 int offset = 0;
6507 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6508 glDescriptor *glDescription = NULL;
6509 GLenum textureDimensions = GL_TEXTURE_2D;
6510 IWineD3DBaseTexture *baseTexture;
6512 WINED3DSURFACE_DESC winedesc;
6514 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6515 memset(&winedesc, 0, sizeof(winedesc));
6516 winedesc.Width = &srcSurfaceWidth;
6517 winedesc.Height = &srcSurfaceHeight;
6518 winedesc.Pool = &srcPool;
6519 winedesc.Format = &srcFormat;
6521 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6523 winedesc.Width = &destSurfaceWidth;
6524 winedesc.Height = &destSurfaceHeight;
6525 winedesc.Pool = &destPool;
6526 winedesc.Format = &destFormat;
6527 winedesc.Size = &destSize;
6529 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6531 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6532 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6533 return WINED3DERR_INVALIDCALL;
6536 if (destFormat == WINED3DFMT_UNKNOWN) {
6537 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6538 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6540 /* Get the update surface description */
6541 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6544 /* Make sure the surface is loaded and up to date */
6545 IWineD3DSurface_PreLoad(pDestinationSurface);
6547 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6549 ENTER_GL();
6551 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6552 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6553 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6554 destLeft = pDestPoint ? pDestPoint->x : 0;
6555 destTop = pDestPoint ? pDestPoint->y : 0;
6558 /* This function doesn't support compressed textures
6559 the pitch is just bytesPerPixel * width */
6560 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6561 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6562 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6563 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6565 /* TODO DXT formats */
6567 if(pSourceRect != NULL && pSourceRect->top != 0){
6568 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6570 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6571 ,This
6572 ,glDescription->level
6573 ,destLeft
6574 ,destTop
6575 ,srcWidth
6576 ,srcHeight
6577 ,glDescription->glFormat
6578 ,glDescription->glType
6579 ,IWineD3DSurface_GetData(pSourceSurface)
6582 /* Sanity check */
6583 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6585 /* need to lock the surface to get the data */
6586 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6589 /* TODO: Cube and volume support */
6590 if(rowoffset != 0){
6591 /* not a whole row so we have to do it a line at a time */
6592 int j;
6594 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6595 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6597 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6599 glTexSubImage2D(glDescription->target
6600 ,glDescription->level
6601 ,destLeft
6603 ,srcWidth
6605 ,glDescription->glFormat
6606 ,glDescription->glType
6607 ,data /* could be quicker using */
6609 data += rowoffset;
6612 } else { /* Full width, so just write out the whole texture */
6614 if (WINED3DFMT_DXT1 == destFormat ||
6615 WINED3DFMT_DXT2 == destFormat ||
6616 WINED3DFMT_DXT3 == destFormat ||
6617 WINED3DFMT_DXT4 == destFormat ||
6618 WINED3DFMT_DXT5 == destFormat) {
6619 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6620 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6621 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6622 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6623 } if (destFormat != srcFormat) {
6624 FIXME("Updating mixed format compressed texture is not curretly support\n");
6625 } else {
6626 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6627 glDescription->level,
6628 glDescription->glFormatInternal,
6629 srcWidth,
6630 srcHeight,
6632 destSize,
6633 IWineD3DSurface_GetData(pSourceSurface));
6635 } else {
6636 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6640 } else {
6641 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6643 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6644 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6645 data returned by GetData non-power2 width/height with hardware non-power2
6646 pow2Width/height are set to surface width height, repacking isn't needed so it
6647 doesn't matter which function gets called. */
6648 glTexSubImage2D(glDescription->target
6649 ,glDescription->level
6650 ,destLeft
6651 ,destTop
6652 ,srcWidth
6653 ,srcHeight
6654 ,glDescription->glFormat
6655 ,glDescription->glType
6656 ,IWineD3DSurface_GetData(pSourceSurface)
6658 } else {
6660 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6661 glTexSubImage2D(glDescription->target
6662 ,glDescription->level
6663 ,destLeft
6664 ,destTop
6665 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6666 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6667 ,glDescription->glFormat
6668 ,glDescription->glType
6669 ,IWineD3DSurface_GetData(pSourceSurface)
6675 checkGLcall("glTexSubImage2D");
6677 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6678 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6679 * surface bigger than it needs to be hmm.. */
6680 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6681 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6682 IWineD3DBaseTexture_Release(baseTexture);
6685 glDisable(textureDimensions); /* This needs to be managed better.... */
6686 LEAVE_GL();
6688 return WINED3D_OK;
6691 /* Used by DirectX 8 */
6692 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6693 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6694 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6697 HRESULT hr = WINED3D_OK;
6698 WINED3DFORMAT srcFormat, destFormat;
6699 UINT srcWidth, destWidth;
6700 UINT srcHeight, destHeight;
6701 UINT srcSize;
6702 WINED3DSURFACE_DESC winedesc;
6704 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6705 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6708 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6709 memset(&winedesc, 0, sizeof(winedesc));
6711 winedesc.Format = &srcFormat;
6712 winedesc.Width = &srcWidth;
6713 winedesc.Height = &srcHeight;
6714 winedesc.Size = &srcSize;
6715 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6717 winedesc.Format = &destFormat;
6718 winedesc.Width = &destWidth;
6719 winedesc.Height = &destHeight;
6720 winedesc.Size = NULL;
6721 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6723 /* Check that the source and destination formats match */
6724 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6725 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6726 return WINED3DERR_INVALIDCALL;
6727 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6728 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6729 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6730 destFormat = srcFormat;
6733 /* Quick if complete copy ... */
6734 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6736 if (srcWidth == destWidth && srcHeight == destHeight) {
6737 WINED3DLOCKED_RECT lrSrc;
6738 WINED3DLOCKED_RECT lrDst;
6739 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6740 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6741 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6743 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6745 IWineD3DSurface_UnlockRect(pSourceSurface);
6746 IWineD3DSurface_UnlockRect(pDestinationSurface);
6747 TRACE("Unlocked src and dst\n");
6749 } else {
6751 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6752 hr = WINED3DERR_INVALIDCALL;
6755 } else {
6757 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6759 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6760 unsigned int i;
6762 /* Copy rect by rect */
6763 for (i = 0; i < cRects; ++i) {
6764 CONST RECT* r = &pSourceRectsArray[i];
6765 CONST POINT* p = &pDestPointsArray[i];
6766 int copyperline;
6767 int j;
6768 WINED3DLOCKED_RECT lrSrc;
6769 WINED3DLOCKED_RECT lrDst;
6770 RECT dest_rect;
6772 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6773 if (srcFormat == WINED3DFMT_DXT1) {
6774 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6775 } else {
6776 copyperline = ((r->right - r->left) * bytesPerPixel);
6779 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6780 dest_rect.left = p->x;
6781 dest_rect.top = p->y;
6782 dest_rect.right = p->x + (r->right - r->left);
6783 dest_rect.bottom= p->y + (r->bottom - r->top);
6784 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6785 TRACE("Locked src and dst\n");
6787 /* Find where to start */
6788 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6789 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6791 IWineD3DSurface_UnlockRect(pSourceSurface);
6792 IWineD3DSurface_UnlockRect(pDestinationSurface);
6793 TRACE("Unlocked src and dst\n");
6795 } else {
6796 unsigned int i;
6797 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6798 int copyperline;
6799 int j;
6800 WINED3DLOCKED_RECT lrSrc;
6801 WINED3DLOCKED_RECT lrDst;
6802 RECT dest_rect;
6804 for(i=0; i < cRects; i++) {
6805 CONST RECT* r = &pSourceRectsArray[i];
6807 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6808 if (srcFormat == WINED3DFMT_DXT1) {
6809 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6810 } else {
6811 copyperline = ((r->right - r->left) * bytesPerPixel);
6813 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6814 dest_rect.left = 0;
6815 dest_rect.top = 0;
6816 dest_rect.right = r->right - r->left;
6817 dest_rect.bottom= r->bottom - r->top;
6818 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6819 TRACE("Locked src and dst\n");
6820 /* Find where to start */
6821 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6822 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6824 IWineD3DSurface_UnlockRect(pSourceSurface);
6825 IWineD3DSurface_UnlockRect(pDestinationSurface);
6826 TRACE("Unlocked src and dst\n");
6831 return hr;
6834 /* Implementation details at http://developer.nvidia.com/attach/6494
6836 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6837 hmm.. no longer supported use
6838 OpenGL evaluators or tessellate surfaces within your application.
6841 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6842 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6844 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6845 FIXME("(%p) : Stub\n", This);
6846 return WINED3D_OK;
6850 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6853 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6854 FIXME("(%p) : Stub\n", This);
6855 return WINED3D_OK;
6858 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6860 TRACE("(%p) Handle(%d)\n", This, Handle);
6861 FIXME("(%p) : Stub\n", This);
6862 return WINED3D_OK;
6865 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6867 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6868 DDBLTFX BltFx;
6869 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6871 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6872 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6873 return WINED3DERR_INVALIDCALL;
6876 /* Just forward this to the DirectDraw blitting engine */
6877 memset(&BltFx, 0, sizeof(BltFx));
6878 BltFx.dwSize = sizeof(BltFx);
6879 BltFx.u5.dwFillColor = color;
6880 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6883 /* rendertarget and deptth stencil functions */
6884 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6887 /* FIXME: Implelent RenderTargetIndex >0 */
6888 if(RenderTargetIndex > 0)
6889 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6891 *ppRenderTarget = This->renderTarget;
6892 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6893 /* Note inc ref on returned surface */
6894 if(*ppRenderTarget != NULL)
6895 IWineD3DSurface_AddRef(*ppRenderTarget);
6896 return WINED3D_OK;
6899 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6901 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6902 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6903 IWineD3DSwapChainImpl *Swapchain;
6904 HRESULT hr;
6906 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6908 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6909 if(hr != WINED3D_OK) {
6910 ERR("Can't get the swapchain\n");
6911 return hr;
6914 /* Make sure to release the swapchain */
6915 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6917 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6918 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6919 return WINED3DERR_INVALIDCALL;
6921 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6922 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6923 return WINED3DERR_INVALIDCALL;
6926 if(Swapchain->frontBuffer != Front) {
6927 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6929 if(Swapchain->frontBuffer)
6930 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6931 Swapchain->frontBuffer = Front;
6933 if(Swapchain->frontBuffer) {
6934 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6938 if(Back && !Swapchain->backBuffer) {
6939 /* We need memory for the back buffer array - only one back buffer this way */
6940 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6941 if(!Swapchain->backBuffer) {
6942 ERR("Out of memory\n");
6943 return E_OUTOFMEMORY;
6947 if(Swapchain->backBuffer[0] != Back) {
6948 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6949 ENTER_GL();
6950 if(!Swapchain->backBuffer[0]) {
6951 /* GL was told to draw to the front buffer at creation,
6952 * undo that
6954 glDrawBuffer(GL_BACK);
6955 checkGLcall("glDrawBuffer(GL_BACK)");
6956 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6957 Swapchain->presentParms.BackBufferCount = 1;
6958 } else if (!Back) {
6959 /* That makes problems - disable for now */
6960 /* glDrawBuffer(GL_FRONT); */
6961 checkGLcall("glDrawBuffer(GL_FRONT)");
6962 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6963 Swapchain->presentParms.BackBufferCount = 0;
6965 LEAVE_GL();
6967 if(Swapchain->backBuffer[0])
6968 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6969 Swapchain->backBuffer[0] = Back;
6971 if(Swapchain->backBuffer[0]) {
6972 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6973 } else {
6974 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6979 return WINED3D_OK;
6982 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6984 *ppZStencilSurface = This->depthStencilBuffer;
6985 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6987 if(*ppZStencilSurface != NULL) {
6988 /* Note inc ref on returned surface */
6989 IWineD3DSurface_AddRef(*ppZStencilSurface);
6991 return WINED3D_OK;
6994 /* internal static helper functions */
6995 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6996 IWineD3DSurface *RenderSurface);
6998 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7000 HRESULT hr = WINED3D_OK;
7001 WINED3DVIEWPORT viewport;
7003 TRACE("(%p) Swapping rendertarget\n",This);
7004 if (RenderTargetIndex > 0) {
7005 FIXME("(%p) Render targets other than the first are not supported\n",This);
7006 RenderTargetIndex = 0;
7009 /* MSDN says that null disables the render target
7010 but a device must always be associated with a render target
7011 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7013 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7014 for more details
7016 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7017 FIXME("Trying to set render target 0 to NULL\n");
7018 return WINED3DERR_INVALIDCALL;
7020 /* TODO: replace Impl* usage with interface usage */
7021 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7022 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);
7023 return WINED3DERR_INVALIDCALL;
7025 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7026 * builds, but I think wine counts as a 'debug' build for now.
7027 ******************************/
7028 /* If we are trying to set what we already have, don't bother */
7029 if (pRenderTarget == This->renderTarget) {
7030 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7031 } else {
7032 /* Otherwise, set the render target up */
7034 if (FALSE == This->sceneEnded) {
7035 IWineD3DDevice_EndScene(iface);
7037 TRACE("clearing renderer\n");
7038 /* IWineD3DDeviceImpl_CleanRender(iface); */
7039 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7040 depending on the renter target implementation being used.
7041 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7042 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7043 stencil buffer and incure an extra memory overhead */
7044 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7047 if (SUCCEEDED(hr)) {
7048 /* Finally, reset the viewport as the MSDN states. */
7049 /* TODO: Replace impl usage */
7050 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7051 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7052 viewport.X = 0;
7053 viewport.Y = 0;
7054 viewport.MaxZ = 1.0f;
7055 viewport.MinZ = 0.0f;
7056 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7057 } else {
7058 FIXME("Unknown error setting the render target\n");
7060 This->sceneEnded = FALSE;
7061 return hr;
7064 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7066 HRESULT hr = WINED3D_OK;
7067 IWineD3DSurface *tmp;
7069 TRACE("(%p) Swapping z-buffer\n",This);
7071 if (pNewZStencil == This->stencilBufferTarget) {
7072 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7073 } else {
7074 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7075 * depending on the renter target implementation being used.
7076 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7077 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7078 * stencil buffer and incure an extra memory overhead
7079 ******************************************************/
7082 tmp = This->stencilBufferTarget;
7083 This->stencilBufferTarget = pNewZStencil;
7084 /* should we be calling the parent or the wined3d surface? */
7085 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7086 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7087 hr = WINED3D_OK;
7088 /** TODO: glEnable/glDisable on depth/stencil depending on
7089 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7090 **********************************************************/
7093 return hr;
7097 #ifdef GL_VERSION_1_3
7098 /* Internal functions not in DirectX */
7099 /** TODO: move this off to the opengl context manager
7100 *(the swapchain doesn't need to know anything about offscreen rendering!)
7101 ****************************************************/
7103 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7107 TRACE("(%p), %p\n", This, swapchain);
7109 if (swapchain->win != swapchain->drawable) {
7110 /* Set everything back the way it ws */
7111 swapchain->render_ctx = swapchain->glCtx;
7112 swapchain->drawable = swapchain->win;
7114 return WINED3D_OK;
7117 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7118 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7120 int i;
7121 unsigned int width;
7122 unsigned int height;
7123 WINED3DFORMAT format;
7124 WINED3DSURFACE_DESC surfaceDesc;
7125 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7126 surfaceDesc.Width = &width;
7127 surfaceDesc.Height = &height;
7128 surfaceDesc.Format = &format;
7129 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7130 *context = NULL;
7131 /* I need a get width/height function (and should do something with the format) */
7132 for (i = 0; i < CONTEXT_CACHE; ++i) {
7133 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7134 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7135 the pSurface can be set to 0 allowing it to be reused from cache **/
7136 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7137 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7138 *context = &This->contextCache[i];
7139 break;
7141 if (This->contextCache[i].Width == 0) {
7142 This->contextCache[i].pSurface = pSurface;
7143 This->contextCache[i].Width = width;
7144 This->contextCache[i].Height = height;
7145 *context = &This->contextCache[i];
7146 break;
7149 if (i == CONTEXT_CACHE) {
7150 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7151 glContext *dropContext = 0;
7152 for (i = 0; i < CONTEXT_CACHE; i++) {
7153 if (This->contextCache[i].usedcount < minUsage) {
7154 dropContext = &This->contextCache[i];
7155 minUsage = This->contextCache[i].usedcount;
7158 /* clean up the context (this doesn't work for ATI at the moment */
7159 #if 0
7160 glXDestroyContext(swapchain->display, dropContext->context);
7161 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7162 #endif
7163 FIXME("Leak\n");
7164 dropContext->Width = 0;
7165 dropContext->pSurface = pSurface;
7166 *context = dropContext;
7167 } else {
7168 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7169 for (i = 0; i < CONTEXT_CACHE; i++) {
7170 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7174 if (*context != NULL)
7175 return WINED3D_OK;
7176 else
7177 return E_OUTOFMEMORY;
7179 #endif
7181 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7182 * the functionality needs splitting up so that we don't do more than we should do.
7183 * this only seems to impact performance a little.
7184 ******************************/
7185 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7186 IWineD3DSurface *RenderSurface) {
7187 HRESULT ret = WINED3DERR_INVALIDCALL;
7188 BOOL oldRecording;
7189 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7192 * Currently only active for GLX >= 1.3
7193 * for others versions we'll have to use GLXPixmaps
7195 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7196 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7197 * so only check OpenGL version
7198 * ..........................
7199 * I don't believe that it is a problem with NVidia headers,
7200 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7201 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7202 * ATI Note:
7203 * Your application will report GLX version 1.2 on glXQueryVersion.
7204 * However, it is safe to call the GLX 1.3 functions as described below.
7206 #if defined(GL_VERSION_1_3)
7208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7209 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7210 IWineD3DSurface *tmp;
7211 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7212 GLXFBConfig* cfgs = NULL;
7213 int nCfgs = 0;
7214 int attribs[256];
7215 int nAttribs = 0;
7216 IWineD3DSwapChain *currentSwapchain;
7217 IWineD3DSwapChainImpl *swapchain;
7218 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7219 * but switch them off if the StencilSurface is set to NULL
7220 ** *********************************************************/
7221 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7222 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7224 /**TODO:
7225 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7226 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7229 #define PUSH1(att) attribs[nAttribs++] = (att);
7230 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7232 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7234 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7235 IWineD3DSwapChainImpl *impSwapChain;
7236 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7237 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7238 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7241 ENTER_GL();
7243 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7244 PUSH2(GLX_X_RENDERABLE, TRUE);
7245 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7246 TRACE("calling makeglcfg\n");
7247 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7248 PUSH1(None);
7250 TRACE("calling chooseFGConfig\n");
7251 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7252 attribs, &nCfgs);
7254 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7255 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7256 why we failed and only show this message once! */
7257 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"); /**/
7258 nAttribs = 0;
7259 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7260 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7261 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7262 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7263 TRACE("calling makeglcfg\n");
7264 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7265 PUSH1(None);
7266 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7267 attribs, &nCfgs);
7270 if (NULL != cfgs) {
7271 #ifdef EXTRA_TRACES
7272 int i;
7273 for (i = 0; i < nCfgs; ++i) {
7274 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7275 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7276 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7279 if (NULL != This->renderTarget) {
7280 glFlush();
7281 vcheckGLcall("glFlush");
7282 /** This is only useful if the old render target was a swapchain,
7283 * we need to supercede this with a function that displays
7284 * the current buffer on the screen. This is easy to do in glx1.3 but
7285 * we need to do copy-write pixels in glx 1.2.
7286 ************************************************/
7287 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7289 printf("Hit Enter to get next frame ...\n");
7290 getchar();
7292 #endif
7295 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7296 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7297 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7301 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7302 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7303 **********************************************************************/
7304 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7305 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7306 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7307 TRACE("making swapchain active\n");
7308 if (RenderSurface != This->renderTarget) {
7309 BOOL backbuf = FALSE;
7310 int i;
7312 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7313 if(RenderSurface == swapchain->backBuffer[i]) {
7314 backbuf = TRUE;
7315 break;
7319 if (backbuf) {
7320 } else {
7321 /* This could be flagged so that some operations work directly with the front buffer */
7322 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7324 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7325 == False) {
7326 TRACE("Error in setting current context: context %p drawable %ld !\n",
7327 impSwapChain->glCtx, impSwapChain->win);
7330 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7332 checkGLcall("glXMakeContextCurrent");
7334 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7336 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7338 /** ********************************************************************
7339 * This is a quickly hacked out implementation of offscreen textures.
7340 * It will work in most cases but there may be problems if the client
7341 * modifies the texture directly, or expects the contents of the rendertarget
7342 * to be persistent.
7344 * There are some real speed vs compatibility issues here:
7345 * we should really use a new context for every texture, but that eats ram.
7346 * we should also be restoring the texture to the pbuffer but that eats CPU
7347 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7348 * but if this means reusing the display backbuffer then we need to make sure that
7349 * states are correctly preserved.
7350 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7351 * and gain a good performance increase at the cost of compatibility.
7352 * I would suggest that, when this is the case, a user configurable flag be made
7353 * available, allowing the user to choose the best emulated experience for them.
7354 *********************************************************************/
7356 XVisualInfo *visinfo;
7357 glContext *newContext;
7359 /* Here were using a shared context model */
7360 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7361 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7364 /* If the context doesn't exist then create a new one */
7365 /* TODO: This should really be part of findGlContext */
7366 if (NULL == newContext->context) {
7368 TRACE("making new buffer\n");
7369 nAttribs = 0;
7370 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7371 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7372 PUSH1(None);
7374 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7376 /** ****************************************
7377 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7378 *they note:
7379 * In future releases, we may provide the calls glXCreateNewContext,
7380 * glXQueryDrawable and glXMakeContextCurrent.
7381 * so until then we have to use glXGetVisualFromFBConfig &co..
7382 ********************************************/
7385 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7386 if (!visinfo) {
7387 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7388 } else {
7389 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7390 XFree(visinfo);
7393 if (NULL == newContext || NULL == newContext->context) {
7394 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7395 } else {
7396 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7397 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7398 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7401 /* Clean up the old context */
7402 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7403 /* Set the current context of the swapchain to the new context */
7404 impSwapChain->drawable = newContext->drawable;
7405 impSwapChain->render_ctx = newContext->context;
7409 /* Disable recording, and apply the stateblock to the new context
7410 * FIXME: This is a bit of a hack, each context should know it's own state,
7411 * the directX current directX state should then be applied to the context */
7412 oldUpdateStateBlock = This->updateStateBlock;
7413 oldRecording= This->isRecordingState;
7414 This->isRecordingState = FALSE;
7415 This->updateStateBlock = This->stateBlock;
7416 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7418 /* clean up the current rendertargets swapchain (if it belonged to one) */
7419 if (currentSwapchain != NULL) {
7420 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7423 /* Were done with the opengl context management, setup the rendertargets */
7425 tmp = This->renderTarget;
7426 This->renderTarget = RenderSurface;
7427 IWineD3DSurface_AddRef(This->renderTarget);
7428 IWineD3DSurface_Release(tmp);
7431 DWORD value;
7433 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7434 /* Check that the container is not a swapchain member */
7436 IWineD3DSwapChain *tmpSwapChain;
7437 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7438 This->renderUpsideDown = TRUE;
7439 }else{
7440 This->renderUpsideDown = FALSE;
7441 IWineD3DSwapChain_Release(tmpSwapChain);
7443 /* Force updating the cull mode */
7444 TRACE("setting render state\n");
7445 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7446 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7448 /* Force updating projection matrix */
7449 This->last_was_rhw = FALSE;
7450 This->proj_valid = FALSE;
7453 /* Restore recording state */
7454 This->isRecordingState = oldRecording;
7455 This->updateStateBlock = oldUpdateStateBlock;
7457 ret = WINED3D_OK;
7459 if (cfgs != NULL) {
7460 XFree(cfgs);
7461 } else {
7462 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7463 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7466 #undef PUSH1
7467 #undef PUSH2
7468 if ( NULL != impSwapChain) {
7469 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7471 LEAVE_GL();
7473 #endif
7474 return ret;
7477 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7478 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7480 /* TODO: the use of Impl is deprecated. */
7481 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7483 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7485 /* some basic validation checks */
7486 if(This->cursorTexture) {
7487 ENTER_GL();
7488 glDeleteTextures(1, &This->cursorTexture);
7489 LEAVE_GL();
7490 This->cursorTexture = 0;
7493 if(pCursorBitmap) {
7494 /* MSDN: Cursor must be A8R8G8B8 */
7495 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7496 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7497 return WINED3DERR_INVALIDCALL;
7500 /* MSDN: Cursor must be smaller than the display mode */
7501 if(pSur->currentDesc.Width > This->ddraw_width ||
7502 pSur->currentDesc.Height > This->ddraw_height) {
7503 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);
7504 return WINED3DERR_INVALIDCALL;
7507 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7508 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7509 * Texture and Blitting code to draw the cursor
7511 pSur->Flags |= SFLAG_FORCELOAD;
7512 IWineD3DSurface_PreLoad(pCursorBitmap);
7513 pSur->Flags &= ~SFLAG_FORCELOAD;
7514 /* Do not store the surface's pointer because the application may release
7515 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7516 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7518 This->cursorTexture = pSur->glDescription.textureName;
7519 This->cursorWidth = pSur->currentDesc.Width;
7520 This->cursorHeight = pSur->currentDesc.Height;
7521 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7524 This->xHotSpot = XHotSpot;
7525 This->yHotSpot = YHotSpot;
7526 return WINED3D_OK;
7529 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7531 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7533 This->xScreenSpace = XScreenSpace;
7534 This->yScreenSpace = YScreenSpace;
7536 return;
7540 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7542 TRACE("(%p) : visible(%d)\n", This, bShow);
7544 This->bCursorVisible = bShow;
7546 return WINED3D_OK;
7549 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7551 TRACE("(%p) : state (%lu)\n", This, This->state);
7552 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7553 switch (This->state) {
7554 case WINED3D_OK:
7555 return WINED3D_OK;
7556 case WINED3DERR_DEVICELOST:
7558 ResourceList *resourceList = This->resources;
7559 while (NULL != resourceList) {
7560 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7561 return WINED3DERR_DEVICENOTRESET;
7562 resourceList = resourceList->next;
7564 return WINED3DERR_DEVICELOST;
7566 case WINED3DERR_DRIVERINTERNALERROR:
7567 return WINED3DERR_DRIVERINTERNALERROR;
7570 /* Unknown state */
7571 return WINED3DERR_DRIVERINTERNALERROR;
7575 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7577 /** FIXME: Resource tracking needs to be done,
7578 * The closes we can do to this is set the priorities of all managed textures low
7579 * and then reset them.
7580 ***********************************************************/
7581 FIXME("(%p) : stub\n", This);
7582 return WINED3D_OK;
7585 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7587 /** FIXME: Resource trascking needs to be done.
7588 * in effect this pulls all non only default
7589 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7590 * and should clear down the context and set it up according to pPresentationParameters
7591 ***********************************************************/
7592 FIXME("(%p) : stub\n", This);
7593 return WINED3D_OK;
7596 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7598 /** FIXME: always true at the moment **/
7599 if(bEnableDialogs == FALSE) {
7600 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7602 return WINED3D_OK;
7606 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7608 TRACE("(%p) : pParameters %p\n", This, pParameters);
7610 *pParameters = This->createParms;
7611 return WINED3D_OK;
7614 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7615 IWineD3DSwapChain *swapchain;
7616 HRESULT hrc = WINED3D_OK;
7618 TRACE("Relaying to swapchain\n");
7620 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7621 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7622 IWineD3DSwapChain_Release(swapchain);
7624 return;
7627 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7628 IWineD3DSwapChain *swapchain;
7629 HRESULT hrc = WINED3D_OK;
7631 TRACE("Relaying to swapchain\n");
7633 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7634 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7635 IWineD3DSwapChain_Release(swapchain);
7637 return;
7641 /** ********************************************************
7642 * Notification functions
7643 ** ********************************************************/
7644 /** This function must be called in the release of a resource when ref == 0,
7645 * the contents of resource must still be correct,
7646 * any handels to other resource held by the caller must be closed
7647 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7648 *****************************************************/
7649 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7651 ResourceList* resourceList;
7653 TRACE("(%p) : resource %p\n", This, resource);
7654 #if 0
7655 EnterCriticalSection(&resourceStoreCriticalSection);
7656 #endif
7657 /* add a new texture to the frot of the linked list */
7658 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7659 resourceList->resource = resource;
7661 /* Get the old head */
7662 resourceList->next = This->resources;
7664 This->resources = resourceList;
7665 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7667 #if 0
7668 LeaveCriticalSection(&resourceStoreCriticalSection);
7669 #endif
7670 return;
7673 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7675 ResourceList* resourceList = NULL;
7676 ResourceList* previousResourceList = NULL;
7678 TRACE("(%p) : resource %p\n", This, resource);
7680 #if 0
7681 EnterCriticalSection(&resourceStoreCriticalSection);
7682 #endif
7683 resourceList = This->resources;
7685 while (resourceList != NULL) {
7686 if(resourceList->resource == resource) break;
7687 previousResourceList = resourceList;
7688 resourceList = resourceList->next;
7691 if (resourceList == NULL) {
7692 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7693 #if 0
7694 LeaveCriticalSection(&resourceStoreCriticalSection);
7695 #endif
7696 return;
7697 } else {
7698 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7700 /* make sure we don't leave a hole in the list */
7701 if (previousResourceList != NULL) {
7702 previousResourceList->next = resourceList->next;
7703 } else {
7704 This->resources = resourceList->next;
7707 #if 0
7708 LeaveCriticalSection(&resourceStoreCriticalSection);
7709 #endif
7710 return;
7714 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7716 int counter;
7718 TRACE("(%p) : resource %p\n", This, resource);
7719 switch(IWineD3DResource_GetType(resource)){
7720 case WINED3DRTYPE_SURFACE:
7721 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7722 break;
7723 case WINED3DRTYPE_TEXTURE:
7724 case WINED3DRTYPE_CUBETEXTURE:
7725 case WINED3DRTYPE_VOLUMETEXTURE:
7726 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7727 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7728 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7729 This->stateBlock->textures[counter] = NULL;
7731 if (This->updateStateBlock != This->stateBlock ){
7732 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7733 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7734 This->updateStateBlock->textures[counter] = NULL;
7738 break;
7739 case WINED3DRTYPE_VOLUME:
7740 /* TODO: nothing really? */
7741 break;
7742 case WINED3DRTYPE_VERTEXBUFFER:
7743 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7745 int streamNumber;
7746 TRACE("Cleaning up stream pointers\n");
7748 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7749 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7750 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7752 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7753 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7754 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7755 This->updateStateBlock->streamSource[streamNumber] = 0;
7756 /* Set changed flag? */
7759 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) */
7760 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7761 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7762 This->stateBlock->streamSource[streamNumber] = 0;
7765 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7766 else { /* This shouldn't happen */
7767 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7769 #endif
7773 break;
7774 case WINED3DRTYPE_INDEXBUFFER:
7775 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7776 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7777 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7778 This->updateStateBlock->pIndexData = NULL;
7781 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7782 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7783 This->stateBlock->pIndexData = NULL;
7787 break;
7788 default:
7789 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7790 break;
7794 /* Remove the resoruce from the resourceStore */
7795 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7797 TRACE("Resource released\n");
7801 /**********************************************************
7802 * IWineD3DDevice VTbl follows
7803 **********************************************************/
7805 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7807 /*** IUnknown methods ***/
7808 IWineD3DDeviceImpl_QueryInterface,
7809 IWineD3DDeviceImpl_AddRef,
7810 IWineD3DDeviceImpl_Release,
7811 /*** IWineD3DDevice methods ***/
7812 IWineD3DDeviceImpl_GetParent,
7813 /*** Creation methods**/
7814 IWineD3DDeviceImpl_CreateVertexBuffer,
7815 IWineD3DDeviceImpl_CreateIndexBuffer,
7816 IWineD3DDeviceImpl_CreateStateBlock,
7817 IWineD3DDeviceImpl_CreateSurface,
7818 IWineD3DDeviceImpl_CreateTexture,
7819 IWineD3DDeviceImpl_CreateVolumeTexture,
7820 IWineD3DDeviceImpl_CreateVolume,
7821 IWineD3DDeviceImpl_CreateCubeTexture,
7822 IWineD3DDeviceImpl_CreateQuery,
7823 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7824 IWineD3DDeviceImpl_CreateVertexDeclaration,
7825 IWineD3DDeviceImpl_CreateVertexShader,
7826 IWineD3DDeviceImpl_CreatePixelShader,
7827 IWineD3DDeviceImpl_CreatePalette,
7828 /*** Odd functions **/
7829 IWineD3DDeviceImpl_Init3D,
7830 IWineD3DDeviceImpl_Uninit3D,
7831 IWineD3DDeviceImpl_EnumDisplayModes,
7832 IWineD3DDeviceImpl_EvictManagedResources,
7833 IWineD3DDeviceImpl_GetAvailableTextureMem,
7834 IWineD3DDeviceImpl_GetBackBuffer,
7835 IWineD3DDeviceImpl_GetCreationParameters,
7836 IWineD3DDeviceImpl_GetDeviceCaps,
7837 IWineD3DDeviceImpl_GetDirect3D,
7838 IWineD3DDeviceImpl_GetDisplayMode,
7839 IWineD3DDeviceImpl_SetDisplayMode,
7840 IWineD3DDeviceImpl_GetHWND,
7841 IWineD3DDeviceImpl_SetHWND,
7842 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7843 IWineD3DDeviceImpl_GetRasterStatus,
7844 IWineD3DDeviceImpl_GetSwapChain,
7845 IWineD3DDeviceImpl_Reset,
7846 IWineD3DDeviceImpl_SetDialogBoxMode,
7847 IWineD3DDeviceImpl_SetCursorProperties,
7848 IWineD3DDeviceImpl_SetCursorPosition,
7849 IWineD3DDeviceImpl_ShowCursor,
7850 IWineD3DDeviceImpl_TestCooperativeLevel,
7851 /*** Getters and setters **/
7852 IWineD3DDeviceImpl_SetClipPlane,
7853 IWineD3DDeviceImpl_GetClipPlane,
7854 IWineD3DDeviceImpl_SetClipStatus,
7855 IWineD3DDeviceImpl_GetClipStatus,
7856 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7857 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7858 IWineD3DDeviceImpl_SetDepthStencilSurface,
7859 IWineD3DDeviceImpl_GetDepthStencilSurface,
7860 IWineD3DDeviceImpl_SetFVF,
7861 IWineD3DDeviceImpl_GetFVF,
7862 IWineD3DDeviceImpl_SetGammaRamp,
7863 IWineD3DDeviceImpl_GetGammaRamp,
7864 IWineD3DDeviceImpl_SetIndices,
7865 IWineD3DDeviceImpl_GetIndices,
7866 IWineD3DDeviceImpl_SetLight,
7867 IWineD3DDeviceImpl_GetLight,
7868 IWineD3DDeviceImpl_SetLightEnable,
7869 IWineD3DDeviceImpl_GetLightEnable,
7870 IWineD3DDeviceImpl_SetMaterial,
7871 IWineD3DDeviceImpl_GetMaterial,
7872 IWineD3DDeviceImpl_SetNPatchMode,
7873 IWineD3DDeviceImpl_GetNPatchMode,
7874 IWineD3DDeviceImpl_SetPaletteEntries,
7875 IWineD3DDeviceImpl_GetPaletteEntries,
7876 IWineD3DDeviceImpl_SetPixelShader,
7877 IWineD3DDeviceImpl_GetPixelShader,
7878 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7879 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7880 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7881 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7882 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7883 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7884 IWineD3DDeviceImpl_SetRenderState,
7885 IWineD3DDeviceImpl_GetRenderState,
7886 IWineD3DDeviceImpl_SetRenderTarget,
7887 IWineD3DDeviceImpl_GetRenderTarget,
7888 IWineD3DDeviceImpl_SetFrontBackBuffers,
7889 IWineD3DDeviceImpl_SetSamplerState,
7890 IWineD3DDeviceImpl_GetSamplerState,
7891 IWineD3DDeviceImpl_SetScissorRect,
7892 IWineD3DDeviceImpl_GetScissorRect,
7893 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7894 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7895 IWineD3DDeviceImpl_SetStreamSource,
7896 IWineD3DDeviceImpl_GetStreamSource,
7897 IWineD3DDeviceImpl_SetStreamSourceFreq,
7898 IWineD3DDeviceImpl_GetStreamSourceFreq,
7899 IWineD3DDeviceImpl_SetTexture,
7900 IWineD3DDeviceImpl_GetTexture,
7901 IWineD3DDeviceImpl_SetTextureStageState,
7902 IWineD3DDeviceImpl_GetTextureStageState,
7903 IWineD3DDeviceImpl_SetTransform,
7904 IWineD3DDeviceImpl_GetTransform,
7905 IWineD3DDeviceImpl_SetVertexDeclaration,
7906 IWineD3DDeviceImpl_GetVertexDeclaration,
7907 IWineD3DDeviceImpl_SetVertexShader,
7908 IWineD3DDeviceImpl_GetVertexShader,
7909 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7910 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7911 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7912 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7913 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7914 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7915 IWineD3DDeviceImpl_SetViewport,
7916 IWineD3DDeviceImpl_GetViewport,
7917 IWineD3DDeviceImpl_MultiplyTransform,
7918 IWineD3DDeviceImpl_ValidateDevice,
7919 IWineD3DDeviceImpl_ProcessVertices,
7920 /*** State block ***/
7921 IWineD3DDeviceImpl_BeginStateBlock,
7922 IWineD3DDeviceImpl_EndStateBlock,
7923 /*** Scene management ***/
7924 IWineD3DDeviceImpl_BeginScene,
7925 IWineD3DDeviceImpl_EndScene,
7926 IWineD3DDeviceImpl_Present,
7927 IWineD3DDeviceImpl_Clear,
7928 /*** Drawing ***/
7929 IWineD3DDeviceImpl_DrawPrimitive,
7930 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7931 IWineD3DDeviceImpl_DrawPrimitiveUP,
7932 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7933 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7934 IWineD3DDeviceImpl_DrawRectPatch,
7935 IWineD3DDeviceImpl_DrawTriPatch,
7936 IWineD3DDeviceImpl_DeletePatch,
7937 IWineD3DDeviceImpl_ColorFill,
7938 IWineD3DDeviceImpl_UpdateTexture,
7939 IWineD3DDeviceImpl_UpdateSurface,
7940 IWineD3DDeviceImpl_CopyRects,
7941 IWineD3DDeviceImpl_StretchRect,
7942 IWineD3DDeviceImpl_GetRenderTargetData,
7943 IWineD3DDeviceImpl_GetFrontBufferData,
7944 /*** Internal use IWineD3DDevice methods ***/
7945 IWineD3DDeviceImpl_SetupTextureStates,
7946 /*** object tracking ***/
7947 IWineD3DDeviceImpl_ResourceReleased
7951 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7952 WINED3DRS_ALPHABLENDENABLE ,
7953 WINED3DRS_ALPHAFUNC ,
7954 WINED3DRS_ALPHAREF ,
7955 WINED3DRS_ALPHATESTENABLE ,
7956 WINED3DRS_BLENDOP ,
7957 WINED3DRS_COLORWRITEENABLE ,
7958 WINED3DRS_DESTBLEND ,
7959 WINED3DRS_DITHERENABLE ,
7960 WINED3DRS_FILLMODE ,
7961 WINED3DRS_FOGDENSITY ,
7962 WINED3DRS_FOGEND ,
7963 WINED3DRS_FOGSTART ,
7964 WINED3DRS_LASTPIXEL ,
7965 WINED3DRS_SHADEMODE ,
7966 WINED3DRS_SRCBLEND ,
7967 WINED3DRS_STENCILENABLE ,
7968 WINED3DRS_STENCILFAIL ,
7969 WINED3DRS_STENCILFUNC ,
7970 WINED3DRS_STENCILMASK ,
7971 WINED3DRS_STENCILPASS ,
7972 WINED3DRS_STENCILREF ,
7973 WINED3DRS_STENCILWRITEMASK ,
7974 WINED3DRS_STENCILZFAIL ,
7975 WINED3DRS_TEXTUREFACTOR ,
7976 WINED3DRS_WRAP0 ,
7977 WINED3DRS_WRAP1 ,
7978 WINED3DRS_WRAP2 ,
7979 WINED3DRS_WRAP3 ,
7980 WINED3DRS_WRAP4 ,
7981 WINED3DRS_WRAP5 ,
7982 WINED3DRS_WRAP6 ,
7983 WINED3DRS_WRAP7 ,
7984 WINED3DRS_ZENABLE ,
7985 WINED3DRS_ZFUNC ,
7986 WINED3DRS_ZWRITEENABLE
7989 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7990 WINED3DTSS_ADDRESSW ,
7991 WINED3DTSS_ALPHAARG0 ,
7992 WINED3DTSS_ALPHAARG1 ,
7993 WINED3DTSS_ALPHAARG2 ,
7994 WINED3DTSS_ALPHAOP ,
7995 WINED3DTSS_BUMPENVLOFFSET ,
7996 WINED3DTSS_BUMPENVLSCALE ,
7997 WINED3DTSS_BUMPENVMAT00 ,
7998 WINED3DTSS_BUMPENVMAT01 ,
7999 WINED3DTSS_BUMPENVMAT10 ,
8000 WINED3DTSS_BUMPENVMAT11 ,
8001 WINED3DTSS_COLORARG0 ,
8002 WINED3DTSS_COLORARG1 ,
8003 WINED3DTSS_COLORARG2 ,
8004 WINED3DTSS_COLOROP ,
8005 WINED3DTSS_RESULTARG ,
8006 WINED3DTSS_TEXCOORDINDEX ,
8007 WINED3DTSS_TEXTURETRANSFORMFLAGS
8010 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8011 WINED3DSAMP_ADDRESSU ,
8012 WINED3DSAMP_ADDRESSV ,
8013 WINED3DSAMP_ADDRESSW ,
8014 WINED3DSAMP_BORDERCOLOR ,
8015 WINED3DSAMP_MAGFILTER ,
8016 WINED3DSAMP_MINFILTER ,
8017 WINED3DSAMP_MIPFILTER ,
8018 WINED3DSAMP_MIPMAPLODBIAS ,
8019 WINED3DSAMP_MAXMIPLEVEL ,
8020 WINED3DSAMP_MAXANISOTROPY ,
8021 WINED3DSAMP_SRGBTEXTURE ,
8022 WINED3DSAMP_ELEMENTINDEX
8025 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8026 WINED3DRS_AMBIENT ,
8027 WINED3DRS_AMBIENTMATERIALSOURCE ,
8028 WINED3DRS_CLIPPING ,
8029 WINED3DRS_CLIPPLANEENABLE ,
8030 WINED3DRS_COLORVERTEX ,
8031 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8032 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8033 WINED3DRS_FOGDENSITY ,
8034 WINED3DRS_FOGEND ,
8035 WINED3DRS_FOGSTART ,
8036 WINED3DRS_FOGTABLEMODE ,
8037 WINED3DRS_FOGVERTEXMODE ,
8038 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8039 WINED3DRS_LIGHTING ,
8040 WINED3DRS_LOCALVIEWER ,
8041 WINED3DRS_MULTISAMPLEANTIALIAS ,
8042 WINED3DRS_MULTISAMPLEMASK ,
8043 WINED3DRS_NORMALIZENORMALS ,
8044 WINED3DRS_PATCHEDGESTYLE ,
8045 WINED3DRS_POINTSCALE_A ,
8046 WINED3DRS_POINTSCALE_B ,
8047 WINED3DRS_POINTSCALE_C ,
8048 WINED3DRS_POINTSCALEENABLE ,
8049 WINED3DRS_POINTSIZE ,
8050 WINED3DRS_POINTSIZE_MAX ,
8051 WINED3DRS_POINTSIZE_MIN ,
8052 WINED3DRS_POINTSPRITEENABLE ,
8053 WINED3DRS_RANGEFOGENABLE ,
8054 WINED3DRS_SPECULARMATERIALSOURCE ,
8055 WINED3DRS_TWEENFACTOR ,
8056 WINED3DRS_VERTEXBLEND
8059 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8060 WINED3DTSS_TEXCOORDINDEX ,
8061 WINED3DTSS_TEXTURETRANSFORMFLAGS
8064 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8065 WINED3DSAMP_DMAPOFFSET