Assorted spelling, case and grammar fixes.
[wine/multimedia.git] / dlls / wined3d / device.c
blob755cb19cc8d8919030f5212de9118d402f6ccc30
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include <stdio.h>
28 #ifdef HAVE_FLOAT_H
29 # include <float.h>
30 #endif
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 D3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 inline static Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* Memory tracking and object counting */
74 static unsigned int emulated_textureram = 64*1024*1024;
76 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
77 /* enable pbuffer support for offscreen textures */
78 BOOL pbuffer_support = FALSE;
79 /* allocate one pbuffer per surface */
80 BOOL pbuffer_per_surface = FALSE;
82 /* static function declarations */
83 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
85 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
87 /* helper macros */
88 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
90 #define D3DCREATEOBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->wineD3DDevice = This; \
95 object->parent = parent; \
96 object->ref = 1; \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
117 *pp##type = NULL; \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
126 *pp##type = NULL; \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * Utility functions follow
148 **********************************************************/
149 /* Convert the D3DLIGHT properties into equivalent gl lights */
150 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
152 float quad_att;
153 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
157 glMatrixMode(GL_MODELVIEW);
158 glPushMatrix();
159 glLoadMatrixf((float *)&This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
161 /* Diffuse: */
162 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
163 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
164 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
165 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
166 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
167 checkGLcall("glLightfv");
169 /* Specular */
170 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
171 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
172 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
173 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
174 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
175 checkGLcall("glLightfv");
177 /* Ambient */
178 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
179 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
180 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
181 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
182 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
183 checkGLcall("glLightfv");
185 /* Attenuation - Are these right? guessing... */
186 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
187 checkGLcall("glLightf");
188 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
189 checkGLcall("glLightf");
191 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
192 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
193 } else {
194 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
197 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
198 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
199 checkGLcall("glLightf");
201 switch (lightInfo->OriginalParms.Type) {
202 case D3DLIGHT_POINT:
203 /* Position */
204 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
205 checkGLcall("glLightfv");
206 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
207 checkGLcall("glLightf");
208 /* FIXME: Range */
209 break;
211 case D3DLIGHT_SPOT:
212 /* Position */
213 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
214 checkGLcall("glLightfv");
215 /* Direction */
216 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
217 checkGLcall("glLightfv");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
219 checkGLcall("glLightf");
220 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
221 checkGLcall("glLightf");
222 /* FIXME: Range */
223 break;
225 case D3DLIGHT_DIRECTIONAL:
226 /* Direction */
227 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
228 checkGLcall("glLightfv");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
230 checkGLcall("glLightf");
231 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
232 checkGLcall("glLightf");
233 break;
235 default:
236 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
239 /* Restore the modelview matrix */
240 glPopMatrix();
243 /**********************************************************
244 * GLSL helper functions follow
245 **********************************************************/
247 /** Attach a GLSL pixel or vertex shader object to the shader program */
248 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
252 if (This->stateBlock->shaderPrgId != 0 && shaderObj != 0) {
253 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->shaderPrgId);
254 GL_EXTCALL(glAttachObjectARB(This->stateBlock->shaderPrgId, shaderObj));
255 checkGLcall("glAttachObjectARB");
259 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
260 * It sets the programId on the current StateBlock (because it should be called
261 * inside of the DrawPrimitive() part of the render loop).
263 * If a program for the given combination does not exist, create one, and store
264 * the program in the list. If it creates a program, it will link the given
265 * objects, too.
267 * We keep the shader programs around on a list because linking
268 * shader objects together is an expensive operation. It's much
269 * faster to loop through a list of pre-compiled & linked programs
270 * each time that the application sets a new pixel or vertex shader
271 * than it is to re-link them together at that time.
273 * The list will be deleted in IWineD3DDevice::Release().
275 void set_glsl_shader_program(IWineD3DDevice *iface) {
277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
278 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
279 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
280 struct glsl_shader_prog_link *curLink = NULL;
281 struct glsl_shader_prog_link *newLink = NULL;
282 struct list *ptr = NULL;
283 GLhandleARB programId = 0;
285 if (NULL == vshader && NULL == pshader) {
286 /* No pixel or vertex shader specified */
287 This->stateBlock->shaderPrgId = 0;
288 return;
291 ptr = list_head( &This->glsl_shader_progs );
292 while (ptr) {
293 /* At least one program exists - see if it matches our ps/vs combination */
294 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
295 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
296 /* Existing Program found, use it */
297 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
298 curLink->programId);
299 This->stateBlock->shaderPrgId = curLink->programId;
300 return;
302 /* This isn't the entry we need - try the next one */
303 ptr = list_next( &This->glsl_shader_progs, ptr );
306 /* If we get to this point, then no matching program exists, so we create one */
307 programId = GL_EXTCALL(glCreateProgramObjectARB());
308 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
309 This->stateBlock->shaderPrgId = programId;
311 if (NULL != vshader) {
312 int i;
313 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
314 char tmp_name[10];
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
322 * GLSL shaders.
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
334 if (NULL != pshader) {
335 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
338 /* Link the program */
339 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
340 GL_EXTCALL(glLinkProgramARB(programId));
341 print_glsl_info_log(&GLINFO_LOCATION, programId);
343 /* Now, we add a list item to associate this program with the vertex and
344 * pixel shaders that it is attached to.
346 * These list items will be deleted when the device is released.
348 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
349 newLink->programId = programId;
350 newLink->pixelShader = pshader;
351 newLink->vertexShader = vshader;
352 list_add_head( &This->glsl_shader_progs, &newLink->entry);
354 return;
357 /** Detach the GLSL pixel or vertex shader object from the shader program */
358 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
362 if (shaderObj != 0 && programId != 0) {
363 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
364 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
365 checkGLcall("glDetachObjectARB");
369 /** Delete a GLSL shader program */
370 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
374 if (obj != 0) {
375 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
376 GL_EXTCALL(glDeleteObjectARB(obj));
377 checkGLcall("glDeleteObjectARB");
381 /** Delete the list of linked programs this shader is associated with.
382 * Also at this point, check to see if there are any objects left attached
383 * to each GLSL program. If not, delete the GLSL program object.
384 * This will be run when a device is released. */
385 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
387 struct list *ptr = NULL;
388 struct glsl_shader_prog_link *curLink = NULL;
389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
391 int numAttached = 0;
392 int i;
393 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
394 (one pixel shader and one vertex shader at most) */
396 ptr = list_head( &This->glsl_shader_progs );
397 while (ptr) {
398 /* First, get the current item,
399 * save the link to the next pointer,
400 * detach and delete shader objects,
401 * then de-allocate the list item's memory */
402 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
403 ptr = list_next( &This->glsl_shader_progs, ptr );
405 /* See if this object is still attached to the program - it may have been detached already */
406 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
407 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
408 for (i = 0; i < numAttached; i++) {
409 detach_glsl_shader(iface, objList[i], curLink->programId);
412 delete_glsl_shader_program(iface, curLink->programId);
414 /* Free the memory for this list item */
415 HeapFree(GetProcessHeap(), 0, curLink);
420 /* Apply the current values to the specified texture stage */
421 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD Flags) {
422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
423 float col[4];
425 union {
426 float f;
427 DWORD d;
428 } tmpvalue;
430 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
431 clamping, MIPLOD, etc. This will work for up to 16 samplers.
434 if (Sampler >= GL_LIMITS(samplers)) {
435 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(samplers));
436 return;
438 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
439 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
440 ENTER_GL();
441 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + Sampler));
442 checkGLcall("glActiveTextureARB");
443 LEAVE_GL();
444 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
445 } else if (Sampler > 0) {
446 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
447 return;
450 /* TODO: change this to a lookup table
451 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
452 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
453 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
454 especially when there are a number of groups of states. */
456 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
458 /* 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 */
459 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
460 /* these are the only two supported states that need to be applied */
461 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
462 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
463 #if 0 /* not supported at the moment */
464 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
465 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
466 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
467 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
468 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
469 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
470 APPLY_STATE(WINED3DTSS_RESULTARG);
471 APPLY_STATE(WINED3DTSS_CONSTANT);
472 #endif
473 /* a quick sanity check in case someone forgot to update this function */
474 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
475 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
477 #undef APPLY_STATE
479 /* apply any sampler states that always need applying */
480 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
481 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
482 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
483 GL_TEXTURE_LOD_BIAS_EXT,
484 tmpvalue.f);
485 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
488 /* Note the D3DRS value applies to all textures, but GL has one
489 * per texture, so apply it now ready to be used!
491 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
492 /* Set the default alpha blend color */
493 if (GL_SUPPORT(ARB_IMAGING)) {
494 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
495 checkGLcall("glBlendColor");
496 } else {
497 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
500 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
501 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
502 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
504 /* TODO: NV_POINT_SPRITE */
505 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
506 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE] != FALSE) {
507 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
508 glDisable(GL_POINT_SMOOTH);
510 /* Centre the texture on the vertex */
511 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
512 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
514 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
515 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
516 checkGLcall("glTexEnvf(...)");
517 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
518 glEnable( GL_POINT_SPRITE_ARB );
519 checkGLcall("glEnable(...)");
520 } else {
521 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
522 glDisable( GL_POINT_SPRITE_ARB );
523 checkGLcall("glEnable(...)");
527 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
530 /**********************************************************
531 * IUnknown parts follows
532 **********************************************************/
534 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
538 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
539 if (IsEqualGUID(riid, &IID_IUnknown)
540 || IsEqualGUID(riid, &IID_IWineD3DBase)
541 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
542 IUnknown_AddRef(iface);
543 *ppobj = This;
544 return S_OK;
546 *ppobj = NULL;
547 return E_NOINTERFACE;
550 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
552 ULONG refCount = InterlockedIncrement(&This->ref);
554 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
555 return refCount;
558 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
560 ULONG refCount = InterlockedDecrement(&This->ref);
562 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
564 if (!refCount) {
565 /* TODO: Clean up all the surfaces and textures! */
566 /* NOTE: You must release the parent if the object was created via a callback
567 ** ***************************/
569 /* Delete any GLSL shader programs that may exist */
570 if (wined3d_settings.shader_mode == SHADER_GLSL) {
571 delete_glsl_shader_list(iface);
574 /* Release the update stateblock */
575 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
576 if(This->updateStateBlock != This->stateBlock)
577 FIXME("(%p) Something's still holding the Update stateblock\n",This);
579 This->updateStateBlock = NULL;
580 { /* because were not doing proper internal refcounts releasing the primary state block
581 causes recursion with the extra checks in ResourceReleased, to avoid this we have
582 to set this->stateBlock = NULL; first */
583 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
584 This->stateBlock = NULL;
586 /* Release the stateblock */
587 if(IWineD3DStateBlock_Release(stateBlock) > 0){
588 FIXME("(%p) Something's still holding the Update stateblock\n",This);
592 if (This->resources != NULL ) {
593 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
594 dumpResources(This->resources);
598 IWineD3D_Release(This->wineD3D);
599 This->wineD3D = NULL;
600 HeapFree(GetProcessHeap(), 0, This);
601 TRACE("Freed device %p\n", This);
602 This = NULL;
604 return refCount;
607 /**********************************************************
608 * IWineD3DDevice implementation follows
609 **********************************************************/
610 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
612 *pParent = This->parent;
613 IUnknown_AddRef(This->parent);
614 return WINED3D_OK;
617 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
618 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
619 GLenum error, glUsage;
620 DWORD vboUsage = object->resource.usage;
621 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p\n", object);
623 ENTER_GL();
624 /* Make sure that the gl error is cleared. Do not use checkGLcall
625 * here because checkGLcall just prints a fixme and continues. However,
626 * if an error during VBO creation occurs we can fall back to non-vbo operation
627 * with full functionality(but performance loss)
629 while(glGetError() != GL_NO_ERROR);
631 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
632 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
633 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
634 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
635 * to check if the rhw and color values are in the correct format.
638 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
639 error = glGetError();
640 if(object->vbo == 0 || error != GL_NO_ERROR) {
641 WARN("Failed to create a VBO with error %d\n", error);
642 goto error;
645 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
646 error = glGetError();
647 if(error != GL_NO_ERROR) {
648 WARN("Failed to bind the VBO, error %d\n", error);
649 goto error;
652 /* Transformed vertices are horribly inflexible. If the app specifies an
653 * vertex buffer with transformed vertices in default pool without DYNAMIC
654 * usage assume DYNAMIC usage and print a warning. The app will have to update
655 * the vertices regularily for them to be useful
657 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
658 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
659 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
660 vboUsage |= WINED3DUSAGE_DYNAMIC;
663 /* Don't use static, because dx apps tend to update the buffer
664 * quite often even if they specify 0 usage
666 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
667 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
668 TRACE("Gl usage = GL_STREAM_DRAW\n");
669 glUsage = GL_STREAM_DRAW_ARB;
670 break;
671 case D3DUSAGE_WRITEONLY:
672 TRACE("Gl usage = GL_STATIC_DRAW\n");
673 glUsage = GL_DYNAMIC_DRAW_ARB;
674 break;
675 case D3DUSAGE_DYNAMIC:
676 TRACE("Gl usage = GL_STREAM_COPY\n");
677 glUsage = GL_STREAM_COPY_ARB;
678 break;
679 default:
680 TRACE("Gl usage = GL_STATIC_COPY\n");
681 glUsage = GL_DYNAMIC_COPY_ARB;
682 break;
685 /* Reserve memory for the buffer. The amount of data won't change
686 * so we are safe with calling glBufferData once with a NULL ptr and
687 * calling glBufferSubData on updates
689 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
690 error = glGetError();
691 if(error != GL_NO_ERROR) {
692 WARN("glBufferDataARB failed with error %d\n", error);
693 goto error;
696 LEAVE_GL();
698 return;
699 error:
700 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
701 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
702 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
703 object->vbo = 0;
704 LEAVE_GL();
705 return;
708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
709 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
710 IUnknown *parent) {
711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
712 IWineD3DVertexBufferImpl *object;
713 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
714 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
715 BOOL conv;
716 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
718 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
719 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
721 if(Size == 0) return WINED3DERR_INVALIDCALL;
723 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
724 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
726 object->fvf = FVF;
728 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
729 * drawStridedFast (half-life 2).
731 * Basically converting the vertices in the buffer is quite expensive, and observations
732 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
733 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
735 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
736 * the range of vertices beeing locked, so each lock will require the whole buffer to be transformed.
737 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
738 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
739 * dx7 apps.
740 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
741 * more. In this call we can convert dx7 buffers too.
743 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
744 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
745 (dxVersion > 7 || !conv) ) {
746 CreateVBO(object);
748 /* DX7 buffers can be locked directly into the VBO(no conversion, see above */
749 if(dxVersion == 7 && object->vbo) {
750 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
751 object->resource.allocatedMemory = NULL;
755 return WINED3D_OK;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
759 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
760 HANDLE *sharedHandle, IUnknown *parent) {
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 IWineD3DIndexBufferImpl *object;
763 TRACE("(%p) Creating index buffer\n", This);
765 /* Allocate the storage for the device */
766 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
768 /*TODO: use VBO's */
769 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
770 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
773 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
774 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
775 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
777 return WINED3D_OK;
780 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
783 IWineD3DStateBlockImpl *object;
784 int i, j;
786 D3DCREATEOBJECTINSTANCE(object, StateBlock)
787 object->blockType = Type;
789 /* Special case - Used during initialization to produce a placeholder stateblock
790 so other functions called can update a state block */
791 if (Type == WINED3DSBT_INIT) {
792 /* Don't bother increasing the reference count otherwise a device will never
793 be freed due to circular dependencies */
794 return WINED3D_OK;
797 /* Otherwise, might as well set the whole state block to the appropriate values */
798 if ( This->stateBlock != NULL) {
799 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
800 } else {
801 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 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
815 } else if (Type == WINED3DSBT_PIXELSTATE) {
817 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
818 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
820 object->changed.pixelShader = TRUE;
822 /* Pixel Shader Constants */
823 for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
824 object->changed.pixelShaderConstantsF[i] = TRUE;
825 object->changed.pixelShaderConstantsB[i] = TRUE;
826 object->changed.pixelShaderConstantsI[i] = TRUE;
828 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
829 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
831 for (j = 0; j < GL_LIMITS(textures); j++) {
832 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
833 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
836 for (j = 0 ; j < 16; j++) {
837 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
839 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
843 } else if (Type == WINED3DSBT_VERTEXSTATE) {
845 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
846 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
848 object->changed.vertexShader = TRUE;
850 /* Vertex Shader Constants */
851 for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
852 object->changed.vertexShaderConstantsF[i] = TRUE;
853 object->changed.vertexShaderConstantsB[i] = TRUE;
854 object->changed.vertexShaderConstantsI[i] = TRUE;
856 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
857 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
859 for (j = 0; j < GL_LIMITS(textures); j++) {
860 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
861 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
864 for (j = 0 ; j < 16; j++){
865 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
866 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
870 /* Duplicate light chain */
872 PLIGHTINFOEL *src = NULL;
873 PLIGHTINFOEL *dst = NULL;
874 PLIGHTINFOEL *newEl = NULL;
875 src = This->stateBlock->lights;
876 object->lights = NULL;
879 while (src) {
880 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
881 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
882 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
883 newEl->prev = dst;
884 newEl->changed = TRUE;
885 newEl->enabledChanged = TRUE;
886 if (dst == NULL) {
887 object->lights = newEl;
888 } else {
889 dst->next = newEl;
891 dst = newEl;
892 src = src->next;
897 } else {
898 FIXME("Unrecognized state block type %d\n", Type);
901 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
902 return WINED3D_OK;
906 /* ************************************
907 MSDN:
908 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
910 Discard
911 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
913 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.
915 ******************************** */
917 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) {
918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
919 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
920 unsigned int pow2Width, pow2Height;
921 unsigned int Size = 1;
922 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
923 TRACE("(%p) Create surface\n",This);
925 /** FIXME: Check ranges on the inputs are valid
926 * MSDN
927 * MultisampleQuality
928 * [in] Quality level. The valid range is between zero and one less than the level
929 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
930 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
931 * values of paired render targets, depth stencil surfaces, and the MultiSample type
932 * must all match.
933 *******************************/
937 * TODO: Discard MSDN
938 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
940 * If this flag is set, the contents of the depth stencil buffer will be
941 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
942 * with a different depth surface.
944 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
945 ***************************/
947 if(MultisampleQuality < 0) {
948 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
949 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
952 if(MultisampleQuality > 0) {
953 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
954 MultisampleQuality=0;
957 /** FIXME: Check that the format is supported
958 * by the device.
959 *******************************/
961 /* Non-power2 support */
963 /* Find the nearest pow2 match */
964 pow2Width = pow2Height = 1;
965 while (pow2Width < Width) pow2Width <<= 1;
966 while (pow2Height < Height) pow2Height <<= 1;
968 if (pow2Width > Width || pow2Height > Height) {
969 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
970 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
971 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
972 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
973 This, Width, Height);
974 return WINED3DERR_NOTAVAILABLE;
978 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
979 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
980 * space!
981 *********************************/
982 if (WINED3DFMT_UNKNOWN == Format) {
983 Size = 0;
984 } else if (Format == WINED3DFMT_DXT1) {
985 /* DXT1 is half byte per pixel */
986 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
988 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
989 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
990 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
991 } else {
992 Size = (pow2Width * tableEntry->bpp) * pow2Height;
995 /** Create and initialise the surface resource **/
996 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
997 /* "Standalone" surface */
998 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1000 object->currentDesc.Width = Width;
1001 object->currentDesc.Height = Height;
1002 object->currentDesc.MultiSampleType = MultiSample;
1003 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1005 /* Setup some glformat defaults */
1006 object->glDescription.glFormat = tableEntry->glFormat;
1007 object->glDescription.glFormatInternal = tableEntry->glInternal;
1008 object->glDescription.glType = tableEntry->glType;
1010 object->glDescription.textureName = 0;
1011 object->glDescription.level = Level;
1012 object->glDescription.target = GL_TEXTURE_2D;
1014 /* Internal data */
1015 object->pow2Width = pow2Width;
1016 object->pow2Height = pow2Height;
1018 /* Flags */
1019 object->Flags = 0; /* We start without flags set */
1020 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1021 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1022 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1023 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1026 if (WINED3DFMT_UNKNOWN != Format) {
1027 object->bytesPerPixel = tableEntry->bpp;
1028 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1029 } else {
1030 object->bytesPerPixel = 0;
1031 object->pow2Size = 0;
1034 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1036 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1038 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1039 * this function is too deap to need to care about things like this.
1040 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1041 * ****************************************/
1042 switch(Pool) {
1043 case WINED3DPOOL_SCRATCH:
1044 if(Lockable == FALSE)
1045 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1046 which are mutually exclusive, setting lockable to true\n");
1047 Lockable = TRUE;
1048 break;
1049 case WINED3DPOOL_SYSTEMMEM:
1050 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1051 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1052 case WINED3DPOOL_MANAGED:
1053 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1054 Usage of DYNAMIC which are mutually exclusive, not doing \
1055 anything just telling you.\n");
1056 break;
1057 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1058 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1059 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1060 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1061 break;
1062 default:
1063 FIXME("(%p) Unknown pool %d\n", This, Pool);
1064 break;
1067 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1068 FIXME("Trying to create a render target that isn't in the default pool\n");
1071 /* mark the texture as dirty so that it get's loaded first time around*/
1072 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1073 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1074 This, Width, Height, Format, debug_d3dformat(Format),
1075 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1077 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1078 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1079 This->ddraw_primary = (IWineD3DSurface *) object;
1081 /* Look at the implementation and set the correct Vtable */
1082 switch(Impl) {
1083 case SURFACE_OPENGL:
1084 /* Nothing to do, it's set already */
1085 break;
1087 case SURFACE_GDI:
1088 object->lpVtbl = &IWineGDISurface_Vtbl;
1089 break;
1091 default:
1092 /* To be sure to catch this */
1093 ERR("Unknown requested surface implementation %d!\n", Impl);
1094 IWineD3DSurface_Release((IWineD3DSurface *) object);
1095 return WINED3DERR_INVALIDCALL;
1098 /* Call the private setup routine */
1099 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1103 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1104 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1106 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1110 unsigned int i;
1111 UINT tmpW;
1112 UINT tmpH;
1113 HRESULT hr;
1114 unsigned int pow2Width = Width;
1115 unsigned int pow2Height = Height;
1118 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1120 /* TODO: It should only be possible to create textures for formats
1121 that are reported as supported */
1122 if (WINED3DFMT_UNKNOWN >= Format) {
1123 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1124 return WINED3DERR_INVALIDCALL;
1127 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1128 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1129 object->width = Width;
1130 object->height = Height;
1132 /** Non-power2 support **/
1133 /* Find the nearest pow2 match */
1134 pow2Width = pow2Height = 1;
1135 while (pow2Width < Width) pow2Width <<= 1;
1136 while (pow2Height < Height) pow2Height <<= 1;
1138 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1139 /* Precalculated scaling for 'faked' non power of two texture coords */
1140 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1141 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1142 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1144 /* Calculate levels for mip mapping */
1145 if (Levels == 0) {
1146 TRACE("calculating levels %d\n", object->baseTexture.levels);
1147 object->baseTexture.levels++;
1148 tmpW = Width;
1149 tmpH = Height;
1150 while (tmpW > 1 || tmpH > 1) {
1151 tmpW = max(1, tmpW >> 1);
1152 tmpH = max(1, tmpH >> 1);
1153 object->baseTexture.levels++;
1155 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1158 /* Generate all the surfaces */
1159 tmpW = Width;
1160 tmpH = Height;
1161 for (i = 0; i < object->baseTexture.levels; i++)
1163 /* use the callback to create the texture surface */
1164 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1165 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1166 FIXME("Failed to create surface %p\n", object);
1167 /* clean up */
1168 object->surfaces[i] = NULL;
1169 IWineD3DTexture_Release((IWineD3DTexture *)object);
1171 *ppTexture = NULL;
1172 return hr;
1175 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1176 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1177 /* calculate the next mipmap level */
1178 tmpW = max(1, tmpW >> 1);
1179 tmpH = max(1, tmpH >> 1);
1182 TRACE("(%p) : Created texture %p\n", This, object);
1183 return WINED3D_OK;
1186 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1187 UINT Width, UINT Height, UINT Depth,
1188 UINT Levels, DWORD Usage,
1189 WINED3DFORMAT Format, WINED3DPOOL Pool,
1190 IWineD3DVolumeTexture **ppVolumeTexture,
1191 HANDLE *pSharedHandle, IUnknown *parent,
1192 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1195 IWineD3DVolumeTextureImpl *object;
1196 unsigned int i;
1197 UINT tmpW;
1198 UINT tmpH;
1199 UINT tmpD;
1201 /* TODO: It should only be possible to create textures for formats
1202 that are reported as supported */
1203 if (WINED3DFMT_UNKNOWN >= Format) {
1204 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1205 return WINED3DERR_INVALIDCALL;
1208 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1209 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1211 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1212 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1214 object->width = Width;
1215 object->height = Height;
1216 object->depth = Depth;
1218 /* Calculate levels for mip mapping */
1219 if (Levels == 0) {
1220 object->baseTexture.levels++;
1221 tmpW = Width;
1222 tmpH = Height;
1223 tmpD = Depth;
1224 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1225 tmpW = max(1, tmpW >> 1);
1226 tmpH = max(1, tmpH >> 1);
1227 tmpD = max(1, tmpD >> 1);
1228 object->baseTexture.levels++;
1230 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1233 /* Generate all the surfaces */
1234 tmpW = Width;
1235 tmpH = Height;
1236 tmpD = Depth;
1238 for (i = 0; i < object->baseTexture.levels; i++)
1240 /* Create the volume */
1241 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1242 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1244 /* Set it's container to this object */
1245 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1247 /* calcualte the next mipmap level */
1248 tmpW = max(1, tmpW >> 1);
1249 tmpH = max(1, tmpH >> 1);
1250 tmpD = max(1, tmpD >> 1);
1253 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1254 TRACE("(%p) : Created volume texture %p\n", This, object);
1255 return WINED3D_OK;
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1259 UINT Width, UINT Height, UINT Depth,
1260 DWORD Usage,
1261 WINED3DFORMAT Format, WINED3DPOOL Pool,
1262 IWineD3DVolume** ppVolume,
1263 HANDLE* pSharedHandle, IUnknown *parent) {
1265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1266 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1267 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1269 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1271 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1272 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1274 object->currentDesc.Width = Width;
1275 object->currentDesc.Height = Height;
1276 object->currentDesc.Depth = Depth;
1277 object->bytesPerPixel = formatDesc->bpp;
1279 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1280 object->lockable = TRUE;
1281 object->locked = FALSE;
1282 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1283 object->dirty = TRUE;
1285 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1288 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1289 UINT Levels, DWORD Usage,
1290 WINED3DFORMAT Format, WINED3DPOOL Pool,
1291 IWineD3DCubeTexture **ppCubeTexture,
1292 HANDLE *pSharedHandle, IUnknown *parent,
1293 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1297 unsigned int i, j;
1298 UINT tmpW;
1299 HRESULT hr;
1300 unsigned int pow2EdgeLength = EdgeLength;
1302 /* TODO: It should only be possible to create textures for formats
1303 that are reported as supported */
1304 if (WINED3DFMT_UNKNOWN >= Format) {
1305 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1306 return WINED3DERR_INVALIDCALL;
1309 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1310 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1312 TRACE("(%p) Create Cube Texture\n", This);
1314 /** Non-power2 support **/
1316 /* Find the nearest pow2 match */
1317 pow2EdgeLength = 1;
1318 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1320 object->edgeLength = EdgeLength;
1321 /* TODO: support for native non-power 2 */
1322 /* Precalculated scaling for 'faked' non power of two texture coords */
1323 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1325 /* Calculate levels for mip mapping */
1326 if (Levels == 0) {
1327 object->baseTexture.levels++;
1328 tmpW = EdgeLength;
1329 while (tmpW > 1) {
1330 tmpW = max(1, tmpW >> 1);
1331 object->baseTexture.levels++;
1333 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1336 /* Generate all the surfaces */
1337 tmpW = EdgeLength;
1338 for (i = 0; i < object->baseTexture.levels; i++) {
1340 /* Create the 6 faces */
1341 for (j = 0; j < 6; j++) {
1343 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1344 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1346 if(hr!= WINED3D_OK) {
1347 /* clean up */
1348 int k;
1349 int l;
1350 for (l = 0; l < j; l++) {
1351 IWineD3DSurface_Release(object->surfaces[j][i]);
1353 for (k = 0; k < i; k++) {
1354 for (l = 0; l < 6; l++) {
1355 IWineD3DSurface_Release(object->surfaces[l][j]);
1359 FIXME("(%p) Failed to create surface\n",object);
1360 HeapFree(GetProcessHeap(),0,object);
1361 *ppCubeTexture = NULL;
1362 return hr;
1364 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1365 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1367 tmpW = max(1, tmpW >> 1);
1370 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1371 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1372 return WINED3D_OK;
1375 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1377 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1379 if (NULL == ppQuery) {
1380 /* Just a check to see if we support this type of query */
1381 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1382 switch(Type) {
1383 case WINED3DQUERYTYPE_OCCLUSION:
1384 TRACE("(%p) occlusion query\n", This);
1385 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1386 hr = WINED3D_OK;
1387 else
1388 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1389 break;
1390 case WINED3DQUERYTYPE_VCACHE:
1391 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1392 case WINED3DQUERYTYPE_VERTEXSTATS:
1393 case WINED3DQUERYTYPE_EVENT:
1394 case WINED3DQUERYTYPE_TIMESTAMP:
1395 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1396 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1397 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1398 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1399 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1400 case WINED3DQUERYTYPE_PIXELTIMINGS:
1401 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1402 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1403 default:
1404 FIXME("(%p) Unhandled query type %d\n", This, Type);
1406 return hr;
1409 D3DCREATEOBJECTINSTANCE(object, Query)
1410 object->type = Type;
1411 /* allocated the 'extended' data based on the type of query requested */
1412 switch(Type){
1413 case D3DQUERYTYPE_OCCLUSION:
1414 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1415 TRACE("(%p) Allocating data for an occlusion query\n", This);
1416 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1417 break;
1419 case D3DQUERYTYPE_VCACHE:
1420 case D3DQUERYTYPE_RESOURCEMANAGER:
1421 case D3DQUERYTYPE_VERTEXSTATS:
1422 case D3DQUERYTYPE_EVENT:
1423 case D3DQUERYTYPE_TIMESTAMP:
1424 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1425 case D3DQUERYTYPE_TIMESTAMPFREQ:
1426 case D3DQUERYTYPE_PIPELINETIMINGS:
1427 case D3DQUERYTYPE_INTERFACETIMINGS:
1428 case D3DQUERYTYPE_VERTEXTIMINGS:
1429 case D3DQUERYTYPE_PIXELTIMINGS:
1430 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1431 case D3DQUERYTYPE_CACHEUTILIZATION:
1432 default:
1433 object->extendedData = 0;
1434 FIXME("(%p) Unhandled query type %d\n",This , Type);
1436 TRACE("(%p) : Created Query %p\n", This, object);
1437 return WINED3D_OK;
1440 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1441 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1442 IUnknown* parent,
1443 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1444 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1447 HDC hDc;
1448 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1449 int num;
1450 XVisualInfo template;
1451 GLXContext oldContext;
1452 Drawable oldDrawable;
1453 HRESULT hr = WINED3D_OK;
1455 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1457 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1458 * does a device hold a reference to a swap chain giving them a lifetime of the device
1459 * or does the swap chain notify the device of its destruction.
1460 *******************************/
1462 /* Check the params */
1463 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1464 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1465 return WINED3DERR_INVALIDCALL;
1466 } else if (*pPresentationParameters->BackBufferCount > 1) {
1467 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");
1470 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1472 /*********************
1473 * Lookup the window Handle and the relating X window handle
1474 ********************/
1476 /* Setup hwnd we are using, plus which display this equates to */
1477 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1478 if (!object->win_handle) {
1479 object->win_handle = This->createParms.hFocusWindow;
1482 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1483 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1484 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1485 return WINED3DERR_NOTAVAILABLE;
1487 hDc = GetDC(object->win_handle);
1488 object->display = get_display(hDc);
1489 ReleaseDC(object->win_handle, hDc);
1490 TRACE("Using a display of %p %p\n", object->display, hDc);
1492 if (NULL == object->display || NULL == hDc) {
1493 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1494 return WINED3DERR_NOTAVAILABLE;
1497 if (object->win == 0) {
1498 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1499 return WINED3DERR_NOTAVAILABLE;
1502 * Create an opengl context for the display visual
1503 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1504 * use different properties after that point in time. FIXME: How to handle when requested format
1505 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1506 * it chooses is identical to the one already being used!
1507 **********************************/
1509 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1510 ENTER_GL();
1512 /* Create a new context for this swapchain */
1513 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1514 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1515 (or the best possible if none is requested) */
1516 TRACE("Found x visual ID : %ld\n", template.visualid);
1518 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1519 if (NULL == object->visInfo) {
1520 ERR("cannot really get XVisual\n");
1521 LEAVE_GL();
1522 return WINED3DERR_NOTAVAILABLE;
1523 } else {
1524 int n, value;
1525 /* Write out some debug info about the visual/s */
1526 TRACE("Using x visual ID : %ld\n", template.visualid);
1527 TRACE(" visual info: %p\n", object->visInfo);
1528 TRACE(" num items : %d\n", num);
1529 for (n = 0;n < num; n++) {
1530 TRACE("=====item=====: %d\n", n + 1);
1531 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1532 TRACE(" screen : %d\n", object->visInfo[n].screen);
1533 TRACE(" depth : %u\n", object->visInfo[n].depth);
1534 TRACE(" class : %d\n", object->visInfo[n].class);
1535 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1536 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1537 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1538 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1539 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1540 /* log some extra glx info */
1541 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1542 TRACE(" gl_aux_buffers : %d\n", value);
1543 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1544 TRACE(" gl_buffer_size : %d\n", value);
1545 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1546 TRACE(" gl_red_size : %d\n", value);
1547 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1548 TRACE(" gl_green_size : %d\n", value);
1549 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1550 TRACE(" gl_blue_size : %d\n", value);
1551 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1552 TRACE(" gl_alpha_size : %d\n", value);
1553 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1554 TRACE(" gl_depth_size : %d\n", value);
1555 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1556 TRACE(" gl_stencil_size : %d\n", value);
1558 /* Now choose a simila visual ID*/
1560 #ifdef USE_CONTEXT_MANAGER
1562 /** TODO: use a context mamager **/
1563 #endif
1566 IWineD3DSwapChain *implSwapChain;
1567 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1568 /* The first time around we create the context that is shared with all other swapchains and render targets */
1569 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1570 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1571 } else {
1573 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1574 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1575 /* and create a new context with the implicit swapchains context as the shared context */
1576 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1577 IWineD3DSwapChain_Release(implSwapChain);
1581 /* Cleanup */
1582 XFree(object->visInfo);
1583 object->visInfo = NULL;
1585 if (NULL == object->glCtx) {
1586 ERR("cannot create glxContext\n");
1587 LEAVE_GL();
1588 return WINED3DERR_NOTAVAILABLE;
1591 LEAVE_GL();
1592 if (object->glCtx == NULL) {
1593 ERR("Error in context creation !\n");
1594 return WINED3DERR_INVALIDCALL;
1595 } else {
1596 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1597 object->win_handle, object->glCtx, object->win, object->visInfo);
1600 /*********************
1601 * Windowed / Fullscreen
1602 *******************/
1605 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1606 * so we should really check to see if there is a fullscreen swapchain already
1607 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1608 **************************************/
1610 if (!*(pPresentationParameters->Windowed)) {
1612 DEVMODEW devmode;
1613 HDC hdc;
1614 int bpp = 0;
1616 /* Get info on the current display setup */
1617 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1618 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1619 DeleteDC(hdc);
1621 /* Change the display settings */
1622 memset(&devmode, 0, sizeof(DEVMODEW));
1623 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1624 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1625 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1626 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1627 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1628 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1630 /* Make popup window */
1631 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1632 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1633 *(pPresentationParameters->BackBufferWidth),
1634 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1636 /* For GetDisplayMode */
1637 This->ddraw_width = devmode.dmPelsWidth;
1638 This->ddraw_height = devmode.dmPelsHeight;
1639 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1643 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1644 * then the corresponding dimension of the client area of the hDeviceWindow
1645 * (or the focus window, if hDeviceWindow is NULL) is taken.
1646 **********************/
1648 if (*(pPresentationParameters->Windowed) &&
1649 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1650 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1652 RECT Rect;
1653 GetClientRect(object->win_handle, &Rect);
1655 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1656 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1657 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1659 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1660 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1661 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1665 /*********************
1666 * finish off parameter initialization
1667 *******************/
1669 /* Put the correct figures in the presentation parameters */
1670 TRACE("Coppying accross presentaion paraneters\n");
1671 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1672 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1673 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1674 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1675 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1676 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1677 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1678 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1679 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1680 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1681 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1682 object->presentParms.Flags = *(pPresentationParameters->Flags);
1683 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1684 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1687 /*********************
1688 * Create the back, front and stencil buffers
1689 *******************/
1691 TRACE("calling rendertarget CB\n");
1692 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1693 object->presentParms.BackBufferWidth,
1694 object->presentParms.BackBufferHeight,
1695 object->presentParms.BackBufferFormat,
1696 object->presentParms.MultiSampleType,
1697 object->presentParms.MultiSampleQuality,
1698 TRUE /* Lockable */,
1699 &object->frontBuffer,
1700 NULL /* pShared (always null)*/);
1701 if (object->frontBuffer != NULL)
1702 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1704 if(object->presentParms.BackBufferCount > 0) {
1705 int i;
1707 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1708 if(!object->backBuffer) {
1709 ERR("Out of memory\n");
1711 if (object->frontBuffer) {
1712 IUnknown *bufferParent;
1713 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1714 IUnknown_Release(bufferParent); /* once for the get parent */
1715 if (IUnknown_Release(bufferParent) > 0) {
1716 FIXME("(%p) Something's still holding the front buffer\n",This);
1719 HeapFree(GetProcessHeap(), 0, object);
1720 return E_OUTOFMEMORY;
1723 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1724 TRACE("calling rendertarget CB\n");
1725 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1726 object->presentParms.BackBufferWidth,
1727 object->presentParms.BackBufferHeight,
1728 object->presentParms.BackBufferFormat,
1729 object->presentParms.MultiSampleType,
1730 object->presentParms.MultiSampleQuality,
1731 TRUE /* Lockable */,
1732 &object->backBuffer[i],
1733 NULL /* pShared (always null)*/);
1734 if(hr == WINED3D_OK && object->backBuffer[i]) {
1735 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1736 } else {
1737 break;
1740 } else {
1741 object->backBuffer = NULL;
1744 if (object->backBuffer != NULL) {
1745 ENTER_GL();
1746 glDrawBuffer(GL_BACK);
1747 checkGLcall("glDrawBuffer(GL_BACK)");
1748 LEAVE_GL();
1749 } else {
1750 /* Single buffering - draw to front buffer */
1751 ENTER_GL();
1752 glDrawBuffer(GL_FRONT);
1753 checkGLcall("glDrawBuffer(GL_FRONT)");
1754 LEAVE_GL();
1757 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1758 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1759 TRACE("Creating depth stencil buffer\n");
1760 if (This->depthStencilBuffer == NULL ) {
1761 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1762 object->presentParms.BackBufferWidth,
1763 object->presentParms.BackBufferHeight,
1764 object->presentParms.AutoDepthStencilFormat,
1765 object->presentParms.MultiSampleType,
1766 object->presentParms.MultiSampleQuality,
1767 FALSE /* FIXME: Discard */,
1768 &This->depthStencilBuffer,
1769 NULL /* pShared (always null)*/ );
1770 if (This->depthStencilBuffer != NULL)
1771 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1774 /** TODO: A check on width, height and multisample types
1775 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1776 ****************************/
1777 object->wantsDepthStencilBuffer = TRUE;
1778 } else {
1779 object->wantsDepthStencilBuffer = FALSE;
1782 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1785 /*********************
1786 * init the default renderTarget management
1787 *******************/
1788 object->drawable = object->win;
1789 object->render_ctx = object->glCtx;
1791 if (hr == WINED3D_OK) {
1792 /*********************
1793 * Setup some defaults and clear down the buffers
1794 *******************/
1795 ENTER_GL();
1796 /** save current context and drawable **/
1797 oldContext = glXGetCurrentContext();
1798 oldDrawable = glXGetCurrentDrawable();
1800 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1801 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1802 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1804 checkGLcall("glXMakeCurrent");
1806 TRACE("Setting up the screen\n");
1807 /* Clear the screen */
1808 glClearColor(1.0, 0.0, 0.0, 0.0);
1809 checkGLcall("glClearColor");
1810 glClearIndex(0);
1811 glClearDepth(1);
1812 glClearStencil(0xffff);
1814 checkGLcall("glClear");
1816 glColor3f(1.0, 1.0, 1.0);
1817 checkGLcall("glColor3f");
1819 glEnable(GL_LIGHTING);
1820 checkGLcall("glEnable");
1822 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1823 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1825 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1826 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1828 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1829 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1831 /* switch back to the original context (if there was one)*/
1832 if (This->swapchains) {
1833 /** TODO: restore the context and drawable **/
1834 glXMakeCurrent(object->display, oldDrawable, oldContext);
1837 LEAVE_GL();
1839 TRACE("Set swapchain to %p\n", object);
1840 } else { /* something went wrong so clean up */
1841 IUnknown* bufferParent;
1842 if (object->frontBuffer) {
1844 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1845 IUnknown_Release(bufferParent); /* once for the get parent */
1846 if (IUnknown_Release(bufferParent) > 0) {
1847 FIXME("(%p) Something's still holding the front buffer\n",This);
1850 if (object->backBuffer) {
1851 int i;
1852 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1853 if(object->backBuffer[i]) {
1854 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1855 IUnknown_Release(bufferParent); /* once for the get parent */
1856 if (IUnknown_Release(bufferParent) > 0) {
1857 FIXME("(%p) Something's still holding the back buffer\n",This);
1861 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1862 object->backBuffer = NULL;
1864 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1865 /* Clean up the context */
1866 /* check that we are the current context first (we shouldn't be though!) */
1867 if (object->glCtx != 0) {
1868 if(glXGetCurrentContext() == object->glCtx) {
1869 glXMakeCurrent(object->display, None, NULL);
1871 glXDestroyContext(object->display, object->glCtx);
1873 HeapFree(GetProcessHeap(), 0, object);
1877 return hr;
1880 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1881 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1883 TRACE("(%p)\n", This);
1885 return This->NumberOfSwapChains;
1888 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1890 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1892 if(iSwapChain < This->NumberOfSwapChains) {
1893 *pSwapChain = This->swapchains[iSwapChain];
1894 IWineD3DSwapChain_AddRef(*pSwapChain);
1895 TRACE("(%p) returning %p\n", This, *pSwapChain);
1896 return WINED3D_OK;
1897 } else {
1898 TRACE("Swapchain out of range\n");
1899 *pSwapChain = NULL;
1900 return WINED3DERR_INVALIDCALL;
1904 /*****
1905 * Vertex Declaration
1906 *****/
1907 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1909 IWineD3DVertexDeclarationImpl *object = NULL;
1910 HRESULT hr = WINED3D_OK;
1911 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1912 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1913 object->allFVF = 0;
1915 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1917 return hr;
1920 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1921 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1923 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1924 HRESULT hr = WINED3D_OK;
1925 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1926 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1928 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1930 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1931 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1932 if (pDeclaration != NULL) {
1933 IWineD3DVertexDeclaration *vertexDeclaration;
1934 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1935 if (WINED3D_OK == hr) {
1936 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1937 object->vertexDeclaration = vertexDeclaration;
1938 } else {
1939 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1940 IWineD3DVertexShader_Release(*ppVertexShader);
1941 return WINED3DERR_INVALIDCALL;
1945 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1947 if (WINED3D_OK != hr) {
1948 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1949 IWineD3DVertexShader_Release(*ppVertexShader);
1950 return WINED3DERR_INVALIDCALL;
1953 #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. */
1954 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1955 /* Foo */
1956 } else {
1957 /* Bar */
1960 #endif
1962 return WINED3D_OK;
1965 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1967 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1968 HRESULT hr = WINED3D_OK;
1970 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1971 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1972 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1973 if (WINED3D_OK == hr) {
1974 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1975 } else {
1976 WARN("(%p) : Failed to create pixel shader\n", This);
1979 return hr;
1982 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1984 IWineD3DPaletteImpl *object;
1985 HRESULT hr;
1986 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1988 /* Create the new object */
1989 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1990 if(!object) {
1991 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1992 return E_OUTOFMEMORY;
1995 object->lpVtbl = &IWineD3DPalette_Vtbl;
1996 object->ref = 1;
1997 object->Flags = Flags;
1998 object->parent = Parent;
1999 object->wineD3DDevice = This;
2000 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2002 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2004 if(!object->hpal) {
2005 HeapFree( GetProcessHeap(), 0, object);
2006 return E_OUTOFMEMORY;
2009 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2010 if(FAILED(hr)) {
2011 IWineD3DPalette_Release((IWineD3DPalette *) object);
2012 return hr;
2015 *Palette = (IWineD3DPalette *) object;
2017 return WINED3D_OK;
2020 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2022 IWineD3DSwapChainImpl *swapchain;
2024 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2025 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2027 /* TODO: Test if OpenGL is compiled in and loaded */
2029 /* Setup the implicit swapchain */
2030 TRACE("Creating implicit swapchain\n");
2031 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2032 WARN("Failed to create implicit swapchain\n");
2033 return WINED3DERR_INVALIDCALL;
2036 This->NumberOfSwapChains = 1;
2037 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2038 if(!This->swapchains) {
2039 ERR("Out of memory!\n");
2040 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2041 return E_OUTOFMEMORY;
2043 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2045 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2046 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2047 This->renderTarget = swapchain->backBuffer[0];
2049 else {
2050 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2051 This->renderTarget = swapchain->frontBuffer;
2053 IWineD3DSurface_AddRef(This->renderTarget);
2054 /* Depth Stencil support */
2055 This->stencilBufferTarget = This->depthStencilBuffer;
2056 if (NULL != This->stencilBufferTarget) {
2057 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2060 /* Set up some starting GL setup */
2061 ENTER_GL();
2063 * Initialize openGL extension related variables
2064 * with Default values
2067 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( &((IWineD3DImpl *) This->wineD3D)->gl_info, swapchain->display);
2068 /* Setup all the devices defaults */
2069 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2070 #if 0
2071 IWineD3DImpl_CheckGraphicsMemory();
2072 #endif
2073 LEAVE_GL();
2075 /* Initialize our list of GLSL programs */
2076 list_init(&This->glsl_shader_progs);
2078 { /* Set a default viewport */
2079 D3DVIEWPORT9 vp;
2080 vp.X = 0;
2081 vp.Y = 0;
2082 vp.Width = *(pPresentationParameters->BackBufferWidth);
2083 vp.Height = *(pPresentationParameters->BackBufferHeight);
2084 vp.MinZ = 0.0f;
2085 vp.MaxZ = 1.0f;
2086 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2089 /* Initialize the current view state */
2090 This->modelview_valid = 1;
2091 This->proj_valid = 0;
2092 This->view_ident = 1;
2093 This->last_was_rhw = 0;
2094 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2095 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2097 /* Clear the screen */
2098 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2100 This->d3d_initialized = TRUE;
2101 return WINED3D_OK;
2104 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2106 int texstage;
2107 IUnknown* stencilBufferParent;
2108 IUnknown* swapChainParent;
2109 uint i;
2110 TRACE("(%p)\n", This);
2112 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2114 for(texstage = 0; texstage < GL_LIMITS(textures); texstage++) {
2115 IWineD3DDevice_SetTexture(iface, texstage, NULL);
2118 /* Release the buffers (with sanity checks)*/
2119 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2120 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2121 if(This->depthStencilBuffer != This->stencilBufferTarget)
2122 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2124 This->stencilBufferTarget = NULL;
2126 TRACE("Releasing the render target at %p\n", This->renderTarget);
2127 if(IWineD3DSurface_Release(This->renderTarget) >0){
2128 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2130 TRACE("Setting rendertarget to NULL\n");
2131 This->renderTarget = NULL;
2133 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2134 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2135 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2136 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2138 This->depthStencilBuffer = NULL;
2140 for(i=0; i < This->NumberOfSwapChains; i++) {
2141 TRACE("Releasing the implicit swapchain %d\n", i);
2142 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2143 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2144 IUnknown_Release(swapChainParent); /* once for the get parent */
2145 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2146 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2150 HeapFree(GetProcessHeap(), 0, This->swapchains);
2151 This->swapchains = NULL;
2152 This->NumberOfSwapChains = 0;
2154 This->d3d_initialized = FALSE;
2155 return WINED3D_OK;
2158 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2161 DEVMODEW DevModeW;
2162 int i;
2163 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2165 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2167 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2168 /* Ignore some modes if a description was passed */
2169 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2170 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2171 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2173 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2175 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2176 return D3D_OK;
2179 return D3D_OK;
2182 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2183 DEVMODEW devmode;
2184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2185 LONG ret;
2186 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2188 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2190 /* Resize the screen even without a window:
2191 * The app could have unset it with SetCooperativeLevel, but not called
2192 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2193 * but we don't have any hwnd
2196 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2197 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2198 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2199 devmode.dmPelsWidth = pMode->Width;
2200 devmode.dmPelsHeight = pMode->Height;
2202 devmode.dmDisplayFrequency = pMode->RefreshRate;
2203 if (pMode->RefreshRate != 0) {
2204 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2207 /* Only change the mode if necessary */
2208 if( (This->ddraw_width == pMode->Width) &&
2209 (This->ddraw_height == pMode->Height) &&
2210 (This->ddraw_format == pMode->Format) &&
2211 (pMode->RefreshRate == 0) ) {
2212 return D3D_OK;
2215 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2216 if (ret != DISP_CHANGE_SUCCESSFUL) {
2217 if(devmode.dmDisplayFrequency != 0) {
2218 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2219 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2220 devmode.dmDisplayFrequency = 0;
2221 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2223 if(ret != DISP_CHANGE_SUCCESSFUL) {
2224 return DDERR_INVALIDMODE;
2228 /* Store the new values */
2229 This->ddraw_width = pMode->Width;
2230 This->ddraw_height = pMode->Height;
2231 This->ddraw_format = pMode->Format;
2233 /* Only do this with a window of course */
2234 if(This->ddraw_window)
2235 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2237 return WINED3D_OK;
2240 static HRESULT WINAPI IWineD3DDeviceImpl_EnumZBufferFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2242 HRESULT ret;
2243 int i = 0;
2244 WINED3DFORMAT FormatList[] = {
2245 WINED3DFMT_D16,
2246 WINED3DFMT_D32,
2247 WINED3DFMT_D24X4S4,
2248 WINED3DFMT_D24S8,
2249 WINED3DFMT_D24X8,
2250 WINED3DFMT_D15S1,
2251 WINED3DFMT_UNKNOWN /* Terminate the list */
2254 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2256 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2257 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2258 ret = Callback((IUnknown *) This, FormatList[i], Context);
2259 if(ret != DDENUMRET_OK) {
2260 TRACE("Enumeration cancelled by Application\n");
2261 return WINED3D_OK;
2263 i++;
2266 TRACE("End of Enumeration\n");
2268 return WINED3D_OK;
2271 static HRESULT WINAPI IWineD3DDeviceImpl_EnumTextureFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2273 HRESULT ret;
2274 int i = 0;
2276 /* From old ddraw:
2277 * WINED3DFMT_A1R5G5B5 needs to be the first 16 bit format, as some dumb apps depend on this
2279 * Do not enumerate RGBA pixel formats: "some games choose the first 16 bit texture format
2280 * with alpha they find enumerated, others the last one. And both want to have the ARGB one."
2281 * But WineD3D doesn't support RGBA formats anyway...
2284 WINED3DFORMAT FormatList[] = {
2285 /* 32 bit */
2286 WINED3DFMT_A8R8G8B8,
2287 WINED3DFMT_X8R8G8B8,
2288 /* 24 bit */
2289 WINED3DFMT_R8G8B8,
2290 /* 16 Bit */
2291 WINED3DFMT_A1R5G5B5,
2292 WINED3DFMT_A4R4G4B4,
2293 WINED3DFMT_R5G6B5,
2294 WINED3DFMT_X1R5G5B5,
2295 /* 8 Bit */
2296 WINED3DFMT_R3G3B2,
2297 WINED3DFMT_P8,
2298 /* FOURCC codes */
2299 WINED3DFMT_DXT1,
2300 WINED3DFMT_DXT3,
2301 WINED3DFMT_DXT5,
2302 /* Terminate the list */
2303 WINED3DFMT_UNKNOWN
2306 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2308 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2309 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2310 ret = Callback((IUnknown *) This, FormatList[i], Context);
2311 if(ret != DDENUMRET_OK) {
2312 TRACE("Enumeration cancelled by Application\n");
2313 return WINED3D_OK;
2315 i++;
2318 TRACE("End of Enumeration\n");
2320 return WINED3D_OK;
2323 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2325 *ppD3D= This->wineD3D;
2326 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2327 IWineD3D_AddRef(*ppD3D);
2328 return WINED3D_OK;
2331 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2332 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2333 * Into the video ram as possible and seeing how many fit
2334 * you can also get the correct initial value from via X and ATI's driver
2335 *******************/
2336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2337 static BOOL showfixmes = TRUE;
2338 if (showfixmes) {
2339 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2340 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2341 showfixmes = FALSE;
2343 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2344 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2345 /* videomemory is simulated videomemory + AGP memory left */
2346 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2351 /*****
2352 * Get / Set FVF
2353 *****/
2354 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2356 HRESULT hr = WINED3D_OK;
2358 /* Update the current state block */
2359 This->updateStateBlock->fvf = fvf;
2360 This->updateStateBlock->changed.fvf = TRUE;
2361 This->updateStateBlock->set.fvf = TRUE;
2363 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2365 if (0 != fvf) {
2366 /* clear down the vertex declaration
2367 NOTE: Axis and Allies doesn't work properly otherwise
2368 (may be a stateblock problem though!)
2370 hr = IWineD3DDevice_SetVertexDeclaration(iface, NULL);
2373 return hr;
2377 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2380 *pfvf = This->stateBlock->fvf;
2381 return WINED3D_OK;
2384 /*****
2385 * Get / Set Stream Source
2386 *****/
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2389 IWineD3DVertexBuffer *oldSrc;
2391 /**TODO: instance and index data, see
2392 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2394 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2395 **************/
2397 /* D3d9 only, but shouldn't hurt d3d8 */
2398 UINT streamFlags;
2400 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2401 if (streamFlags) {
2402 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2403 FIXME("stream index data not supported\n");
2405 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2406 FIXME("stream instance data not supported\n");
2410 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2412 if (StreamNumber >= MAX_STREAMS) {
2413 WARN("Stream out of range %d\n", StreamNumber);
2414 return WINED3DERR_INVALIDCALL;
2417 oldSrc = This->stateBlock->streamSource[StreamNumber];
2418 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2420 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2421 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2422 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2423 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2424 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2425 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2427 /* Handle recording of state blocks */
2428 if (This->isRecordingState) {
2429 TRACE("Recording... not performing anything\n");
2430 return WINED3D_OK;
2433 /* Not recording... */
2434 /* Need to do a getParent and pass the reffs up */
2435 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2436 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2437 so for now, just count internally */
2438 if (pStreamData != NULL) {
2439 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2440 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2441 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2443 vbImpl->stream = StreamNumber;
2444 vbImpl->Flags |= VBFLAG_STREAM;
2445 IWineD3DVertexBuffer_AddRef(pStreamData);
2447 if (oldSrc != NULL) {
2448 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2449 IWineD3DVertexBuffer_Release(oldSrc);
2452 return WINED3D_OK;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 UINT streamFlags;
2459 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2460 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2463 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2464 if (streamFlags) {
2465 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2466 FIXME("stream index data not supported\n");
2468 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2469 FIXME("stream instance data not supported\n");
2473 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2475 if (StreamNumber >= MAX_STREAMS) {
2476 WARN("Stream out of range %d\n", StreamNumber);
2477 return WINED3DERR_INVALIDCALL;
2479 *pStream = This->stateBlock->streamSource[StreamNumber];
2480 *pStride = This->stateBlock->streamStride[StreamNumber];
2481 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2483 if (*pStream == NULL) {
2484 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2485 return WINED3DERR_INVALIDCALL;
2488 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2489 return WINED3D_OK;
2492 /*Should be quite easy, just an extension of vertexdata
2493 ref...
2494 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2496 The divider is a bit odd though
2498 VertexOffset = StartVertex / Divider * StreamStride +
2499 VertexIndex / Divider * StreamStride + StreamOffset
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2506 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2508 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2509 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2510 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2512 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2513 FIXME("Stream indexing not fully supported\n");
2516 return WINED3D_OK;
2519 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2523 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2525 TRACE("(%p) : returning %d\n", This, *Divider);
2527 return WINED3D_OK;
2530 /*****
2531 * Get / Set & Multiply Transform
2532 *****/
2533 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 /* Most of this routine, comments included copied from ddraw tree initially: */
2537 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2539 /* Handle recording of state blocks */
2540 if (This->isRecordingState) {
2541 TRACE("Recording... not performing anything\n");
2542 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2543 This->updateStateBlock->set.transform[d3dts] = TRUE;
2544 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2545 return WINED3D_OK;
2549 * If the new matrix is the same as the current one,
2550 * we cut off any further processing. this seems to be a reasonable
2551 * optimization because as was noticed, some apps (warcraft3 for example)
2552 * tend towards setting the same matrix repeatedly for some reason.
2554 * From here on we assume that the new matrix is different, wherever it matters.
2556 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2557 TRACE("The app is setting the same matrix over again\n");
2558 return WINED3D_OK;
2559 } else {
2560 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2564 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2565 where ViewMat = Camera space, WorldMat = world space.
2567 In OpenGL, camera and world space is combined into GL_MODELVIEW
2568 matrix. The Projection matrix stay projection matrix.
2571 /* Capture the times we can just ignore the change for now */
2572 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2573 This->modelview_valid = FALSE;
2574 return WINED3D_OK;
2576 } else if (d3dts == D3DTS_PROJECTION) {
2577 This->proj_valid = FALSE;
2578 return WINED3D_OK;
2580 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2581 /* Indexed Vertex Blending Matrices 256 -> 511 */
2582 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2583 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2584 return WINED3D_OK;
2587 /* Now we really are going to have to change a matrix */
2588 ENTER_GL();
2590 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2591 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2592 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2593 unsigned int k;
2595 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2596 * NOTE: We have to reset the positions even if the light/plane is not currently
2597 * enabled, since the call to enable it will not reset the position.
2598 * NOTE2: Apparently texture transforms do NOT need reapplying
2601 PLIGHTINFOEL *lightChain = NULL;
2602 This->modelview_valid = FALSE;
2603 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2605 glMatrixMode(GL_MODELVIEW);
2606 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2607 glPushMatrix();
2608 glLoadMatrixf((float *)lpmatrix);
2609 checkGLcall("glLoadMatrixf(...)");
2611 /* Reset lights */
2612 lightChain = This->stateBlock->lights;
2613 while (lightChain && lightChain->glIndex != -1) {
2614 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2615 checkGLcall("glLightfv posn");
2616 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2617 checkGLcall("glLightfv dirn");
2618 lightChain = lightChain->next;
2621 /* Reset Clipping Planes if clipping is enabled */
2622 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2623 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2624 checkGLcall("glClipPlane");
2626 glPopMatrix();
2628 } else { /* What was requested!?? */
2629 WARN("invalid matrix specified: %i\n", d3dts);
2632 /* Release lock, all done */
2633 LEAVE_GL();
2634 return WINED3D_OK;
2637 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 TRACE("(%p) : for Transform State %d\n", This, State);
2640 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2641 return WINED3D_OK;
2644 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2645 D3DMATRIX *mat = NULL;
2646 D3DMATRIX temp;
2648 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2649 * below means it will be recorded in a state block change, but it
2650 * works regardless where it is recorded.
2651 * If this is found to be wrong, change to StateBlock.
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2654 TRACE("(%p) : For state %u\n", This, State);
2656 if (State < HIGHEST_TRANSFORMSTATE)
2658 mat = &This->updateStateBlock->transforms[State];
2659 } else {
2660 FIXME("Unhandled transform state!!\n");
2663 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2665 /* Apply change via set transform - will reapply to eg. lights this way */
2666 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2669 /*****
2670 * Get / Set Light
2671 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2672 *****/
2673 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2674 you can reference any indexes you want as long as that number max are enabled at any
2675 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2676 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2677 but when recording, just build a chain pretty much of commands to be replayed. */
2679 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2680 float rho;
2681 PLIGHTINFOEL *object, *temp;
2683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2684 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2686 /* If recording state block, just add to end of lights chain */
2687 if (This->isRecordingState) {
2688 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2689 if (NULL == object) {
2690 return WINED3DERR_OUTOFVIDEOMEMORY;
2692 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2693 object->OriginalIndex = Index;
2694 object->glIndex = -1;
2695 object->changed = TRUE;
2697 /* Add to the END of the chain of lights changes to be replayed */
2698 if (This->updateStateBlock->lights == NULL) {
2699 This->updateStateBlock->lights = object;
2700 } else {
2701 temp = This->updateStateBlock->lights;
2702 while (temp->next != NULL) temp=temp->next;
2703 temp->next = object;
2705 TRACE("Recording... not performing anything more\n");
2706 return WINED3D_OK;
2709 /* Ok, not recording any longer so do real work */
2710 object = This->stateBlock->lights;
2711 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2713 /* If we didn't find it in the list of lights, time to add it */
2714 if (object == NULL) {
2715 PLIGHTINFOEL *insertAt,*prevPos;
2717 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2718 if (NULL == object) {
2719 return WINED3DERR_OUTOFVIDEOMEMORY;
2721 object->OriginalIndex = Index;
2722 object->glIndex = -1;
2724 /* Add it to the front of list with the idea that lights will be changed as needed
2725 BUT after any lights currently assigned GL indexes */
2726 insertAt = This->stateBlock->lights;
2727 prevPos = NULL;
2728 while (insertAt != NULL && insertAt->glIndex != -1) {
2729 prevPos = insertAt;
2730 insertAt = insertAt->next;
2733 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2734 This->stateBlock->lights = object;
2735 } else if (insertAt == NULL) { /* End of list */
2736 prevPos->next = object;
2737 object->prev = prevPos;
2738 } else { /* Middle of chain */
2739 if (prevPos == NULL) {
2740 This->stateBlock->lights = object;
2741 } else {
2742 prevPos->next = object;
2744 object->prev = prevPos;
2745 object->next = insertAt;
2746 insertAt->prev = object;
2750 /* Initialize the object */
2751 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,
2752 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2753 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2754 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2755 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2756 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2757 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2759 /* Save away the information */
2760 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2762 switch (pLight->Type) {
2763 case D3DLIGHT_POINT:
2764 /* Position */
2765 object->lightPosn[0] = pLight->Position.x;
2766 object->lightPosn[1] = pLight->Position.y;
2767 object->lightPosn[2] = pLight->Position.z;
2768 object->lightPosn[3] = 1.0f;
2769 object->cutoff = 180.0f;
2770 /* FIXME: Range */
2771 break;
2773 case D3DLIGHT_DIRECTIONAL:
2774 /* Direction */
2775 object->lightPosn[0] = -pLight->Direction.x;
2776 object->lightPosn[1] = -pLight->Direction.y;
2777 object->lightPosn[2] = -pLight->Direction.z;
2778 object->lightPosn[3] = 0.0;
2779 object->exponent = 0.0f;
2780 object->cutoff = 180.0f;
2781 break;
2783 case D3DLIGHT_SPOT:
2784 /* Position */
2785 object->lightPosn[0] = pLight->Position.x;
2786 object->lightPosn[1] = pLight->Position.y;
2787 object->lightPosn[2] = pLight->Position.z;
2788 object->lightPosn[3] = 1.0;
2790 /* Direction */
2791 object->lightDirn[0] = pLight->Direction.x;
2792 object->lightDirn[1] = pLight->Direction.y;
2793 object->lightDirn[2] = pLight->Direction.z;
2794 object->lightDirn[3] = 1.0;
2797 * opengl-ish and d3d-ish spot lights use too different models for the
2798 * light "intensity" as a function of the angle towards the main light direction,
2799 * so we only can approximate very roughly.
2800 * however spot lights are rather rarely used in games (if ever used at all).
2801 * furthermore if still used, probably nobody pays attention to such details.
2803 if (pLight->Falloff == 0) {
2804 rho = 6.28f;
2805 } else {
2806 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2808 if (rho < 0.0001) rho = 0.0001f;
2809 object->exponent = -0.3/log(cos(rho/2));
2810 object->cutoff = pLight->Phi*90/M_PI;
2812 /* FIXME: Range */
2813 break;
2815 default:
2816 FIXME("Unrecognized light type %d\n", pLight->Type);
2819 /* Update the live definitions if the light is currently assigned a glIndex */
2820 if (object->glIndex != -1) {
2821 setup_light(iface, object->glIndex, object);
2823 return WINED3D_OK;
2826 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2827 PLIGHTINFOEL *lightInfo = NULL;
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2829 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2831 /* Locate the light in the live lights */
2832 lightInfo = This->stateBlock->lights;
2833 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2835 if (lightInfo == NULL) {
2836 TRACE("Light information requested but light not defined\n");
2837 return WINED3DERR_INVALIDCALL;
2840 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2841 return WINED3D_OK;
2844 /*****
2845 * Get / Set Light Enable
2846 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2847 *****/
2848 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2849 PLIGHTINFOEL *lightInfo = NULL;
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2853 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2854 if (This->isRecordingState) {
2855 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2856 if (NULL == lightInfo) {
2857 return WINED3DERR_OUTOFVIDEOMEMORY;
2859 lightInfo->OriginalIndex = Index;
2860 lightInfo->glIndex = -1;
2861 lightInfo->enabledChanged = TRUE;
2863 /* Add to the END of the chain of lights changes to be replayed */
2864 if (This->updateStateBlock->lights == NULL) {
2865 This->updateStateBlock->lights = lightInfo;
2866 } else {
2867 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2868 while (temp->next != NULL) temp=temp->next;
2869 temp->next = lightInfo;
2871 TRACE("Recording... not performing anything more\n");
2872 return WINED3D_OK;
2875 /* Not recording... So, locate the light in the live lights */
2876 lightInfo = This->stateBlock->lights;
2877 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2879 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2880 if (lightInfo == NULL) {
2882 TRACE("Light enabled requested but light not defined, so defining one!\n");
2883 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2885 /* Search for it again! Should be fairly quick as near head of list */
2886 lightInfo = This->stateBlock->lights;
2887 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2888 if (lightInfo == NULL) {
2889 FIXME("Adding default lights has failed dismally\n");
2890 return WINED3DERR_INVALIDCALL;
2894 /* OK, we now have a light... */
2895 if (Enable == FALSE) {
2897 /* If we are disabling it, check it was enabled, and
2898 still only do something if it has assigned a glIndex (which it should have!) */
2899 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2900 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2901 ENTER_GL();
2902 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2903 checkGLcall("glDisable GL_LIGHT0+Index");
2904 LEAVE_GL();
2905 } else {
2906 TRACE("Nothing to do as light was not enabled\n");
2908 lightInfo->lightEnabled = FALSE;
2909 } else {
2911 /* We are enabling it. If it is enabled, it's really simple */
2912 if (lightInfo->lightEnabled) {
2913 /* nop */
2914 TRACE("Nothing to do as light was enabled\n");
2916 /* If it already has a glIndex, it's still simple */
2917 } else if (lightInfo->glIndex != -1) {
2918 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2919 lightInfo->lightEnabled = TRUE;
2920 ENTER_GL();
2921 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2922 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2923 LEAVE_GL();
2925 /* Otherwise got to find space - lights are ordered gl indexes first */
2926 } else {
2927 PLIGHTINFOEL *bsf = NULL;
2928 PLIGHTINFOEL *pos = This->stateBlock->lights;
2929 PLIGHTINFOEL *prev = NULL;
2930 int Index= 0;
2931 int glIndex = -1;
2933 /* Try to minimize changes as much as possible */
2934 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2936 /* Try to remember which index can be replaced if necessary */
2937 if (bsf==NULL && pos->lightEnabled == FALSE) {
2938 /* Found a light we can replace, save as best replacement */
2939 bsf = pos;
2942 /* Step to next space */
2943 prev = pos;
2944 pos = pos->next;
2945 Index ++;
2948 /* If we have too many active lights, fail the call */
2949 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2950 FIXME("Program requests too many concurrent lights\n");
2951 return WINED3DERR_INVALIDCALL;
2953 /* If we have allocated all lights, but not all are enabled,
2954 reuse one which is not enabled */
2955 } else if (Index == This->maxConcurrentLights) {
2956 /* use bsf - Simply swap the new light and the BSF one */
2957 PLIGHTINFOEL *bsfNext = bsf->next;
2958 PLIGHTINFOEL *bsfPrev = bsf->prev;
2960 /* Sort out ends */
2961 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2962 if (bsf->prev != NULL) {
2963 bsf->prev->next = lightInfo;
2964 } else {
2965 This->stateBlock->lights = lightInfo;
2968 /* If not side by side, lots of chains to update */
2969 if (bsf->next != lightInfo) {
2970 lightInfo->prev->next = bsf;
2971 bsf->next->prev = lightInfo;
2972 bsf->next = lightInfo->next;
2973 bsf->prev = lightInfo->prev;
2974 lightInfo->next = bsfNext;
2975 lightInfo->prev = bsfPrev;
2977 } else {
2978 /* Simple swaps */
2979 bsf->prev = lightInfo;
2980 bsf->next = lightInfo->next;
2981 lightInfo->next = bsf;
2982 lightInfo->prev = bsfPrev;
2986 /* Update states */
2987 glIndex = bsf->glIndex;
2988 bsf->glIndex = -1;
2989 lightInfo->glIndex = glIndex;
2990 lightInfo->lightEnabled = TRUE;
2992 /* Finally set up the light in gl itself */
2993 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2994 ENTER_GL();
2995 setup_light(iface, glIndex, lightInfo);
2996 glEnable(GL_LIGHT0 + glIndex);
2997 checkGLcall("glEnable GL_LIGHT0 new setup");
2998 LEAVE_GL();
3000 /* If we reached the end of the allocated lights, with space in the
3001 gl lights, setup a new light */
3002 } else if (pos->glIndex == -1) {
3004 /* We reached the end of the allocated gl lights, so already
3005 know the index of the next one! */
3006 glIndex = Index;
3007 lightInfo->glIndex = glIndex;
3008 lightInfo->lightEnabled = TRUE;
3010 /* In an ideal world, it's already in the right place */
3011 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
3012 /* No need to move it */
3013 } else {
3014 /* Remove this light from the list */
3015 lightInfo->prev->next = lightInfo->next;
3016 if (lightInfo->next != NULL) {
3017 lightInfo->next->prev = lightInfo->prev;
3020 /* Add in at appropriate place (inbetween prev and pos) */
3021 lightInfo->prev = prev;
3022 lightInfo->next = pos;
3023 if (prev == NULL) {
3024 This->stateBlock->lights = lightInfo;
3025 } else {
3026 prev->next = lightInfo;
3028 if (pos != NULL) {
3029 pos->prev = lightInfo;
3033 /* Finally set up the light in gl itself */
3034 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
3035 ENTER_GL();
3036 setup_light(iface, glIndex, lightInfo);
3037 glEnable(GL_LIGHT0 + glIndex);
3038 checkGLcall("glEnable GL_LIGHT0 new setup");
3039 LEAVE_GL();
3044 return WINED3D_OK;
3047 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3049 PLIGHTINFOEL *lightInfo = NULL;
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 TRACE("(%p) : for idx(%ld)\n", This, Index);
3053 /* Locate the light in the live lights */
3054 lightInfo = This->stateBlock->lights;
3055 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3057 if (lightInfo == NULL) {
3058 TRACE("Light enabled state requested but light not defined\n");
3059 return WINED3DERR_INVALIDCALL;
3061 *pEnable = lightInfo->lightEnabled;
3062 return WINED3D_OK;
3065 /*****
3066 * Get / Set Clip Planes
3067 *****/
3068 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3072 /* Validate Index */
3073 if (Index >= GL_LIMITS(clipplanes)) {
3074 TRACE("Application has requested clipplane this device doesn't support\n");
3075 return WINED3DERR_INVALIDCALL;
3078 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3079 This->updateStateBlock->set.clipplane[Index] = TRUE;
3080 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3081 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3082 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3083 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3085 /* Handle recording of state blocks */
3086 if (This->isRecordingState) {
3087 TRACE("Recording... not performing anything\n");
3088 return WINED3D_OK;
3091 /* Apply it */
3093 ENTER_GL();
3095 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3096 glMatrixMode(GL_MODELVIEW);
3097 glPushMatrix();
3098 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
3100 TRACE("Clipplane [%f,%f,%f,%f]\n",
3101 This->updateStateBlock->clipplane[Index][0],
3102 This->updateStateBlock->clipplane[Index][1],
3103 This->updateStateBlock->clipplane[Index][2],
3104 This->updateStateBlock->clipplane[Index][3]);
3105 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3106 checkGLcall("glClipPlane");
3108 glPopMatrix();
3109 LEAVE_GL();
3111 return WINED3D_OK;
3114 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3116 TRACE("(%p) : for idx %ld\n", This, Index);
3118 /* Validate Index */
3119 if (Index >= GL_LIMITS(clipplanes)) {
3120 TRACE("Application has requested clipplane this device doesn't support\n");
3121 return WINED3DERR_INVALIDCALL;
3124 pPlane[0] = This->stateBlock->clipplane[Index][0];
3125 pPlane[1] = This->stateBlock->clipplane[Index][1];
3126 pPlane[2] = This->stateBlock->clipplane[Index][2];
3127 pPlane[3] = This->stateBlock->clipplane[Index][3];
3128 return WINED3D_OK;
3131 /*****
3132 * Get / Set Clip Plane Status
3133 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3134 *****/
3135 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3137 FIXME("(%p) : stub\n", This);
3138 if (NULL == pClipStatus) {
3139 return WINED3DERR_INVALIDCALL;
3141 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3142 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3143 return WINED3D_OK;
3146 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 FIXME("(%p) : stub\n", This);
3149 if (NULL == pClipStatus) {
3150 return WINED3DERR_INVALIDCALL;
3152 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3153 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3154 return WINED3D_OK;
3157 /*****
3158 * Get / Set Material
3159 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3160 *****/
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 This->updateStateBlock->changed.material = TRUE;
3165 This->updateStateBlock->set.material = TRUE;
3166 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3168 /* Handle recording of state blocks */
3169 if (This->isRecordingState) {
3170 TRACE("Recording... not performing anything\n");
3171 return WINED3D_OK;
3174 ENTER_GL();
3175 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3176 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3177 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3178 pMaterial->Ambient.b, pMaterial->Ambient.a);
3179 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3180 pMaterial->Specular.b, pMaterial->Specular.a);
3181 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3182 pMaterial->Emissive.b, pMaterial->Emissive.a);
3183 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3185 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3186 checkGLcall("glMaterialfv(GL_AMBIENT)");
3187 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3188 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3190 /* Only change material color if specular is enabled, otherwise it is set to black */
3191 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3192 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3193 checkGLcall("glMaterialfv(GL_SPECULAR");
3194 } else {
3195 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3196 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3197 checkGLcall("glMaterialfv(GL_SPECULAR");
3199 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3200 checkGLcall("glMaterialfv(GL_EMISSION)");
3201 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3202 checkGLcall("glMaterialf(GL_SHININESS");
3204 LEAVE_GL();
3205 return WINED3D_OK;
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3211 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3212 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3213 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3214 pMaterial->Ambient.b, pMaterial->Ambient.a);
3215 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3216 pMaterial->Specular.b, pMaterial->Specular.a);
3217 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3218 pMaterial->Emissive.b, pMaterial->Emissive.a);
3219 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3221 return WINED3D_OK;
3224 /*****
3225 * Get / Set Indices
3226 *****/
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3228 UINT BaseVertexIndex) {
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 IWineD3DIndexBuffer *oldIdxs;
3232 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3233 oldIdxs = This->updateStateBlock->pIndexData;
3235 This->updateStateBlock->changed.indices = TRUE;
3236 This->updateStateBlock->set.indices = TRUE;
3237 This->updateStateBlock->pIndexData = pIndexData;
3238 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3240 /* Handle recording of state blocks */
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3243 return WINED3D_OK;
3246 if (NULL != pIndexData) {
3247 IWineD3DIndexBuffer_AddRef(pIndexData);
3249 if (NULL != oldIdxs) {
3250 IWineD3DIndexBuffer_Release(oldIdxs);
3252 return WINED3D_OK;
3255 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 *ppIndexData = This->stateBlock->pIndexData;
3260 /* up ref count on ppindexdata */
3261 if (*ppIndexData) {
3262 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3263 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3264 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3265 }else{
3266 TRACE("(%p) No index data set\n", This);
3268 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3270 return WINED3D_OK;
3273 /*****
3274 * Get / Set Viewports
3275 *****/
3276 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 TRACE("(%p)\n", This);
3280 This->updateStateBlock->changed.viewport = TRUE;
3281 This->updateStateBlock->set.viewport = TRUE;
3282 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3284 /* Handle recording of state blocks */
3285 if (This->isRecordingState) {
3286 TRACE("Recording... not performing anything\n");
3287 return WINED3D_OK;
3289 This->viewport_changed = TRUE;
3291 ENTER_GL();
3293 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3294 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3296 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3297 checkGLcall("glDepthRange");
3298 /* Note: GL requires lower left, DirectX supplies upper left */
3299 /* TODO: replace usage of renderTarget with context management */
3300 glViewport(pViewport->X,
3301 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3302 pViewport->Width, pViewport->Height);
3304 checkGLcall("glViewport");
3306 LEAVE_GL();
3308 return WINED3D_OK;
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3314 TRACE("(%p)\n", This);
3315 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3316 return WINED3D_OK;
3319 static void renderstate_stencil_twosided(
3320 IWineD3DDeviceImpl *This,
3321 GLint face,
3322 GLint func,
3323 GLint ref,
3324 GLuint mask,
3325 GLint stencilFail,
3326 GLint depthFail,
3327 GLint stencilPass ) {
3328 #if 0 /* Don't use OpenGL 2.0 calls for now */
3329 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3330 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3331 checkGLcall("glStencilFuncSeparate(...)");
3332 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3333 checkGLcall("glStencilOpSeparate(...)");
3335 else
3336 #endif
3337 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3338 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3339 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3340 GL_EXTCALL(glActiveStencilFaceEXT(face));
3341 checkGLcall("glActiveStencilFaceEXT(...)");
3342 glStencilFunc(func, ref, mask);
3343 checkGLcall("glStencilFunc(...)");
3344 glStencilOp(stencilFail, depthFail, stencilPass);
3345 checkGLcall("glStencilOp(...)");
3346 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3347 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3348 checkGLcall("glStencilFuncSeparateATI(...)");
3349 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3350 checkGLcall("glStencilOpSeparateATI(...)");
3351 } else {
3352 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3356 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3357 DWORD onesided_enable = FALSE;
3358 DWORD twosided_enable = FALSE;
3359 GLint func = GL_ALWAYS;
3360 GLint func_ccw = GL_ALWAYS;
3361 GLint ref = 0;
3362 GLuint mask = 0;
3363 GLint stencilFail = GL_KEEP;
3364 GLint depthFail = GL_KEEP;
3365 GLint stencilPass = GL_KEEP;
3366 GLint stencilFail_ccw = GL_KEEP;
3367 GLint depthFail_ccw = GL_KEEP;
3368 GLint stencilPass_ccw = GL_KEEP;
3370 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3371 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3372 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3373 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3374 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3375 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3376 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3377 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3378 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3379 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3380 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3381 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3382 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3383 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3384 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3385 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3386 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3387 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3388 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3389 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3390 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3391 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3392 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3393 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3395 switch(State) {
3396 case WINED3DRS_STENCILENABLE :
3397 onesided_enable = Value;
3398 break;
3399 case WINED3DRS_TWOSIDEDSTENCILMODE :
3400 twosided_enable = Value;
3401 break;
3402 case WINED3DRS_STENCILFUNC :
3403 func = StencilFunc(Value);
3404 break;
3405 case WINED3DRS_CCW_STENCILFUNC :
3406 func_ccw = StencilFunc(Value);
3407 break;
3408 case WINED3DRS_STENCILREF :
3409 ref = Value;
3410 break;
3411 case WINED3DRS_STENCILMASK :
3412 mask = Value;
3413 break;
3414 case WINED3DRS_STENCILFAIL :
3415 stencilFail = StencilOp(Value);
3416 break;
3417 case WINED3DRS_STENCILZFAIL :
3418 depthFail = StencilOp(Value);
3419 break;
3420 case WINED3DRS_STENCILPASS :
3421 stencilPass = StencilOp(Value);
3422 break;
3423 case WINED3DRS_CCW_STENCILFAIL :
3424 stencilFail_ccw = StencilOp(Value);
3425 break;
3426 case WINED3DRS_CCW_STENCILZFAIL :
3427 depthFail_ccw = StencilOp(Value);
3428 break;
3429 case WINED3DRS_CCW_STENCILPASS :
3430 stencilPass_ccw = StencilOp(Value);
3431 break;
3432 default :
3433 ERR("This should not happen!");
3436 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3437 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3438 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3439 onesided_enable, twosided_enable, ref, mask,
3440 func, stencilFail, depthFail, stencilPass,
3441 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3443 if (twosided_enable) {
3444 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3445 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3446 } else {
3447 if (onesided_enable) {
3448 glEnable(GL_STENCIL_TEST);
3449 checkGLcall("glEnable GL_STENCIL_TEST");
3450 glStencilFunc(func, ref, mask);
3451 checkGLcall("glStencilFunc(...)");
3452 glStencilOp(stencilFail, depthFail, stencilPass);
3453 checkGLcall("glStencilOp(...)");
3454 } else {
3455 glDisable(GL_STENCIL_TEST);
3456 checkGLcall("glDisable GL_STENCIL_TEST");
3461 /*****
3462 * Get / Set Render States
3463 * TODO: Verify against dx9 definitions
3464 *****/
3465 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3468 DWORD OldValue = This->stateBlock->renderState[State];
3470 /* Simple way of referring to either a DWORD or a 4 byte float */
3471 union {
3472 DWORD d;
3473 float f;
3474 } tmpvalue;
3476 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3477 This->updateStateBlock->changed.renderState[State] = TRUE;
3478 This->updateStateBlock->set.renderState[State] = TRUE;
3479 This->updateStateBlock->renderState[State] = Value;
3481 /* Handle recording of state blocks */
3482 if (This->isRecordingState) {
3483 TRACE("Recording... not performing anything\n");
3484 return WINED3D_OK;
3487 ENTER_GL();
3489 switch (State) {
3490 case WINED3DRS_FILLMODE :
3491 switch ((D3DFILLMODE) Value) {
3492 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3493 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3494 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3495 default:
3496 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3498 checkGLcall("glPolygonMode (fillmode)");
3499 break;
3501 case WINED3DRS_LIGHTING :
3502 if (Value) {
3503 glEnable(GL_LIGHTING);
3504 checkGLcall("glEnable GL_LIGHTING");
3505 } else {
3506 glDisable(GL_LIGHTING);
3507 checkGLcall("glDisable GL_LIGHTING");
3509 break;
3511 case WINED3DRS_ZENABLE :
3512 switch ((D3DZBUFFERTYPE) Value) {
3513 case D3DZB_FALSE:
3514 glDisable(GL_DEPTH_TEST);
3515 checkGLcall("glDisable GL_DEPTH_TEST");
3516 break;
3517 case D3DZB_TRUE:
3518 glEnable(GL_DEPTH_TEST);
3519 checkGLcall("glEnable GL_DEPTH_TEST");
3520 break;
3521 case D3DZB_USEW:
3522 glEnable(GL_DEPTH_TEST);
3523 checkGLcall("glEnable GL_DEPTH_TEST");
3524 FIXME("W buffer is not well handled\n");
3525 break;
3526 default:
3527 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3529 break;
3531 case WINED3DRS_CULLMODE :
3533 /* If we are culling "back faces with clockwise vertices" then
3534 set front faces to be counter clockwise and enable culling
3535 of back faces */
3536 switch ((D3DCULL) Value) {
3537 case D3DCULL_NONE:
3538 glDisable(GL_CULL_FACE);
3539 checkGLcall("glDisable GL_CULL_FACE");
3540 break;
3541 case D3DCULL_CW:
3542 glEnable(GL_CULL_FACE);
3543 checkGLcall("glEnable GL_CULL_FACE");
3544 if (This->renderUpsideDown) {
3545 glFrontFace(GL_CW);
3546 checkGLcall("glFrontFace GL_CW");
3547 } else {
3548 glFrontFace(GL_CCW);
3549 checkGLcall("glFrontFace GL_CCW");
3551 glCullFace(GL_BACK);
3552 break;
3553 case D3DCULL_CCW:
3554 glEnable(GL_CULL_FACE);
3555 checkGLcall("glEnable GL_CULL_FACE");
3556 if (This->renderUpsideDown) {
3557 glFrontFace(GL_CCW);
3558 checkGLcall("glFrontFace GL_CCW");
3559 } else {
3560 glFrontFace(GL_CW);
3561 checkGLcall("glFrontFace GL_CW");
3563 glCullFace(GL_BACK);
3564 break;
3565 default:
3566 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3568 break;
3570 case WINED3DRS_SHADEMODE :
3571 switch ((D3DSHADEMODE) Value) {
3572 case D3DSHADE_FLAT:
3573 glShadeModel(GL_FLAT);
3574 checkGLcall("glShadeModel");
3575 break;
3576 case D3DSHADE_GOURAUD:
3577 glShadeModel(GL_SMOOTH);
3578 checkGLcall("glShadeModel");
3579 break;
3580 case D3DSHADE_PHONG:
3581 FIXME("D3DSHADE_PHONG isn't supported?\n");
3583 LEAVE_GL();
3584 return WINED3DERR_INVALIDCALL;
3585 default:
3586 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3588 break;
3590 case WINED3DRS_DITHERENABLE :
3591 if (Value) {
3592 glEnable(GL_DITHER);
3593 checkGLcall("glEnable GL_DITHER");
3594 } else {
3595 glDisable(GL_DITHER);
3596 checkGLcall("glDisable GL_DITHER");
3598 break;
3600 case WINED3DRS_ZWRITEENABLE :
3601 if (Value) {
3602 glDepthMask(1);
3603 checkGLcall("glDepthMask");
3604 } else {
3605 glDepthMask(0);
3606 checkGLcall("glDepthMask");
3608 break;
3610 case WINED3DRS_ZFUNC :
3612 int glParm = GL_LESS;
3614 switch ((D3DCMPFUNC) Value) {
3615 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3616 case D3DCMP_LESS: glParm=GL_LESS; break;
3617 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3618 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3619 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3620 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3621 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3622 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3623 default:
3624 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3626 glDepthFunc(glParm);
3627 checkGLcall("glDepthFunc");
3629 break;
3631 case WINED3DRS_AMBIENT :
3633 float col[4];
3634 D3DCOLORTOGLFLOAT4(Value, col);
3635 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3636 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3637 checkGLcall("glLightModel for MODEL_AMBIENT");
3640 break;
3642 case WINED3DRS_ALPHABLENDENABLE :
3643 if (Value) {
3644 glEnable(GL_BLEND);
3645 checkGLcall("glEnable GL_BLEND");
3646 } else {
3647 glDisable(GL_BLEND);
3648 checkGLcall("glDisable GL_BLEND");
3650 break;
3652 case WINED3DRS_SRCBLEND :
3653 case WINED3DRS_DESTBLEND :
3655 int newVal = GL_ZERO;
3656 switch (Value) {
3657 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3658 case D3DBLEND_ONE : newVal = GL_ONE; break;
3659 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3660 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3661 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3662 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3663 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3664 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3665 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3666 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3667 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3669 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3670 This->srcBlend = newVal;
3671 This->dstBlend = newVal;
3672 break;
3674 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3675 This->srcBlend = newVal;
3676 This->dstBlend = newVal;
3677 break;
3678 default:
3679 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3682 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3683 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3684 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3685 glBlendFunc(This->srcBlend, This->dstBlend);
3687 checkGLcall("glBlendFunc");
3689 break;
3691 case WINED3DRS_ALPHATESTENABLE :
3692 case WINED3DRS_ALPHAFUNC :
3693 case WINED3DRS_ALPHAREF :
3694 case WINED3DRS_COLORKEYENABLE :
3696 int glParm = 0.0;
3697 float ref = GL_LESS;
3698 BOOL enable_ckey = FALSE;
3700 IWineD3DSurfaceImpl *surf;
3702 /* Find out if the texture on the first stage has a ckey set */
3703 if(This->stateBlock->textures[0]) {
3704 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3705 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3708 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3709 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3710 glEnable(GL_ALPHA_TEST);
3711 checkGLcall("glEnable GL_ALPHA_TEST");
3712 } else {
3713 glDisable(GL_ALPHA_TEST);
3714 checkGLcall("glDisable GL_ALPHA_TEST");
3715 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3716 * enable call
3718 break;
3721 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3722 glParm = GL_NOTEQUAL;
3723 ref = 0.0;
3724 } else {
3725 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3727 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3728 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3729 case D3DCMP_LESS: glParm = GL_LESS; break;
3730 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3731 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3732 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3733 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3734 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3735 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3736 default:
3737 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3740 This->alphafunc = glParm;
3741 glAlphaFunc(glParm, ref);
3742 checkGLcall("glAlphaFunc");
3744 break;
3746 case WINED3DRS_CLIPPLANEENABLE :
3747 case WINED3DRS_CLIPPING :
3749 /* Ensure we only do the changed clip planes */
3750 DWORD enable = 0xFFFFFFFF;
3751 DWORD disable = 0x00000000;
3753 /* If enabling / disabling all */
3754 if (State == WINED3DRS_CLIPPING) {
3755 if (Value) {
3756 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3757 disable = 0x00;
3758 } else {
3759 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3760 enable = 0x00;
3762 } else {
3763 enable = Value & ~OldValue;
3764 disable = ~Value & OldValue;
3767 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3768 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3769 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3770 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3771 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3772 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3774 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3775 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3776 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3777 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3778 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3779 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3781 /** update clipping status */
3782 if (enable) {
3783 This->stateBlock->clip_status.ClipUnion = 0;
3784 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3785 } else {
3786 This->stateBlock->clip_status.ClipUnion = 0;
3787 This->stateBlock->clip_status.ClipIntersection = 0;
3790 break;
3792 case WINED3DRS_BLENDOP :
3794 int glParm = GL_FUNC_ADD;
3796 switch ((D3DBLENDOP) Value) {
3797 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3798 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3799 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3800 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3801 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3802 default:
3803 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3806 if(GL_SUPPORT(ARB_IMAGING)) {
3807 TRACE("glBlendEquation(%x)\n", glParm);
3808 GL_EXTCALL(glBlendEquation(glParm));
3809 checkGLcall("glBlendEquation");
3810 } else {
3811 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3814 break;
3816 case WINED3DRS_TEXTUREFACTOR :
3818 unsigned int i;
3820 /* Note the texture color applies to all textures whereas
3821 GL_TEXTURE_ENV_COLOR applies to active only */
3822 float col[4];
3823 D3DCOLORTOGLFLOAT4(Value, col);
3824 /* Set the default alpha blend color */
3825 if (GL_SUPPORT(ARB_IMAGING)) {
3826 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3827 checkGLcall("glBlendColor");
3828 } else {
3829 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3832 /* And now the default texture color as well */
3833 for (i = 0; i < GL_LIMITS(textures); i++) {
3835 /* Note the D3DRS value applies to all textures, but GL has one
3836 per texture, so apply it now ready to be used! */
3837 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3838 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3839 checkGLcall("glActiveTextureARB");
3840 } else if (i>0) {
3841 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3844 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3845 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3848 break;
3850 case WINED3DRS_SPECULARENABLE :
3852 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3853 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3854 specular color. This is wrong:
3855 Separate specular color means the specular colour is maintained separately, whereas
3856 single color means it is merged in. However in both cases they are being used to
3857 some extent.
3858 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3859 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3860 running 1.4 yet!
3862 if (Value) {
3863 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3864 checkGLcall("glMaterialfv");
3865 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3866 glEnable(GL_COLOR_SUM_EXT);
3867 } else {
3868 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3870 checkGLcall("glEnable(GL_COLOR_SUM)");
3871 } else {
3872 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3874 /* for the case of enabled lighting: */
3875 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3876 checkGLcall("glMaterialfv");
3878 /* for the case of disabled lighting: */
3879 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3880 glDisable(GL_COLOR_SUM_EXT);
3881 } else {
3882 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3884 checkGLcall("glDisable(GL_COLOR_SUM)");
3887 break;
3889 case WINED3DRS_STENCILENABLE :
3890 case WINED3DRS_TWOSIDEDSTENCILMODE :
3891 case WINED3DRS_STENCILFUNC :
3892 case WINED3DRS_CCW_STENCILFUNC :
3893 case WINED3DRS_STENCILREF :
3894 case WINED3DRS_STENCILMASK :
3895 case WINED3DRS_STENCILFAIL :
3896 case WINED3DRS_STENCILZFAIL :
3897 case WINED3DRS_STENCILPASS :
3898 case WINED3DRS_CCW_STENCILFAIL :
3899 case WINED3DRS_CCW_STENCILZFAIL :
3900 case WINED3DRS_CCW_STENCILPASS :
3901 renderstate_stencil(This, State, Value);
3902 break;
3903 case WINED3DRS_STENCILWRITEMASK :
3905 glStencilMask(Value);
3906 TRACE("glStencilMask(%lu)\n", Value);
3907 checkGLcall("glStencilMask");
3909 break;
3911 case WINED3DRS_FOGENABLE :
3913 if (Value) {
3914 glEnable(GL_FOG);
3915 checkGLcall("glEnable GL_FOG");
3916 } else {
3917 glDisable(GL_FOG);
3918 checkGLcall("glDisable GL_FOG");
3921 break;
3923 case WINED3DRS_RANGEFOGENABLE :
3925 if (Value) {
3926 TRACE("Enabled RANGEFOG");
3927 } else {
3928 TRACE("Disabled RANGEFOG");
3931 break;
3933 case WINED3DRS_FOGCOLOR :
3935 float col[4];
3936 D3DCOLORTOGLFLOAT4(Value, col);
3937 /* Set the default alpha blend color */
3938 glFogfv(GL_FOG_COLOR, &col[0]);
3939 checkGLcall("glFog GL_FOG_COLOR");
3941 break;
3943 case WINED3DRS_FOGTABLEMODE :
3944 case WINED3DRS_FOGVERTEXMODE :
3946 /* 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." */
3947 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3948 glHint(GL_FOG_HINT, GL_FASTEST);
3949 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3950 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3951 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3952 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3954 case D3DFOG_EXP: {
3955 if(!This->last_was_rhw) {
3956 glFogi(GL_FOG_MODE, GL_EXP);
3957 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3958 if(GL_SUPPORT(EXT_FOG_COORD)) {
3959 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3960 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3961 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3962 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3964 break;
3967 case D3DFOG_EXP2: {
3968 if(!This->last_was_rhw) {
3969 glFogi(GL_FOG_MODE, GL_EXP2);
3970 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3971 if(GL_SUPPORT(EXT_FOG_COORD)) {
3972 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3973 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3974 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3975 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3977 break;
3980 case D3DFOG_LINEAR: {
3981 if(!This->last_was_rhw) {
3982 glFogi(GL_FOG_MODE, GL_LINEAR);
3983 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3984 if(GL_SUPPORT(EXT_FOG_COORD)) {
3985 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3986 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3987 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3988 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3990 break;
3993 case D3DFOG_NONE: {
3994 /* Both are none? According to msdn the alpha channel of the specular
3995 * color contains a fog factor. Set it in drawStridedSlow.
3996 * Same happens with Vertexfog on transformed vertices
3998 if(GL_SUPPORT(EXT_FOG_COORD)) {
3999 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
4000 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
4001 glFogi(GL_FOG_MODE, GL_LINEAR);
4002 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
4003 glFogf(GL_FOG_START, (float) 0xff);
4004 checkGLcall("glFogfv GL_FOG_START");
4005 glFogf(GL_FOG_END, 0.0);
4006 checkGLcall("glFogfv GL_FOG_END");
4007 } else {
4008 /* Disable GL fog, handle this in software in drawStridedSlow */
4009 glDisable(GL_FOG);
4010 checkGLcall("glDisable(GL_FOG)");
4012 break;
4014 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
4016 } else {
4017 glHint(GL_FOG_HINT, GL_NICEST);
4018 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
4019 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
4020 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
4021 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
4022 if(GL_SUPPORT(EXT_FOG_COORD)) {
4023 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4024 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4025 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4026 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4028 break;
4029 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
4030 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
4031 if(GL_SUPPORT(EXT_FOG_COORD)) {
4032 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4033 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4034 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4035 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4037 break;
4038 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
4039 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
4040 if(GL_SUPPORT(EXT_FOG_COORD)) {
4041 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
4042 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
4043 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
4044 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
4046 break;
4047 case D3DFOG_NONE: /* Won't happen */
4048 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4051 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4052 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4055 break;
4057 case WINED3DRS_FOGSTART :
4059 tmpvalue.d = Value;
4060 glFogfv(GL_FOG_START, &tmpvalue.f);
4061 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4062 TRACE("Fog Start == %f\n", tmpvalue.f);
4064 break;
4066 case WINED3DRS_FOGEND :
4068 tmpvalue.d = Value;
4069 glFogfv(GL_FOG_END, &tmpvalue.f);
4070 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4071 TRACE("Fog End == %f\n", tmpvalue.f);
4073 break;
4075 case WINED3DRS_FOGDENSITY :
4077 tmpvalue.d = Value;
4078 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4079 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4081 break;
4083 case WINED3DRS_VERTEXBLEND :
4085 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4086 TRACE("Vertex Blending state to %ld\n", Value);
4088 break;
4090 case WINED3DRS_TWEENFACTOR :
4092 tmpvalue.d = Value;
4093 This->updateStateBlock->tween_factor = tmpvalue.f;
4094 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4096 break;
4098 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4100 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4102 break;
4104 case WINED3DRS_COLORVERTEX :
4105 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4106 case WINED3DRS_SPECULARMATERIALSOURCE :
4107 case WINED3DRS_AMBIENTMATERIALSOURCE :
4108 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4110 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4112 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4113 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4114 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4115 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4116 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4117 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4119 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4120 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4121 Parm = GL_AMBIENT_AND_DIFFUSE;
4122 } else {
4123 Parm = GL_DIFFUSE;
4125 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4126 Parm = GL_AMBIENT;
4127 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4128 Parm = GL_EMISSION;
4129 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4130 Parm = GL_SPECULAR;
4131 } else {
4132 Parm = -1;
4135 if (Parm == -1) {
4136 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4137 } else {
4138 This->tracking_color = NEEDS_TRACKING;
4139 This->tracking_parm = Parm;
4142 } else {
4143 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4146 break;
4148 case WINED3DRS_LINEPATTERN :
4150 union {
4151 DWORD d;
4152 D3DLINEPATTERN lp;
4153 } tmppattern;
4154 tmppattern.d = Value;
4156 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4158 if (tmppattern.lp.wRepeatFactor) {
4159 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4160 checkGLcall("glLineStipple(repeat, linepattern)");
4161 glEnable(GL_LINE_STIPPLE);
4162 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4163 } else {
4164 glDisable(GL_LINE_STIPPLE);
4165 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4168 break;
4170 case WINED3DRS_ZBIAS : /* D3D8 only */
4172 if (Value) {
4173 tmpvalue.d = Value;
4174 TRACE("ZBias value %f\n", tmpvalue.f);
4175 glPolygonOffset(0, -tmpvalue.f);
4176 checkGLcall("glPolygonOffset(0, -Value)");
4177 glEnable(GL_POLYGON_OFFSET_FILL);
4178 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4179 glEnable(GL_POLYGON_OFFSET_LINE);
4180 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4181 glEnable(GL_POLYGON_OFFSET_POINT);
4182 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4183 } else {
4184 glDisable(GL_POLYGON_OFFSET_FILL);
4185 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4186 glDisable(GL_POLYGON_OFFSET_LINE);
4187 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4188 glDisable(GL_POLYGON_OFFSET_POINT);
4189 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4192 break;
4194 case WINED3DRS_NORMALIZENORMALS :
4195 if (Value) {
4196 glEnable(GL_NORMALIZE);
4197 checkGLcall("glEnable(GL_NORMALIZE);");
4198 } else {
4199 glDisable(GL_NORMALIZE);
4200 checkGLcall("glDisable(GL_NORMALIZE);");
4202 break;
4204 case WINED3DRS_POINTSIZE :
4205 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4206 tmpvalue.d = Value;
4207 TRACE("Set point size to %f\n", tmpvalue.f);
4208 glPointSize(tmpvalue.f);
4209 checkGLcall("glPointSize(...);");
4210 break;
4212 case WINED3DRS_POINTSIZE_MIN :
4213 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4214 tmpvalue.d = Value;
4215 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4216 checkGLcall("glPointParameterfEXT(...);");
4217 } else {
4218 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4220 break;
4222 case WINED3DRS_POINTSIZE_MAX :
4223 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4224 tmpvalue.d = Value;
4225 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4226 checkGLcall("glPointParameterfEXT(...);");
4227 } else {
4228 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4230 break;
4232 case WINED3DRS_POINTSCALE_A :
4233 case WINED3DRS_POINTSCALE_B :
4234 case WINED3DRS_POINTSCALE_C :
4235 case WINED3DRS_POINTSCALEENABLE :
4238 * POINTSCALEENABLE controls how point size value is treated. If set to
4239 * true, the point size is scaled with respect to height of viewport.
4240 * When set to false point size is in pixels.
4242 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4245 /* Default values */
4246 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4249 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4250 * This means that OpenGL will clamp really small point sizes to 1.0f.
4251 * To correct for this we need to multiply by the scale factor when sizes
4252 * are less than 1.0f. scale_factor = 1.0f / point_size.
4254 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4255 if(pointSize > 0.0f) {
4256 GLfloat scaleFactor;
4258 if(pointSize < 1.0f) {
4259 scaleFactor = pointSize * pointSize;
4260 } else {
4261 scaleFactor = 1.0f;
4264 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4265 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4266 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4267 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4268 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4269 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4270 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4274 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4275 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4276 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4278 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4279 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4280 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4281 } else {
4282 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4284 break;
4286 case WINED3DRS_COLORWRITEENABLE :
4288 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4289 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4290 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4291 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4292 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4293 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4294 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4295 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4296 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4297 checkGLcall("glColorMask(...)");
4299 break;
4301 case WINED3DRS_LOCALVIEWER :
4303 GLint state = (Value) ? 1 : 0;
4304 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4305 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4307 break;
4309 case WINED3DRS_LASTPIXEL :
4311 if (Value) {
4312 TRACE("Last Pixel Drawing Enabled\n");
4313 } else {
4314 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4317 break;
4319 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4321 if (Value) {
4322 TRACE("Software Processing Enabled\n");
4323 } else {
4324 TRACE("Software Processing Disabled\n");
4327 break;
4329 /** not supported */
4330 case WINED3DRS_ZVISIBLE :
4332 LEAVE_GL();
4333 return WINED3DERR_INVALIDCALL;
4335 case WINED3DRS_POINTSPRITEENABLE :
4337 /* TODO: NV_POINT_SPRITE */
4338 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4339 TRACE("Point sprites not supported\n");
4340 break;
4344 * Point sprites are always enabled. Value controls texture coordinate
4345 * replacement mode. Must be set true for point sprites to use
4346 * textures.
4348 glEnable(GL_POINT_SPRITE_ARB);
4349 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4351 if (Value) {
4352 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4353 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4354 } else {
4355 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4356 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4358 break;
4360 case WINED3DRS_EDGEANTIALIAS :
4362 if(Value) {
4363 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4364 glEnable(GL_BLEND);
4365 checkGLcall("glEnable(GL_BLEND)");
4366 glEnable(GL_LINE_SMOOTH);
4367 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4368 } else {
4369 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4370 glDisable(GL_BLEND);
4371 checkGLcall("glDisable(GL_BLEND)");
4373 glDisable(GL_LINE_SMOOTH);
4374 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4376 break;
4378 case WINED3DRS_WRAP0 :
4379 case WINED3DRS_WRAP1 :
4380 case WINED3DRS_WRAP2 :
4381 case WINED3DRS_WRAP3 :
4382 case WINED3DRS_WRAP4 :
4383 case WINED3DRS_WRAP5 :
4384 case WINED3DRS_WRAP6 :
4385 case WINED3DRS_WRAP7 :
4386 case WINED3DRS_WRAP8 :
4387 case WINED3DRS_WRAP9 :
4388 case WINED3DRS_WRAP10 :
4389 case WINED3DRS_WRAP11 :
4390 case WINED3DRS_WRAP12 :
4391 case WINED3DRS_WRAP13 :
4392 case WINED3DRS_WRAP14 :
4393 case WINED3DRS_WRAP15 :
4395 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4396 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4397 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4398 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4399 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4401 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4403 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4404 break;
4405 case WINED3DRS_MULTISAMPLEANTIALIAS :
4407 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4408 TRACE("Multisample antialiasing not supported\n");
4409 break;
4412 if(Value) {
4413 glEnable(GL_MULTISAMPLE_ARB);
4414 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4415 } else {
4416 glDisable(GL_MULTISAMPLE_ARB);
4417 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4419 break;
4421 case WINED3DRS_SCISSORTESTENABLE :
4423 if(Value) {
4424 glEnable(GL_SCISSOR_TEST);
4425 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4426 } else {
4427 glDisable(GL_SCISSOR_TEST);
4428 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4430 break;
4432 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4434 if(Value) {
4435 tmpvalue.d = Value;
4436 glEnable(GL_POLYGON_OFFSET_FILL);
4437 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4438 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4439 checkGLcall("glPolygonOffset(...)");
4440 } else {
4441 glDisable(GL_POLYGON_OFFSET_FILL);
4442 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4444 break;
4446 case WINED3DRS_ANTIALIASEDLINEENABLE :
4448 if(Value) {
4449 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4450 glEnable(GL_BLEND);
4451 checkGLcall("glEnable(GL_BLEND)");
4452 glEnable(GL_LINE_SMOOTH);
4453 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4454 } else {
4455 glDisable(GL_BLEND);
4456 checkGLcall("glDisable(GL_BLEND)");
4457 glDisable(GL_LINE_SMOOTH);
4458 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4460 break;
4462 case WINED3DRS_DEPTHBIAS :
4464 if(Value) {
4465 tmpvalue.d = Value;
4466 glEnable(GL_POLYGON_OFFSET_FILL);
4467 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4468 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4469 checkGLcall("glPolygonOffset(...)");
4470 } else {
4471 glDisable(GL_POLYGON_OFFSET_FILL);
4472 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4474 break;
4477 case WINED3DRS_TEXTUREPERSPECTIVE :
4479 if (Value)
4480 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4481 else
4482 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4483 break;
4486 case WINED3DRS_STIPPLEDALPHA :
4488 if (Value)
4489 ERR(" Stippled Alpha not supported yet.\n");
4490 break;
4492 case WINED3DRS_ANTIALIAS :
4494 if (Value)
4495 ERR(" Antialias not supported yet.\n");
4496 break;
4498 default:
4499 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4502 LEAVE_GL();
4504 return WINED3D_OK;
4507 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4510 *pValue = This->stateBlock->renderState[State];
4511 return WINED3D_OK;
4514 /*****
4515 * Get / Set Sampler States
4516 * TODO: Verify against dx9 definitions
4517 *****/
4519 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 * SetSampler is designed to allow for more than the standard up to 8 textures
4523 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4524 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4526 * http://developer.nvidia.com/object/General_FAQ.html#t6
4528 * There are two new settings for GForce
4529 * the sampler one:
4530 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4531 * and the texture one:
4532 * GL_MAX_TEXTURE_COORDS_ARB.
4533 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4534 ******************/
4535 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4536 if(Sampler > GL_LIMITS(samplers) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4537 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4538 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(samplers), WINED3D_HIGHEST_SAMPLER_STATE);
4539 return WINED3DERR_INVALIDCALL;
4542 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4543 debug_d3dsamplerstate(Type), Type, Value);
4544 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4545 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4546 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4548 /* Handle recording of state blocks */
4549 if (This->isRecordingState) {
4550 TRACE("Recording... not performing anything\n");
4551 return WINED3D_OK;
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 /** TODO: check that sampler is in range **/
4560 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4561 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4563 return WINED3D_OK;
4566 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 ENTER_GL();
4570 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4571 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4572 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4573 LEAVE_GL();
4575 return WINED3D_OK;
4578 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 GLint scissorBox[4];
4582 ENTER_GL();
4583 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4584 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4585 pRect->left = scissorBox[0];
4586 pRect->top = scissorBox[1];
4587 pRect->right = scissorBox[0] + scissorBox[2];
4588 pRect->bottom = scissorBox[1] + scissorBox[3];
4589 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4590 LEAVE_GL();
4591 return WINED3D_OK;
4594 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4596 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4598 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4600 This->updateStateBlock->vertexDecl = pDecl;
4601 This->updateStateBlock->changed.vertexDecl = TRUE;
4602 This->updateStateBlock->set.vertexDecl = TRUE;
4604 if (This->isRecordingState) {
4605 TRACE("Recording... not performing anything\n");
4608 if (NULL != pDecl) {
4609 IWineD3DVertexDeclaration_AddRef(pDecl);
4611 if (NULL != oldDecl) {
4612 IWineD3DVertexDeclaration_Release(oldDecl);
4614 return WINED3D_OK;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4622 *ppDecl = This->stateBlock->vertexDecl;
4623 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4624 return WINED3D_OK;
4627 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4631 This->updateStateBlock->vertexShader = pShader;
4632 This->updateStateBlock->changed.vertexShader = TRUE;
4633 This->updateStateBlock->set.vertexShader = TRUE;
4635 if (This->isRecordingState) {
4636 TRACE("Recording... not performing anything\n");
4639 if (NULL != pShader) {
4640 IWineD3DVertexShader_AddRef(pShader);
4642 if (NULL != oldShader) {
4643 IWineD3DVertexShader_Release(oldShader);
4646 if (pShader != NULL && ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration != NULL) {
4647 TRACE("(%p) : setting vertexDeclaration(%p)\n", This, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4648 IWineD3DDevice_SetVertexDeclaration(iface, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4651 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4653 * TODO: merge HAL shaders context switching from prototype
4655 return WINED3D_OK;
4658 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 if (NULL == ppShader) {
4662 return WINED3DERR_INVALIDCALL;
4664 *ppShader = This->stateBlock->vertexShader;
4665 if( NULL != *ppShader)
4666 IWineD3DVertexShader_AddRef(*ppShader);
4668 TRACE("(%p) : returning %p\n", This, *ppShader);
4669 return WINED3D_OK;
4672 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4673 IWineD3DDevice *iface,
4674 UINT start,
4675 CONST BOOL *srcData,
4676 UINT count) {
4678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4679 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4681 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4682 iface, srcData, start, count);
4684 if (srcData == NULL || cnt < 0)
4685 return WINED3DERR_INVALIDCALL;
4687 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4689 for (i = start; i < cnt + start; ++i) {
4690 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4691 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4694 return WINED3D_OK;
4697 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4698 IWineD3DDevice *iface,
4699 UINT start,
4700 BOOL *dstData,
4701 UINT count) {
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4704 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4706 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4707 iface, dstData, start, count);
4709 if (dstData == NULL || cnt < 0)
4710 return WINED3DERR_INVALIDCALL;
4712 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4713 return WINED3D_OK;
4716 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4717 IWineD3DDevice *iface,
4718 UINT start,
4719 CONST int *srcData,
4720 UINT count) {
4722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4723 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4725 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4726 iface, srcData, start, count);
4728 if (srcData == NULL || cnt < 0)
4729 return WINED3DERR_INVALIDCALL;
4731 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4733 for (i = start; i < cnt + start; ++i) {
4734 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4735 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4738 return WINED3D_OK;
4741 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4742 IWineD3DDevice *iface,
4743 UINT start,
4744 int *dstData,
4745 UINT count) {
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4750 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4751 iface, dstData, start, count);
4753 if (dstData == NULL || cnt < 0)
4754 return WINED3DERR_INVALIDCALL;
4756 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4757 return WINED3D_OK;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4761 IWineD3DDevice *iface,
4762 UINT start,
4763 CONST float *srcData,
4764 UINT count) {
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4769 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4770 iface, srcData, start, count);
4772 if (srcData == NULL || cnt < 0)
4773 return WINED3DERR_INVALIDCALL;
4775 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4777 for (i = start; i < cnt + start; ++i) {
4778 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4779 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4782 return WINED3D_OK;
4785 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4786 IWineD3DDevice *iface,
4787 UINT start,
4788 float *dstData,
4789 UINT count) {
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4792 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4794 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4795 iface, dstData, start, count);
4797 if (dstData == NULL || cnt < 0)
4798 return WINED3DERR_INVALIDCALL;
4800 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4807 This->updateStateBlock->pixelShader = pShader;
4808 This->updateStateBlock->changed.pixelShader = TRUE;
4809 This->updateStateBlock->set.pixelShader = TRUE;
4811 /* Handle recording of state blocks */
4812 if (This->isRecordingState) {
4813 TRACE("Recording... not performing anything\n");
4816 if (NULL != pShader) {
4817 IWineD3DPixelShader_AddRef(pShader);
4819 if (NULL != oldShader) {
4820 IWineD3DPixelShader_Release(oldShader);
4823 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4825 * TODO: merge HAL shaders context switching from prototype
4827 return WINED3D_OK;
4830 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 if (NULL == ppShader) {
4834 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4835 return WINED3DERR_INVALIDCALL;
4838 *ppShader = This->stateBlock->pixelShader;
4839 if (NULL != *ppShader) {
4840 IWineD3DPixelShader_AddRef(*ppShader);
4842 TRACE("(%p) : returning %p\n", This, *ppShader);
4843 return WINED3D_OK;
4846 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4847 IWineD3DDevice *iface,
4848 UINT start,
4849 CONST BOOL *srcData,
4850 UINT count) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4855 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4856 iface, srcData, start, count);
4858 if (srcData == NULL || cnt < 0)
4859 return WINED3DERR_INVALIDCALL;
4861 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4863 for (i = start; i < cnt + start; ++i) {
4864 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4865 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4868 return WINED3D_OK;
4871 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4872 IWineD3DDevice *iface,
4873 UINT start,
4874 BOOL *dstData,
4875 UINT count) {
4877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4878 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4880 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4881 iface, dstData, start, count);
4883 if (dstData == NULL || cnt < 0)
4884 return WINED3DERR_INVALIDCALL;
4886 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4887 return WINED3D_OK;
4890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4891 IWineD3DDevice *iface,
4892 UINT start,
4893 CONST int *srcData,
4894 UINT count) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4899 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4900 iface, srcData, start, count);
4902 if (srcData == NULL || cnt < 0)
4903 return WINED3DERR_INVALIDCALL;
4905 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4907 for (i = start; i < cnt + start; ++i) {
4908 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4909 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4912 return WINED3D_OK;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4916 IWineD3DDevice *iface,
4917 UINT start,
4918 int *dstData,
4919 UINT count) {
4921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4922 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4924 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4925 iface, dstData, start, count);
4927 if (dstData == NULL || cnt < 0)
4928 return WINED3DERR_INVALIDCALL;
4930 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4931 return WINED3D_OK;
4934 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4935 IWineD3DDevice *iface,
4936 UINT start,
4937 CONST float *srcData,
4938 UINT count) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4943 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4944 iface, srcData, start, count);
4946 if (srcData == NULL || cnt < 0)
4947 return WINED3DERR_INVALIDCALL;
4949 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4951 for (i = start; i < cnt + start; ++i) {
4952 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4953 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4956 return WINED3D_OK;
4959 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4960 IWineD3DDevice *iface,
4961 UINT start,
4962 float *dstData,
4963 UINT count) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4968 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4969 iface, dstData, start, count);
4971 if (dstData == NULL || cnt < 0)
4972 return WINED3DERR_INVALIDCALL;
4974 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4975 return WINED3D_OK;
4978 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4979 static HRESULT
4980 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4981 char *dest_ptr, *dest_conv = NULL;
4982 unsigned int i;
4983 DWORD DestFVF = dest->fvf;
4984 D3DVIEWPORT9 vp;
4985 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4986 BOOL doClip;
4987 int numTextures;
4989 if (SrcFVF & D3DFVF_NORMAL) {
4990 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4993 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4994 ERR("Source has no position mask\n");
4995 return WINED3DERR_INVALIDCALL;
4998 /* We might access VBOs from this code, so hold the lock */
4999 ENTER_GL();
5001 if (dest->resource.allocatedMemory == NULL) {
5002 /* This may happen if we do direct locking into a vbo. Unlikely,
5003 * but theoretically possible(ddraw processvertices test)
5005 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5006 if(!dest->resource.allocatedMemory) {
5007 LEAVE_GL();
5008 ERR("Out of memory\n");
5009 return E_OUTOFMEMORY;
5011 if(dest->vbo) {
5012 void *src;
5013 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5014 checkGLcall("glBindBufferARB");
5015 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY));
5016 if(src) {
5017 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5019 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5020 checkGLcall("glUnmapBufferARB");
5024 /* Get a pointer into the destination vbo(create one if none exists) and
5025 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5027 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5028 CreateVBO(dest);
5031 if(dest->vbo) {
5032 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5033 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY));
5034 if(!dest_conv) {
5035 ERR("glMapBuffer failed\n");
5036 /* Continue without storing converted vertices */
5040 /* Should I clip?
5041 * a) D3DRS_CLIPPING is enabled
5042 * b) WINED3DVOP_CLIP is passed
5044 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5045 static BOOL warned = FALSE;
5047 * The clipping code is not quite correct. Some things need
5048 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5049 * so disable clipping for now.
5050 * (The graphics in Half-Life are broken, and my processvertices
5051 * test crashes with IDirect3DDevice3)
5052 doClip = TRUE;
5054 doClip = FALSE;
5055 if(!warned) {
5056 warned = TRUE;
5057 FIXME("Clipping is broken and disabled for now\n");
5059 } else doClip = FALSE;
5060 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5061 if(dest_conv) {
5062 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5065 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5066 D3DTS_VIEW,
5067 &view_mat);
5068 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5069 D3DTS_PROJECTION,
5070 &proj_mat);
5071 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5072 D3DTS_WORLDMATRIX(0),
5073 &world_mat);
5075 TRACE("View mat:\n");
5076 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); \
5077 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); \
5078 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); \
5079 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); \
5081 TRACE("Proj mat:\n");
5082 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); \
5083 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); \
5084 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); \
5085 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); \
5087 TRACE("World mat:\n");
5088 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); \
5089 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); \
5090 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); \
5091 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); \
5093 /* Get the viewport */
5094 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5095 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5096 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5098 multiply_matrix(&mat,&view_mat,&world_mat);
5099 multiply_matrix(&mat,&proj_mat,&mat);
5101 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5103 for (i = 0; i < dwCount; i+= 1) {
5104 unsigned int tex_index;
5106 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5107 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5108 /* The position first */
5109 float *p =
5110 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5111 float x, y, z, rhw;
5112 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5114 /* Multiplication with world, view and projection matrix */
5115 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);
5116 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);
5117 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);
5118 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);
5120 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5122 /* WARNING: The following things are taken from d3d7 and were not yet checked
5123 * against d3d8 or d3d9!
5126 /* Clipping conditions: From
5127 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5129 * A vertex is clipped if it does not match the following requirements
5130 * -rhw < x <= rhw
5131 * -rhw < y <= rhw
5132 * 0 < z <= rhw
5133 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5135 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5136 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5140 if( doClip == FALSE ||
5141 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5142 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5143 ( rhw > eps ) ) ) {
5145 /* "Normal" viewport transformation (not clipped)
5146 * 1) The values are divided by rhw
5147 * 2) The y axis is negative, so multiply it with -1
5148 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5149 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5150 * 4) Multiply x with Width/2 and add Width/2
5151 * 5) The same for the height
5152 * 6) Add the viewpoint X and Y to the 2D coordinates and
5153 * The minimum Z value to z
5154 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5156 * Well, basically it's simply a linear transformation into viewport
5157 * coordinates
5160 x /= rhw;
5161 y /= rhw;
5162 z /= rhw;
5164 y *= -1;
5166 x *= vp.Width / 2;
5167 y *= vp.Height / 2;
5168 z *= vp.MaxZ - vp.MinZ;
5170 x += vp.Width / 2 + vp.X;
5171 y += vp.Height / 2 + vp.Y;
5172 z += vp.MinZ;
5174 rhw = 1 / rhw;
5175 } else {
5176 /* That vertex got clipped
5177 * Contrary to OpenGL it is not dropped completely, it just
5178 * undergoes a different calculation.
5180 TRACE("Vertex got clipped\n");
5181 x += rhw;
5182 y += rhw;
5184 x /= 2;
5185 y /= 2;
5187 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5188 * outside of the main vertex buffer memory. That needs some more
5189 * investigation...
5193 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5196 ( (float *) dest_ptr)[0] = x;
5197 ( (float *) dest_ptr)[1] = y;
5198 ( (float *) dest_ptr)[2] = z;
5199 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5201 dest_ptr += 3 * sizeof(float);
5203 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5204 dest_ptr += sizeof(float);
5207 if(dest_conv) {
5208 float w = 1 / rhw;
5209 ( (float *) dest_conv)[0] = x * w;
5210 ( (float *) dest_conv)[1] = y * w;
5211 ( (float *) dest_conv)[2] = z * w;
5212 ( (float *) dest_conv)[3] = w;
5214 dest_conv += 3 * sizeof(float);
5216 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5217 dest_conv += sizeof(float);
5221 if (DestFVF & D3DFVF_PSIZE) {
5222 dest_ptr += sizeof(DWORD);
5223 if(dest_conv) dest_conv += sizeof(DWORD);
5225 if (DestFVF & D3DFVF_NORMAL) {
5226 float *normal =
5227 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5228 /* AFAIK this should go into the lighting information */
5229 FIXME("Didn't expect the destination to have a normal\n");
5230 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5231 if(dest_conv) {
5232 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5236 if (DestFVF & D3DFVF_DIFFUSE) {
5237 DWORD *color_d =
5238 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5239 if(!color_d) {
5240 static BOOL warned = FALSE;
5242 if(warned == FALSE) {
5243 ERR("No diffuse color in source, but destination has one\n");
5244 warned = TRUE;
5247 *( (DWORD *) dest_ptr) = 0xffffffff;
5248 dest_ptr += sizeof(DWORD);
5250 if(dest_conv) {
5251 *( (DWORD *) dest_conv) = 0xffffffff;
5252 dest_conv += sizeof(DWORD);
5255 else {
5256 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5257 if(dest_conv) {
5258 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5259 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5260 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5261 dest_conv += sizeof(DWORD);
5266 if (DestFVF & D3DFVF_SPECULAR) {
5267 /* What's the color value in the feedback buffer? */
5268 DWORD *color_s =
5269 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5270 if(!color_s) {
5271 static BOOL warned = FALSE;
5273 if(warned == FALSE) {
5274 ERR("No specular color in source, but destination has one\n");
5275 warned = TRUE;
5278 *( (DWORD *) dest_ptr) = 0xFF000000;
5279 dest_ptr += sizeof(DWORD);
5281 if(dest_conv) {
5282 *( (DWORD *) dest_conv) = 0xFF000000;
5283 dest_conv += sizeof(DWORD);
5286 else {
5287 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5288 if(dest_conv) {
5289 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5290 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5291 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5292 dest_conv += sizeof(DWORD);
5297 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5298 float *tex_coord =
5299 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5300 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5301 if(!tex_coord) {
5302 ERR("No source texture, but destination requests one\n");
5303 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5304 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5306 else {
5307 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5308 if(dest_conv) {
5309 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5315 if(dest_conv) {
5316 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5317 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5320 LEAVE_GL();
5322 return WINED3D_OK;
5324 #undef copy_and_next
5326 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5328 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5329 WineDirect3DVertexStridedData strided;
5330 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5332 /* We don't need the source vbo because this buffer is only used as
5333 * a source for ProcessVertices. Avoid wasting resources by converting the
5334 * buffer and loading the VBO
5336 if(SrcImpl->vbo) {
5337 TRACE("Releaseing the source vbo, it won't be needed\n");
5339 if(!SrcImpl->resource.allocatedMemory) {
5340 /* Rescue the data from the buffer */
5341 void *src;
5342 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5343 if(!SrcImpl->resource.allocatedMemory) {
5344 ERR("Out of memory\n");
5345 return E_OUTOFMEMORY;
5348 ENTER_GL();
5349 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5350 checkGLcall("glBindBufferARB");
5352 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY));
5353 if(src) {
5354 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5357 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5358 checkGLcall("glUnmapBufferARB");
5359 } else {
5360 ENTER_GL();
5363 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5364 checkGLcall("glBindBufferARB");
5365 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5366 checkGLcall("glDeleteBuffersARB");
5367 LEAVE_GL();
5369 SrcImpl->vbo = 0;
5372 memset(&strided, 0, sizeof(strided));
5373 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5375 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5378 /*****
5379 * Apply / Get / Set Texture Stage States
5380 * TODO: Verify against dx9 definitions
5381 *****/
5383 /* 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 */
5384 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5386 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5387 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5389 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5391 /* Check that the stage is within limits */
5392 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
5393 TRACE("Attempt to access invalid texture rejected\n");
5394 return;
5397 ENTER_GL();
5399 switch (Type) {
5400 case WINED3DTSS_ALPHAOP :
5401 case WINED3DTSS_COLOROP :
5402 /* nothing to do as moved to drawprim for now */
5403 break;
5404 case WINED3DTSS_ADDRESSW :
5405 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5406 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5407 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5409 } else {
5410 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5411 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5412 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5413 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5415 #endif
5416 case WINED3DTSS_TEXCOORDINDEX :
5418 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5420 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5421 one flag, you can still specify an index value, which the system uses to
5422 determine the texture wrapping mode.
5423 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5424 means use the vertex position (camera-space) as the input texture coordinates
5425 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5426 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5427 to the TEXCOORDINDEX value */
5430 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5432 switch (Value & 0xFFFF0000) {
5433 case D3DTSS_TCI_PASSTHRU:
5434 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5435 glDisable(GL_TEXTURE_GEN_S);
5436 glDisable(GL_TEXTURE_GEN_T);
5437 glDisable(GL_TEXTURE_GEN_R);
5438 glDisable(GL_TEXTURE_GEN_Q);
5439 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5440 break;
5442 case D3DTSS_TCI_CAMERASPACEPOSITION:
5443 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5444 as the input texture coordinates for this stage's texture transformation. This
5445 equates roughly to EYE_LINEAR */
5447 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5448 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5449 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5450 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5451 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5453 glMatrixMode(GL_MODELVIEW);
5454 glPushMatrix();
5455 glLoadIdentity();
5456 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5457 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5458 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5459 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5460 glPopMatrix();
5462 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5463 glEnable(GL_TEXTURE_GEN_S);
5464 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5465 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5466 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5467 glEnable(GL_TEXTURE_GEN_T);
5468 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5469 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5470 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5471 glEnable(GL_TEXTURE_GEN_R);
5472 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5473 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5474 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5476 break;
5478 case D3DTSS_TCI_CAMERASPACENORMAL:
5480 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5481 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5482 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5483 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5484 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5485 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5487 glMatrixMode(GL_MODELVIEW);
5488 glPushMatrix();
5489 glLoadIdentity();
5490 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5491 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5492 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5493 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5494 glPopMatrix();
5496 glEnable(GL_TEXTURE_GEN_S);
5497 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5498 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5499 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5500 glEnable(GL_TEXTURE_GEN_T);
5501 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5502 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5503 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5504 glEnable(GL_TEXTURE_GEN_R);
5505 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5506 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5507 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5510 break;
5512 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5514 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5515 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5516 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5517 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5518 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5519 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5521 glMatrixMode(GL_MODELVIEW);
5522 glPushMatrix();
5523 glLoadIdentity();
5524 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5525 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5526 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5527 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5528 glPopMatrix();
5530 glEnable(GL_TEXTURE_GEN_S);
5531 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5532 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5533 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5534 glEnable(GL_TEXTURE_GEN_T);
5535 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5536 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5537 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5538 glEnable(GL_TEXTURE_GEN_R);
5539 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5540 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5541 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5544 break;
5546 /* Unhandled types: */
5547 default:
5548 /* Todo: */
5549 /* ? disable GL_TEXTURE_GEN_n ? */
5550 glDisable(GL_TEXTURE_GEN_S);
5551 glDisable(GL_TEXTURE_GEN_T);
5552 glDisable(GL_TEXTURE_GEN_R);
5553 glDisable(GL_TEXTURE_GEN_Q);
5554 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5555 break;
5558 break;
5560 /* Unhandled */
5561 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5562 set_texture_matrix((float *)&This->stateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5563 break;
5565 case WINED3DTSS_BUMPENVMAT00 :
5566 case WINED3DTSS_BUMPENVMAT01 :
5567 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5568 break;
5569 case WINED3DTSS_BUMPENVMAT10 :
5570 case WINED3DTSS_BUMPENVMAT11 :
5571 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5572 break;
5574 case WINED3DTSS_BUMPENVLSCALE :
5575 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5576 break;
5578 case WINED3DTSS_BUMPENVLOFFSET :
5579 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5580 break;
5582 case WINED3DTSS_RESULTARG :
5583 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5584 break;
5586 default:
5587 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5588 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5591 LEAVE_GL();
5593 return;
5596 /*****
5597 * Get / Set Texture Stage States
5598 * TODO: Verify against dx9 definitions
5599 *****/
5600 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5605 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5607 /* Reject invalid texture units */
5608 if (Stage >= GL_LIMITS(textures)) {
5609 TRACE("Attempt to access invalid texture rejected\n");
5610 return WINED3DERR_INVALIDCALL;
5613 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5614 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5615 This->updateStateBlock->textureState[Stage][Type] = Value;
5617 return WINED3D_OK;
5620 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5622 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5623 *pValue = This->updateStateBlock->textureState[Stage][Type];
5624 return WINED3D_OK;
5627 /*****
5628 * Get / Set Texture
5629 *****/
5630 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5633 IWineD3DBaseTexture *oldTexture;
5635 oldTexture = This->updateStateBlock->textures[Stage];
5636 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5638 #if 0 /* TODO: check so vertex textures */
5639 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5640 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5641 return WINED3D_OK;
5643 #endif
5645 /* Reject invalid texture units */
5646 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
5647 WARN("Attempt to access invalid texture rejected\n");
5648 return WINED3DERR_INVALIDCALL;
5651 if(pTexture != NULL) {
5652 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5654 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5655 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5656 return WINED3DERR_INVALIDCALL;
5660 oldTexture = This->updateStateBlock->textures[Stage];
5661 TRACE("GL_LIMITS %d\n",GL_LIMITS(textures));
5662 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5664 This->updateStateBlock->set.textures[Stage] = TRUE;
5665 This->updateStateBlock->changed.textures[Stage] = TRUE;
5666 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5667 This->updateStateBlock->textures[Stage] = pTexture;
5669 /* Handle recording of state blocks */
5670 if (This->isRecordingState) {
5671 TRACE("Recording... not performing anything\n");
5672 return WINED3D_OK;
5675 /** NOTE: MSDN says that setTexture increases the reference count,
5676 * and the the application nust set the texture back to null (or have a leaky application),
5677 * This means we should pass the refcount up to the parent
5678 *******************************/
5679 if (NULL != This->updateStateBlock->textures[Stage]) {
5680 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5683 if (NULL != oldTexture) {
5684 IWineD3DBaseTexture_Release(oldTexture);
5687 /* Reset color keying */
5688 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5689 BOOL enable_ckey = FALSE;
5691 if(pTexture) {
5692 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5693 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5696 if(enable_ckey) {
5697 glAlphaFunc(GL_NOTEQUAL, 0.0);
5698 checkGLcall("glAlphaFunc");
5702 return WINED3D_OK;
5705 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5709 /* Reject invalid texture units */
5710 if (Stage >= GL_LIMITS(textures)) {
5711 TRACE("Attempt to access invalid texture rejected\n");
5712 return WINED3DERR_INVALIDCALL;
5714 *ppTexture=This->updateStateBlock->textures[Stage];
5715 if (*ppTexture)
5716 IWineD3DBaseTexture_AddRef(*ppTexture);
5717 else
5718 return WINED3DERR_INVALIDCALL;
5719 return WINED3D_OK;
5722 /*****
5723 * Get Back Buffer
5724 *****/
5725 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5726 IWineD3DSurface **ppBackBuffer) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 IWineD3DSwapChain *swapChain;
5729 HRESULT hr;
5731 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5733 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5734 if (hr == WINED3D_OK) {
5735 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5736 IWineD3DSwapChain_Release(swapChain);
5737 } else {
5738 *ppBackBuffer = NULL;
5740 return hr;
5743 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 WARN("(%p) : stub, calling idirect3d for now\n", This);
5746 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5749 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5751 IWineD3DSwapChain *swapChain;
5752 HRESULT hr;
5754 if(iSwapChain > 0) {
5755 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5756 if (hr == WINED3D_OK) {
5757 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5758 IWineD3DSwapChain_Release(swapChain);
5759 } else {
5760 FIXME("(%p) Error getting display mode\n", This);
5762 } else {
5763 /* Don't read the real display mode,
5764 but return the stored mode instead. X11 can't change the color
5765 depth, and some apps are pretty angry if they SetDisplayMode from
5766 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5768 Also don't relay to the swapchain because with ddraw it's possible
5769 that there isn't a swapchain at all */
5770 pMode->Width = This->ddraw_width;
5771 pMode->Height = This->ddraw_height;
5772 pMode->Format = This->ddraw_format;
5773 pMode->RefreshRate = 0;
5774 hr = WINED3D_OK;
5777 return hr;
5780 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 TRACE("(%p)->(%p)\n", This, hWnd);
5784 This->ddraw_window = hWnd;
5785 return WINED3D_OK;
5788 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5790 TRACE("(%p)->(%p)\n", This, hWnd);
5792 *hWnd = This->ddraw_window;
5793 return WINED3D_OK;
5796 /*****
5797 * Stateblock related functions
5798 *****/
5800 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 IWineD3DStateBlockImpl *object;
5803 TRACE("(%p)", This);
5805 if (This->isRecordingState) {
5806 return WINED3DERR_INVALIDCALL;
5809 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5810 if (NULL == object ) {
5811 FIXME("(%p)Error allocating memory for stateblock\n", This);
5812 return E_OUTOFMEMORY;
5814 TRACE("(%p) creted object %p\n", This, object);
5815 object->wineD3DDevice= This;
5816 /** FIXME: object->parent = parent; **/
5817 object->parent = NULL;
5818 object->blockType = WINED3DSBT_ALL;
5819 object->ref = 1;
5820 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5822 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5823 This->updateStateBlock = object;
5824 This->isRecordingState = TRUE;
5826 TRACE("(%p) recording stateblock %p\n",This , object);
5827 return WINED3D_OK;
5830 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5833 if (!This->isRecordingState) {
5834 FIXME("(%p) not recording! returning error\n", This);
5835 *ppStateBlock = NULL;
5836 return WINED3DERR_INVALIDCALL;
5839 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5840 This->isRecordingState = FALSE;
5841 This->updateStateBlock = This->stateBlock;
5842 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5843 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5844 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5845 return WINED3D_OK;
5848 /*****
5849 * Scene related functions
5850 *****/
5851 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5852 /* At the moment we have no need for any functionality at the beginning
5853 of a scene */
5854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5855 TRACE("(%p) : stub\n", This);
5856 return WINED3D_OK;
5859 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5861 TRACE("(%p)\n", This);
5862 ENTER_GL();
5863 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5864 glFlush();
5865 checkGLcall("glFlush");
5867 TRACE("End Scene\n");
5868 if(This->renderTarget != NULL) {
5870 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5871 IUnknown *targetContainer = NULL;
5872 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5873 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5874 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5875 /** always dirtify for now. we must find a better way to see that surface have been modified
5876 (Modifications should will only occur via draw-primitive, but we do need better locking
5877 switching to render-to-texture should remove the overhead though.
5879 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5880 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5881 IWineD3DSurface_PreLoad(This->renderTarget);
5882 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5883 IUnknown_Release(targetContainer);
5886 This->sceneEnded = TRUE;
5887 LEAVE_GL();
5888 return WINED3D_OK;
5891 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5892 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5893 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5895 IWineD3DSwapChain *swapChain = NULL;
5896 int i;
5897 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5899 TRACE("(%p) Presenting the frame\n", This);
5901 for(i = 0 ; i < swapchains ; i ++) {
5903 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5904 TRACE("presentinng chain %d, %p\n", i, swapChain);
5905 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5906 IWineD3DSwapChain_Release(swapChain);
5909 return WINED3D_OK;
5912 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5913 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5916 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5917 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5918 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5919 GLbitfield glMask = 0;
5920 GLboolean old_ztest;
5921 GLfloat old_z_clear_value;
5922 GLint old_stencil_clear_value;
5923 GLfloat old_color_clear_value[4];
5924 unsigned int i;
5925 CONST D3DRECT* curRect;
5927 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5928 Count, pRects, Flags, Z, Stencil);
5930 ENTER_GL();
5932 glEnable(GL_SCISSOR_TEST);
5933 checkGLcall("glEnable GL_SCISSOR_TEST");
5935 if (Count > 0 && pRects) {
5936 curRect = pRects;
5937 } else {
5938 curRect = NULL;
5941 /* Only set the values up once, as they are not changing */
5942 if (Flags & D3DCLEAR_STENCIL) {
5943 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5944 glClearStencil(Stencil);
5945 checkGLcall("glClearStencil");
5946 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5947 glStencilMask(0xFFFFFFFF);
5950 if (Flags & D3DCLEAR_ZBUFFER) {
5951 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5952 glDepthMask(GL_TRUE);
5953 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5954 glClearDepth(Z);
5955 checkGLcall("glClearDepth");
5956 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5959 if (Flags & D3DCLEAR_TARGET) {
5960 TRACE("Clearing screen with glClear to color %lx\n", Color);
5961 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5962 glClearColor(D3DCOLOR_R(Color),
5963 D3DCOLOR_G(Color),
5964 D3DCOLOR_B(Color),
5965 D3DCOLOR_A(Color));
5966 checkGLcall("glClearColor");
5968 /* Clear ALL colors! */
5969 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5970 glMask = glMask | GL_COLOR_BUFFER_BIT;
5973 /* Now process each rect in turn */
5974 for (i = 0; i < Count || i == 0; i++) {
5976 if (curRect) {
5977 /* Note gl uses lower left, width/height */
5978 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5979 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5980 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5981 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5982 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5983 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5984 checkGLcall("glScissor");
5985 } else {
5986 glScissor(This->stateBlock->viewport.X,
5987 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5988 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5989 This->stateBlock->viewport.Width,
5990 This->stateBlock->viewport.Height);
5991 checkGLcall("glScissor");
5994 /* Clear the selected rectangle (or full screen) */
5995 glClear(glMask);
5996 checkGLcall("glClear");
5998 /* Step to the next rectangle */
5999 if (curRect) curRect = curRect + sizeof(D3DRECT);
6002 /* Restore the old values (why..?) */
6003 if (Flags & D3DCLEAR_STENCIL) {
6004 glClearStencil(old_stencil_clear_value);
6005 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6007 if (Flags & D3DCLEAR_ZBUFFER) {
6008 glDepthMask(old_ztest);
6009 glClearDepth(old_z_clear_value);
6011 if (Flags & D3DCLEAR_TARGET) {
6012 glClearColor(old_color_clear_value[0],
6013 old_color_clear_value[1],
6014 old_color_clear_value[2],
6015 old_color_clear_value[3]);
6016 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6017 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6018 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6019 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6022 glDisable(GL_SCISSOR_TEST);
6023 checkGLcall("glDisable");
6024 LEAVE_GL();
6026 return WINED3D_OK;
6029 /*****
6030 * Drawing functions
6031 *****/
6032 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6033 UINT PrimitiveCount) {
6035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6036 This->stateBlock->streamIsUP = FALSE;
6038 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6039 debug_d3dprimitivetype(PrimitiveType),
6040 StartVertex, PrimitiveCount);
6041 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6042 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6045 return WINED3D_OK;
6048 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6049 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6050 D3DPRIMITIVETYPE PrimitiveType,
6051 INT baseVIndex, UINT minIndex,
6052 UINT NumVertices, UINT startIndex, UINT primCount) {
6054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6055 UINT idxStride = 2;
6056 IWineD3DIndexBuffer *pIB;
6057 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6059 pIB = This->stateBlock->pIndexData;
6060 This->stateBlock->streamIsUP = FALSE;
6062 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6063 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6064 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6066 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6067 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6068 idxStride = 2;
6069 } else {
6070 idxStride = 4;
6073 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6074 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6076 return WINED3D_OK;
6079 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6080 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6081 UINT VertexStreamZeroStride) {
6082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6085 debug_d3dprimitivetype(PrimitiveType),
6086 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6088 /* release the stream source */
6089 if (This->stateBlock->streamSource[0] != NULL) {
6090 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6093 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6094 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6095 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6096 This->stateBlock->streamIsUP = TRUE;
6098 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6099 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6101 /* MSDN specifies stream zero settings must be set to NULL */
6102 This->stateBlock->streamStride[0] = 0;
6103 This->stateBlock->streamSource[0] = NULL;
6105 /*stream zero settings set to null at end, as per the msdn */
6106 return WINED3D_OK;
6109 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6110 UINT MinVertexIndex, UINT NumVertices,
6111 UINT PrimitiveCount, CONST void* pIndexData,
6112 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6113 UINT VertexStreamZeroStride) {
6114 int idxStride;
6115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6117 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6118 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6119 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6120 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6122 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6123 idxStride = 2;
6124 } else {
6125 idxStride = 4;
6128 /* release the stream and index data */
6129 if (This->stateBlock->streamSource[0] != NULL) {
6130 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6132 if (This->stateBlock->pIndexData) {
6133 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6136 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6137 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6138 This->stateBlock->streamIsUP = TRUE;
6139 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6141 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6143 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6144 This->stateBlock->streamSource[0] = NULL;
6145 This->stateBlock->streamStride[0] = 0;
6146 This->stateBlock->pIndexData = NULL;
6148 return WINED3D_OK;
6151 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6153 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6154 return WINED3D_OK;
6156 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6157 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6159 HRESULT hr = WINED3D_OK;
6160 WINED3DRESOURCETYPE sourceType;
6161 WINED3DRESOURCETYPE destinationType;
6162 int i ,levels;
6164 /* TODO: think about moving the code into IWineD3DBaseTexture */
6166 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6168 /* verify that the source and destination textures aren't NULL */
6169 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6170 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6171 This, pSourceTexture, pDestinationTexture);
6172 hr = WINED3DERR_INVALIDCALL;
6175 if (pSourceTexture == pDestinationTexture) {
6176 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6177 This, pSourceTexture, pDestinationTexture);
6178 hr = WINED3DERR_INVALIDCALL;
6180 /* Verify that the source and destination textures are the same type */
6181 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6182 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6184 if (sourceType != destinationType) {
6185 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6186 This);
6187 hr = WINED3DERR_INVALIDCALL;
6190 /* check that both textures have the identical numbers of levels */
6191 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6192 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6193 hr = WINED3DERR_INVALIDCALL;
6196 if (WINED3D_OK == hr) {
6198 /* Make sure that the destination texture is loaded */
6199 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6201 /* Update every surface level of the texture */
6202 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6204 switch (sourceType) {
6205 case WINED3DRTYPE_TEXTURE:
6207 IWineD3DSurface *srcSurface;
6208 IWineD3DSurface *destSurface;
6210 for (i = 0 ; i < levels ; ++i) {
6211 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6212 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6213 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6214 IWineD3DSurface_Release(srcSurface);
6215 IWineD3DSurface_Release(destSurface);
6216 if (WINED3D_OK != hr) {
6217 WARN("(%p) : Call to update surface failed\n", This);
6218 return hr;
6222 break;
6223 case WINED3DRTYPE_CUBETEXTURE:
6225 IWineD3DSurface *srcSurface;
6226 IWineD3DSurface *destSurface;
6227 WINED3DCUBEMAP_FACES faceType;
6229 for (i = 0 ; i < levels ; ++i) {
6230 /* Update each cube face */
6231 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6232 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6233 if (WINED3D_OK != hr) {
6234 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6235 } else {
6236 TRACE("Got srcSurface %p\n", srcSurface);
6238 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6239 if (WINED3D_OK != hr) {
6240 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6241 } else {
6242 TRACE("Got desrSurface %p\n", destSurface);
6244 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6245 IWineD3DSurface_Release(srcSurface);
6246 IWineD3DSurface_Release(destSurface);
6247 if (WINED3D_OK != hr) {
6248 WARN("(%p) : Call to update surface failed\n", This);
6249 return hr;
6254 break;
6255 #if 0 /* TODO: Add support for volume textures */
6256 case WINED3DRTYPE_VOLUMETEXTURE:
6258 IWineD3DVolume srcVolume = NULL;
6259 IWineD3DSurface destVolume = NULL;
6261 for (i = 0 ; i < levels ; ++i) {
6262 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6263 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6264 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6265 IWineD3DVolume_Release(srcSurface);
6266 IWineD3DVolume_Release(destSurface);
6267 if (WINED3D_OK != hr) {
6268 WARN("(%p) : Call to update volume failed\n", This);
6269 return hr;
6273 break;
6274 #endif
6275 default:
6276 FIXME("(%p) : Unsupported source and destination type\n", This);
6277 hr = WINED3DERR_INVALIDCALL;
6281 return hr;
6284 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6285 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6286 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6289 TRACE("(%p) : stub\n", This);
6290 return WINED3D_OK;
6292 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6294 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6295 * NOTE It may be best to move the code into surface to occomplish this
6296 ****************************************/
6298 WINED3DSURFACE_DESC surfaceDesc;
6299 unsigned int surfaceWidth, surfaceHeight;
6300 glDescriptor *targetGlDescription = NULL;
6301 glDescriptor *surfaceGlDescription = NULL;
6302 IWineD3DSwapChainImpl *container = NULL;
6304 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6305 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6306 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6308 surfaceDesc.Width = &surfaceWidth;
6309 surfaceDesc.Height = &surfaceHeight;
6310 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6311 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6313 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6314 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6315 ENTER_GL();
6316 /* TODO: opengl Context switching for swapchains etc... */
6317 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6318 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6319 glReadBuffer(GL_BACK);
6320 vcheckGLcall("glReadBuffer(GL_BACK)");
6321 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6322 glReadBuffer(GL_FRONT);
6323 vcheckGLcall("glReadBuffer(GL_FRONT)");
6324 } else if (pRenderTarget == This->depthStencilBuffer) {
6325 FIXME("Reading of depthstencil not yet supported\n");
6328 glReadPixels(surfaceGlDescription->target,
6329 surfaceGlDescription->level,
6330 surfaceWidth,
6331 surfaceHeight,
6332 surfaceGlDescription->glFormat,
6333 surfaceGlDescription->glType,
6334 (void *)IWineD3DSurface_GetData(pSurface));
6335 vcheckGLcall("glReadPixels(...)");
6336 if(NULL != container ){
6337 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6339 } else {
6340 IWineD3DBaseTexture *container;
6341 GLenum textureDimensions = GL_TEXTURE_2D;
6343 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6344 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6345 IWineD3DBaseTexture_Release(container);
6347 /* TODO: 2D -> Cube surface coppies etc.. */
6348 if (surfaceGlDescription->target != textureDimensions) {
6349 FIXME("(%p) : Texture dimension mismatch\n", This);
6351 glEnable(textureDimensions);
6352 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6353 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6354 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6355 vcheckGLcall("glBindTexture");
6356 glGetTexImage(surfaceGlDescription->target,
6357 surfaceGlDescription->level,
6358 surfaceGlDescription->glFormat,
6359 surfaceGlDescription->glType,
6360 (void *)IWineD3DSurface_GetData(pSurface));
6361 glDisable(textureDimensions);
6362 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6365 LEAVE_GL();
6366 return WINED3D_OK;
6369 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6370 IWineD3DSwapChain *swapChain;
6371 HRESULT hr;
6372 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6373 if(hr == WINED3D_OK) {
6374 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6375 IWineD3DSwapChain_Release(swapChain);
6377 return hr;
6380 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6382 /* return a sensible default */
6383 *pNumPasses = 1;
6384 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6385 FIXME("(%p) : stub\n", This);
6386 return WINED3D_OK;
6389 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6391 int j;
6392 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6393 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6394 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6395 return WINED3DERR_INVALIDCALL;
6397 for (j = 0; j < 256; ++j) {
6398 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6399 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6400 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6401 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6403 TRACE("(%p) : returning\n", This);
6404 return WINED3D_OK;
6407 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6409 int j;
6410 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6411 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6412 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6413 return WINED3DERR_INVALIDCALL;
6415 for (j = 0; j < 256; ++j) {
6416 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6417 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6418 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6419 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6421 TRACE("(%p) : returning\n", This);
6422 return WINED3D_OK;
6425 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6427 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6428 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6429 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6430 return WINED3DERR_INVALIDCALL;
6432 /*TODO: stateblocks */
6433 This->currentPalette = PaletteNumber;
6434 TRACE("(%p) : returning\n", This);
6435 return WINED3D_OK;
6438 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6440 if (PaletteNumber == NULL) {
6441 WARN("(%p) : returning Invalid Call\n", This);
6442 return WINED3DERR_INVALIDCALL;
6444 /*TODO: stateblocks */
6445 *PaletteNumber = This->currentPalette;
6446 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6447 return WINED3D_OK;
6450 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6452 static BOOL showFixmes = TRUE;
6453 if (showFixmes) {
6454 FIXME("(%p) : stub\n", This);
6455 showFixmes = FALSE;
6458 This->softwareVertexProcessing = bSoftware;
6459 return WINED3D_OK;
6463 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6465 static BOOL showFixmes = TRUE;
6466 if (showFixmes) {
6467 FIXME("(%p) : stub\n", This);
6468 showFixmes = FALSE;
6470 return This->softwareVertexProcessing;
6474 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6476 IWineD3DSwapChain *swapChain;
6477 HRESULT hr;
6479 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6481 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6482 if(hr == WINED3D_OK){
6483 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6484 IWineD3DSwapChain_Release(swapChain);
6485 }else{
6486 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6488 return hr;
6492 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6494 static BOOL showfixmes = TRUE;
6495 if(nSegments != 0.0f) {
6496 if( showfixmes) {
6497 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6498 showfixmes = FALSE;
6501 return WINED3D_OK;
6504 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6506 static BOOL showfixmes = TRUE;
6507 if( showfixmes) {
6508 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6509 showfixmes = FALSE;
6511 return 0.0f;
6514 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6516 /** TODO: remove casts to IWineD3DSurfaceImpl
6517 * NOTE: move code to surface to accomplish this
6518 ****************************************/
6519 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6520 int srcWidth, srcHeight;
6521 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6522 WINED3DFORMAT destFormat, srcFormat;
6523 UINT destSize;
6524 int destLeft, destTop;
6525 WINED3DPOOL srcPool, destPool;
6526 int offset = 0;
6527 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6528 glDescriptor *glDescription = NULL;
6529 GLenum textureDimensions = GL_TEXTURE_2D;
6530 IWineD3DBaseTexture *baseTexture;
6532 WINED3DSURFACE_DESC winedesc;
6534 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6535 memset(&winedesc, 0, sizeof(winedesc));
6536 winedesc.Width = &srcSurfaceWidth;
6537 winedesc.Height = &srcSurfaceHeight;
6538 winedesc.Pool = &srcPool;
6539 winedesc.Format = &srcFormat;
6541 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6543 winedesc.Width = &destSurfaceWidth;
6544 winedesc.Height = &destSurfaceHeight;
6545 winedesc.Pool = &destPool;
6546 winedesc.Format = &destFormat;
6547 winedesc.Size = &destSize;
6549 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6551 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6552 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6553 return WINED3DERR_INVALIDCALL;
6556 if (destFormat == WINED3DFMT_UNKNOWN) {
6557 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6558 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6560 /* Get the update surface description */
6561 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6564 /* Make sure the surface is loaded and up to date */
6565 IWineD3DSurface_PreLoad(pDestinationSurface);
6567 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6569 ENTER_GL();
6571 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6572 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6573 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6574 destLeft = pDestPoint ? pDestPoint->x : 0;
6575 destTop = pDestPoint ? pDestPoint->y : 0;
6578 /* This function doesn't support compressed textures
6579 the pitch is just bytesPerPixel * width */
6580 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6581 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6582 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6583 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6585 /* TODO DXT formats */
6587 if(pSourceRect != NULL && pSourceRect->top != 0){
6588 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6590 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6591 ,This
6592 ,glDescription->level
6593 ,destLeft
6594 ,destTop
6595 ,srcWidth
6596 ,srcHeight
6597 ,glDescription->glFormat
6598 ,glDescription->glType
6599 ,IWineD3DSurface_GetData(pSourceSurface)
6602 /* Sanity check */
6603 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6605 /* need to lock the surface to get the data */
6606 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6609 /* TODO: Cube and volume support */
6610 if(rowoffset != 0){
6611 /* not a whole row so we have to do it a line at a time */
6612 int j;
6614 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6615 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6617 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6619 glTexSubImage2D(glDescription->target
6620 ,glDescription->level
6621 ,destLeft
6623 ,srcWidth
6625 ,glDescription->glFormat
6626 ,glDescription->glType
6627 ,data /* could be quicker using */
6629 data += rowoffset;
6632 } else { /* Full width, so just write out the whole texture */
6634 if (WINED3DFMT_DXT1 == destFormat ||
6635 WINED3DFMT_DXT2 == destFormat ||
6636 WINED3DFMT_DXT3 == destFormat ||
6637 WINED3DFMT_DXT4 == destFormat ||
6638 WINED3DFMT_DXT5 == destFormat) {
6639 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6640 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6641 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6642 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6643 } if (destFormat != srcFormat) {
6644 FIXME("Updating mixed format compressed texture is not curretly support\n");
6645 } else {
6646 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6647 glDescription->level,
6648 glDescription->glFormatInternal,
6649 srcWidth,
6650 srcHeight,
6652 destSize,
6653 IWineD3DSurface_GetData(pSourceSurface));
6655 } else {
6656 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6660 } else {
6661 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6663 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6664 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6665 data returned by GetData non-power2 width/height with hardware non-power2
6666 pow2Width/height are set to surface width height, repacking isn't needed so it
6667 doesn't matter which function gets called. */
6668 glTexSubImage2D(glDescription->target
6669 ,glDescription->level
6670 ,destLeft
6671 ,destTop
6672 ,srcWidth
6673 ,srcHeight
6674 ,glDescription->glFormat
6675 ,glDescription->glType
6676 ,IWineD3DSurface_GetData(pSourceSurface)
6678 } else {
6680 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6681 glTexSubImage2D(glDescription->target
6682 ,glDescription->level
6683 ,destLeft
6684 ,destTop
6685 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6686 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6687 ,glDescription->glFormat
6688 ,glDescription->glType
6689 ,IWineD3DSurface_GetData(pSourceSurface)
6695 checkGLcall("glTexSubImage2D");
6697 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6698 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6699 * surface bigger than it needs to be hmm.. */
6700 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6701 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6702 IWineD3DBaseTexture_Release(baseTexture);
6705 glDisable(textureDimensions); /* This needs to be managed better.... */
6706 LEAVE_GL();
6708 return WINED3D_OK;
6711 /* Used by DirectX 8 */
6712 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6713 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6714 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6717 HRESULT hr = WINED3D_OK;
6718 WINED3DFORMAT srcFormat, destFormat;
6719 UINT srcWidth, destWidth;
6720 UINT srcHeight, destHeight;
6721 UINT srcSize;
6722 WINED3DSURFACE_DESC winedesc;
6724 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6725 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6728 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6729 memset(&winedesc, 0, sizeof(winedesc));
6731 winedesc.Format = &srcFormat;
6732 winedesc.Width = &srcWidth;
6733 winedesc.Height = &srcHeight;
6734 winedesc.Size = &srcSize;
6735 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6737 winedesc.Format = &destFormat;
6738 winedesc.Width = &destWidth;
6739 winedesc.Height = &destHeight;
6740 winedesc.Size = NULL;
6741 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6743 /* Check that the source and destination formats match */
6744 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6745 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6746 return WINED3DERR_INVALIDCALL;
6747 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6748 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6749 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6750 destFormat = srcFormat;
6753 /* Quick if complete copy ... */
6754 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6756 if (srcWidth == destWidth && srcHeight == destHeight) {
6757 WINED3DLOCKED_RECT lrSrc;
6758 WINED3DLOCKED_RECT lrDst;
6759 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6760 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6761 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6763 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6765 IWineD3DSurface_UnlockRect(pSourceSurface);
6766 IWineD3DSurface_UnlockRect(pDestinationSurface);
6767 TRACE("Unlocked src and dst\n");
6769 } else {
6771 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6772 hr = WINED3DERR_INVALIDCALL;
6775 } else {
6777 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6779 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6780 unsigned int i;
6782 /* Copy rect by rect */
6783 for (i = 0; i < cRects; ++i) {
6784 CONST RECT* r = &pSourceRectsArray[i];
6785 CONST POINT* p = &pDestPointsArray[i];
6786 int copyperline;
6787 int j;
6788 WINED3DLOCKED_RECT lrSrc;
6789 WINED3DLOCKED_RECT lrDst;
6790 RECT dest_rect;
6792 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6793 if (srcFormat == WINED3DFMT_DXT1) {
6794 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6795 } else {
6796 copyperline = ((r->right - r->left) * bytesPerPixel);
6799 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6800 dest_rect.left = p->x;
6801 dest_rect.top = p->y;
6802 dest_rect.right = p->x + (r->right - r->left);
6803 dest_rect.bottom= p->y + (r->bottom - r->top);
6804 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6805 TRACE("Locked src and dst\n");
6807 /* Find where to start */
6808 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6809 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6811 IWineD3DSurface_UnlockRect(pSourceSurface);
6812 IWineD3DSurface_UnlockRect(pDestinationSurface);
6813 TRACE("Unlocked src and dst\n");
6815 } else {
6816 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6817 hr = WINED3DERR_INVALIDCALL;
6821 return hr;
6824 /* Implementation details at http://developer.nvidia.com/attach/6494
6826 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6827 hmm.. no longer supported use
6828 OpenGL evaluators or tessellate surfaces within your application.
6831 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6832 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6834 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6835 FIXME("(%p) : Stub\n", This);
6836 return WINED3D_OK;
6840 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6841 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6843 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6844 FIXME("(%p) : Stub\n", This);
6845 return WINED3D_OK;
6848 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6850 TRACE("(%p) Handle(%d)\n", This, Handle);
6851 FIXME("(%p) : Stub\n", This);
6852 return WINED3D_OK;
6855 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6856 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6857 fill a surface with a block of color! */
6858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6859 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6860 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6861 IWineD3DSwapChainImpl *container = NULL;
6862 BOOL isRenderTarget = FALSE;
6863 unsigned int width, height;
6864 unsigned int top, left;
6865 unsigned int u, v;
6866 DWORD *data;
6867 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6869 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6870 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6871 return WINED3DERR_INVALIDCALL;
6874 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6875 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6876 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6877 /* TODO: make sure we set everything back to the way it was, and context management!
6878 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6879 vcheckGLcall("glIntegerv");
6880 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6881 vcheckGLcall("glIntegerv");
6883 TRACE("Color fill to render targets may cause some graphics issues\n");
6884 if (pSurface == container->frontBuffer) {
6885 glDrawBuffer(GL_FRONT);
6886 } else {
6887 glDrawBuffer(GL_BACK);
6889 } else {
6890 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6891 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6892 } else {
6893 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6895 if (container != NULL) {
6896 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6898 /* we can use GL_STENCIL_INDEX etc...*/
6899 return WINED3D_OK;
6901 if (container != NULL) {
6902 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6904 isRenderTarget = TRUE;
6906 /* TODO: drawing to GL_FRONT and GL_BACK */
6907 /* TODO: see if things can be speeded up by using the correct
6908 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6909 if (pRect == NULL) {
6910 top = 0;
6911 left = 0;
6912 width = surface->currentDesc.Width;
6913 height = surface->currentDesc.Height;
6914 } else {
6915 left = pRect->x1;
6916 top = pRect->y1;
6917 width = pRect->x2 - left;
6918 height = pRect->y2 - top;
6921 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6922 /* Create a 'line' of color color, in the correct format for the surface */
6923 for (u = 0 ; u < width ; u ++) {
6924 data[u] = color;
6927 ENTER_GL();
6928 if (isRenderTarget == FALSE) {
6929 glDescriptor *glDesc;
6930 IWineD3DSurface_PreLoad(pSurface);
6932 /* draw a block of the coloured line on the sufrace */
6933 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6934 for (v = 0 ; v< height;v++) {
6935 glTexSubImage2D(glDesc->target
6936 ,glDesc->level /* level */
6937 ,left
6938 ,top + v
6939 ,width
6940 ,1 /* height */
6941 ,GL_RGBA
6942 ,GL_UNSIGNED_BYTE
6943 ,data
6946 checkGLcall("glTexSubImage2D");
6947 /* clean up */
6948 glDisable(glDesc->target);
6949 } else {
6950 /** FIXME: Using GLClear may be faster **/
6951 glRasterPos2i(left, top);
6952 glPixelZoom((float)width ,(float)height);
6953 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6954 checkGLcall("glDrawPixels");
6956 HeapFree(GetProcessHeap(), 0, data);
6957 LEAVE_GL();
6958 return WINED3D_OK;
6962 /* rendertarget and deptth stencil functions */
6963 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6966 /* FIXME: Implelent RenderTargetIndex >0 */
6967 if(RenderTargetIndex > 0)
6968 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6970 *ppRenderTarget = This->renderTarget;
6971 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6972 /* Note inc ref on returned surface */
6973 if(*ppRenderTarget != NULL)
6974 IWineD3DSurface_AddRef(*ppRenderTarget);
6975 return WINED3D_OK;
6978 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6980 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6981 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6982 IWineD3DSwapChainImpl *Swapchain;
6983 HRESULT hr;
6985 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6987 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6988 if(hr != WINED3D_OK) {
6989 ERR("Can't get the swapchain\n");
6990 return hr;
6993 /* Make sure to release the swapchain */
6994 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6996 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6997 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6998 return WINED3DERR_INVALIDCALL;
7000 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7001 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7002 return WINED3DERR_INVALIDCALL;
7005 if(Swapchain->frontBuffer != Front) {
7006 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7008 if(Swapchain->frontBuffer)
7009 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7010 Swapchain->frontBuffer = Front;
7012 if(Swapchain->frontBuffer) {
7013 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7017 if(Back && !Swapchain->backBuffer) {
7018 /* We need memory for the back buffer array - only one back buffer this way */
7019 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7020 if(!Swapchain->backBuffer) {
7021 ERR("Out of memory\n");
7022 return E_OUTOFMEMORY;
7026 if(Swapchain->backBuffer[0] != Back) {
7027 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7028 ENTER_GL();
7029 if(!Swapchain->backBuffer[0]) {
7030 /* GL was told to draw to the front buffer at creation,
7031 * undo that
7033 glDrawBuffer(GL_BACK);
7034 checkGLcall("glDrawBuffer(GL_BACK)");
7035 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7036 Swapchain->presentParms.BackBufferCount = 1;
7037 } else if (!Back) {
7038 /* That makes problems - disable for now */
7039 /* glDrawBuffer(GL_FRONT); */
7040 checkGLcall("glDrawBuffer(GL_FRONT)");
7041 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7042 Swapchain->presentParms.BackBufferCount = 0;
7044 LEAVE_GL();
7046 if(Swapchain->backBuffer[0])
7047 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7048 Swapchain->backBuffer[0] = Back;
7050 if(Swapchain->backBuffer[0]) {
7051 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7052 } else {
7053 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7058 return WINED3D_OK;
7061 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7063 *ppZStencilSurface = This->depthStencilBuffer;
7064 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7066 if(*ppZStencilSurface != NULL) {
7067 /* Note inc ref on returned surface */
7068 IWineD3DSurface_AddRef(*ppZStencilSurface);
7070 return WINED3D_OK;
7073 /* internal static helper functions */
7074 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7075 IWineD3DSurface *RenderSurface);
7077 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7079 HRESULT hr = WINED3D_OK;
7080 WINED3DVIEWPORT viewport;
7082 TRACE("(%p) Swapping rendertarget\n",This);
7083 if (RenderTargetIndex > 0) {
7084 FIXME("(%p) Render targets other than the first are not supported\n",This);
7085 RenderTargetIndex = 0;
7088 /* MSDN says that null disables the render target
7089 but a device must always be associated with a render target
7090 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7092 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7093 for more details
7095 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7096 FIXME("Trying to set render target 0 to NULL\n");
7097 return WINED3DERR_INVALIDCALL;
7099 /* TODO: replace Impl* usage with interface usage */
7100 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7101 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);
7102 return WINED3DERR_INVALIDCALL;
7104 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7105 * builds, but I think wine counts as a 'debug' build for now.
7106 ******************************/
7107 /* If we are trying to set what we already have, don't bother */
7108 if (pRenderTarget == This->renderTarget) {
7109 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7110 } else {
7111 /* Otherwise, set the render target up */
7113 if (FALSE == This->sceneEnded) {
7114 IWineD3DDevice_EndScene(iface);
7116 TRACE("clearing renderer\n");
7117 /* IWineD3DDeviceImpl_CleanRender(iface); */
7118 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7119 depending on the renter target implementation being used.
7120 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7121 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7122 stencil buffer and incure an extra memory overhead */
7123 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7126 if (SUCCEEDED(hr)) {
7127 /* Finally, reset the viewport as the MSDN states. */
7128 /* TODO: Replace impl usage */
7129 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7130 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7131 viewport.X = 0;
7132 viewport.Y = 0;
7133 viewport.MaxZ = 1.0f;
7134 viewport.MinZ = 0.0f;
7135 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7136 } else {
7137 FIXME("Unknown error setting the render target\n");
7139 This->sceneEnded = FALSE;
7140 return hr;
7143 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7145 HRESULT hr = WINED3D_OK;
7146 IWineD3DSurface *tmp;
7148 TRACE("(%p) Swapping z-buffer\n",This);
7150 if (pNewZStencil == This->stencilBufferTarget) {
7151 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7152 } else {
7153 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7154 * depending on the renter target implementation being used.
7155 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7156 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7157 * stencil buffer and incure an extra memory overhead
7158 ******************************************************/
7161 tmp = This->stencilBufferTarget;
7162 This->stencilBufferTarget = pNewZStencil;
7163 /* should we be calling the parent or the wined3d surface? */
7164 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7165 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7166 hr = WINED3D_OK;
7167 /** TODO: glEnable/glDisable on depth/stencil depending on
7168 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7169 **********************************************************/
7172 return hr;
7176 #ifdef GL_VERSION_1_3
7177 /* Internal functions not in DirectX */
7178 /** TODO: move this off to the opengl context manager
7179 *(the swapchain doesn't need to know anything about offscreen rendering!)
7180 ****************************************************/
7182 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7186 TRACE("(%p), %p\n", This, swapchain);
7188 if (swapchain->win != swapchain->drawable) {
7189 /* Set everything back the way it ws */
7190 swapchain->render_ctx = swapchain->glCtx;
7191 swapchain->drawable = swapchain->win;
7193 return WINED3D_OK;
7196 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7197 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7199 int i;
7200 unsigned int width;
7201 unsigned int height;
7202 WINED3DFORMAT format;
7203 WINED3DSURFACE_DESC surfaceDesc;
7204 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7205 surfaceDesc.Width = &width;
7206 surfaceDesc.Height = &height;
7207 surfaceDesc.Format = &format;
7208 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7209 *context = NULL;
7210 /* I need a get width/height function (and should do something with the format) */
7211 for (i = 0; i < CONTEXT_CACHE; ++i) {
7212 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7213 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7214 the pSurface can be set to 0 allowing it to be reused from cache **/
7215 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7216 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7217 *context = &This->contextCache[i];
7218 break;
7220 if (This->contextCache[i].Width == 0) {
7221 This->contextCache[i].pSurface = pSurface;
7222 This->contextCache[i].Width = width;
7223 This->contextCache[i].Height = height;
7224 *context = &This->contextCache[i];
7225 break;
7228 if (i == CONTEXT_CACHE) {
7229 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7230 glContext *dropContext = 0;
7231 for (i = 0; i < CONTEXT_CACHE; i++) {
7232 if (This->contextCache[i].usedcount < minUsage) {
7233 dropContext = &This->contextCache[i];
7234 minUsage = This->contextCache[i].usedcount;
7237 /* clean up the context (this doesn't work for ATI at the moment */
7238 #if 0
7239 glXDestroyContext(swapchain->display, dropContext->context);
7240 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7241 #endif
7242 FIXME("Leak\n");
7243 dropContext->Width = 0;
7244 dropContext->pSurface = pSurface;
7245 *context = dropContext;
7246 } else {
7247 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7248 for (i = 0; i < CONTEXT_CACHE; i++) {
7249 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7253 if (*context != NULL)
7254 return WINED3D_OK;
7255 else
7256 return E_OUTOFMEMORY;
7258 #endif
7260 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7261 * the functionality needs splitting up so that we don't do more than we should do.
7262 * this only seems to impact performance a little.
7263 ******************************/
7264 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7265 IWineD3DSurface *RenderSurface) {
7266 HRESULT ret = WINED3DERR_INVALIDCALL;
7269 * Currently only active for GLX >= 1.3
7270 * for others versions we'll have to use GLXPixmaps
7272 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7273 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7274 * so only check OpenGL version
7275 * ..........................
7276 * I don't believe that it is a problem with NVidia headers,
7277 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7278 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7279 * ATI Note:
7280 * Your application will report GLX version 1.2 on glXQueryVersion.
7281 * However, it is safe to call the GLX 1.3 functions as described below.
7283 #if defined(GL_VERSION_1_3)
7285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7286 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7287 IWineD3DSurface *tmp;
7288 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7289 GLXFBConfig* cfgs = NULL;
7290 int nCfgs = 0;
7291 int attribs[256];
7292 int nAttribs = 0;
7293 IWineD3DSwapChain *currentSwapchain;
7294 IWineD3DSwapChainImpl *swapchain;
7295 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7296 * but switch them off if the StencilSurface is set to NULL
7297 ** *********************************************************/
7298 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7299 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7301 /**TODO:
7302 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7303 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7306 #define PUSH1(att) attribs[nAttribs++] = (att);
7307 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7309 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7311 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7312 IWineD3DSwapChainImpl *impSwapChain;
7313 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7314 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7315 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7318 ENTER_GL();
7320 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7321 PUSH2(GLX_X_RENDERABLE, TRUE);
7322 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7323 TRACE("calling makeglcfg\n");
7324 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7325 PUSH1(None);
7327 TRACE("calling chooseFGConfig\n");
7328 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7329 attribs, &nCfgs);
7331 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7332 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7333 why we failed and only show this message once! */
7334 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"); /**/
7335 nAttribs = 0;
7336 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7337 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7338 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7339 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7340 TRACE("calling makeglcfg\n");
7341 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7342 PUSH1(None);
7343 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7344 attribs, &nCfgs);
7347 if (NULL != cfgs) {
7348 #ifdef EXTRA_TRACES
7349 int i;
7350 for (i = 0; i < nCfgs; ++i) {
7351 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7352 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7353 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7356 if (NULL != This->renderTarget) {
7357 glFlush();
7358 vcheckGLcall("glFlush");
7359 /** This is only useful if the old render target was a swapchain,
7360 * we need to supercede this with a function that displays
7361 * the current buffer on the screen. This is easy to do in glx1.3 but
7362 * we need to do copy-write pixels in glx 1.2.
7363 ************************************************/
7364 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7366 printf("Hit Enter to get next frame ...\n");
7367 getchar();
7369 #endif
7372 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7373 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7374 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7378 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7379 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7380 **********************************************************************/
7381 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7382 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7383 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7384 TRACE("making swapchain active\n");
7385 if (RenderSurface != This->renderTarget) {
7386 BOOL backbuf = FALSE;
7387 int i;
7389 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7390 if(RenderSurface == swapchain->backBuffer[i]) {
7391 backbuf = TRUE;
7392 break;
7396 if (backbuf) {
7397 } else {
7398 /* This could be flagged so that some operations work directly with the front buffer */
7399 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7401 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7402 == False) {
7403 TRACE("Error in setting current context: context %p drawable %ld !\n",
7404 impSwapChain->glCtx, impSwapChain->win);
7407 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7409 checkGLcall("glXMakeContextCurrent");
7411 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7413 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7415 /** ********************************************************************
7416 * This is a quickly hacked out implementation of offscreen textures.
7417 * It will work in most cases but there may be problems if the client
7418 * modifies the texture directly, or expects the contents of the rendertarget
7419 * to be persistent.
7421 * There are some real speed vs compatibility issues here:
7422 * we should really use a new context for every texture, but that eats ram.
7423 * we should also be restoring the texture to the pbuffer but that eats CPU
7424 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7425 * but if this means reusing the display backbuffer then we need to make sure that
7426 * states are correctly preserved.
7427 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7428 * and gain a good performance increase at the cost of compatibility.
7429 * I would suggest that, when this is the case, a user configurable flag be made
7430 * available, allowing the user to choose the best emulated experience for them.
7431 *********************************************************************/
7433 XVisualInfo *visinfo;
7434 glContext *newContext;
7436 /* Here were using a shared context model */
7437 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7438 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7441 /* If the context doesn't exist then create a new one */
7442 /* TODO: This should really be part of findGlContext */
7443 if (NULL == newContext->context) {
7445 TRACE("making new buffer\n");
7446 nAttribs = 0;
7447 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7448 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7449 PUSH1(None);
7451 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7453 /** ****************************************
7454 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7455 *they note:
7456 * In future releases, we may provide the calls glXCreateNewContext,
7457 * glXQueryDrawable and glXMakeContextCurrent.
7458 * so until then we have to use glXGetVisualFromFBConfig &co..
7459 ********************************************/
7462 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7463 if (!visinfo) {
7464 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7465 } else {
7466 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7467 XFree(visinfo);
7470 if (NULL == newContext || NULL == newContext->context) {
7471 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7472 } else {
7473 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7474 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7475 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7478 /* Clean up the old context */
7479 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7480 /* Set the current context of the swapchain to the new context */
7481 impSwapChain->drawable = newContext->drawable;
7482 impSwapChain->render_ctx = newContext->context;
7486 #if 1 /* Apply the stateblock to the new context
7487 FIXME: This is a bit of a hack, each context should know it's own state,
7488 the directX current directX state should then be applied to the context */
7490 BOOL oldRecording;
7491 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7492 oldUpdateStateBlock = This->updateStateBlock;
7493 oldRecording= This->isRecordingState;
7494 This->isRecordingState = FALSE;
7495 This->updateStateBlock = This->stateBlock;
7496 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7498 This->isRecordingState = oldRecording;
7499 This->updateStateBlock = oldUpdateStateBlock;
7501 #endif
7504 /* clean up the current rendertargets swapchain (if it belonged to one) */
7505 if (currentSwapchain != NULL) {
7506 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7509 /* Were done with the opengl context management, setup the rendertargets */
7511 tmp = This->renderTarget;
7512 This->renderTarget = RenderSurface;
7513 IWineD3DSurface_AddRef(This->renderTarget);
7514 IWineD3DSurface_Release(tmp);
7519 DWORD value;
7520 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7521 /* Check that the container is not a swapchain member */
7523 IWineD3DSwapChain *tmpSwapChain;
7524 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7525 This->renderUpsideDown = TRUE;
7526 }else{
7527 This->renderUpsideDown = FALSE;
7528 IWineD3DSwapChain_Release(tmpSwapChain);
7530 /* Force updating the cull mode */
7531 TRACE("setting render state\n");
7532 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7533 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7535 /* Force updating projection matrix */
7536 This->last_was_rhw = FALSE;
7537 This->proj_valid = FALSE;
7540 ret = WINED3D_OK;
7542 if (cfgs != NULL) {
7543 XFree(cfgs);
7544 } else {
7545 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7546 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7549 #undef PUSH1
7550 #undef PUSH2
7551 if ( NULL != impSwapChain) {
7552 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7554 LEAVE_GL();
7556 #endif
7557 return ret;
7560 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7561 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7563 /* TODO: the use of Impl is deprecated. */
7564 /* some basic validation checks */
7565 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7567 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7569 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7570 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7571 return WINED3DERR_INVALIDCALL;
7573 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7574 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7575 return WINED3DERR_INVALIDCALL;
7577 /* TODO: make the cursor 'real' */
7579 This->xHotSpot = XHotSpot;
7580 This->yHotSpot = YHotSpot;
7582 return WINED3D_OK;
7585 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7587 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7589 This->xScreenSpace = XScreenSpace;
7590 This->yScreenSpace = YScreenSpace;
7592 return;
7596 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7598 TRACE("(%p) : visible(%d)\n", This, bShow);
7600 This->bCursorVisible = bShow;
7602 return WINED3D_OK;
7605 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7607 TRACE("(%p) : state (%lu)\n", This, This->state);
7608 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7609 switch (This->state) {
7610 case WINED3D_OK:
7611 return WINED3D_OK;
7612 case WINED3DERR_DEVICELOST:
7614 ResourceList *resourceList = This->resources;
7615 while (NULL != resourceList) {
7616 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7617 return WINED3DERR_DEVICENOTRESET;
7618 resourceList = resourceList->next;
7620 return WINED3DERR_DEVICELOST;
7622 case WINED3DERR_DRIVERINTERNALERROR:
7623 return WINED3DERR_DRIVERINTERNALERROR;
7626 /* Unknown state */
7627 return WINED3DERR_DRIVERINTERNALERROR;
7631 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7633 /** FIXME: Resource tracking needs to be done,
7634 * The closes we can do to this is set the priorities of all managed textures low
7635 * and then reset them.
7636 ***********************************************************/
7637 FIXME("(%p) : stub\n", This);
7638 return WINED3D_OK;
7641 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7643 /** FIXME: Resource trascking needs to be done.
7644 * in effect this pulls all non only default
7645 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7646 * and should clear down the context and set it up according to pPresentationParameters
7647 ***********************************************************/
7648 FIXME("(%p) : stub\n", This);
7649 return WINED3D_OK;
7652 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7654 /** FIXME: always true at the moment **/
7655 if(bEnableDialogs == FALSE) {
7656 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7658 return WINED3D_OK;
7662 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7664 TRACE("(%p) : pParameters %p\n", This, pParameters);
7666 *pParameters = This->createParms;
7667 return WINED3D_OK;
7670 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7671 IWineD3DSwapChain *swapchain;
7672 HRESULT hrc = WINED3D_OK;
7674 TRACE("Relaying to swapchain\n");
7676 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7677 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7678 IWineD3DSwapChain_Release(swapchain);
7680 return;
7683 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7684 IWineD3DSwapChain *swapchain;
7685 HRESULT hrc = WINED3D_OK;
7687 TRACE("Relaying to swapchain\n");
7689 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7690 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7691 IWineD3DSwapChain_Release(swapchain);
7693 return;
7697 /** ********************************************************
7698 * Notification functions
7699 ** ********************************************************/
7700 /** This function must be called in the release of a resource when ref == 0,
7701 * the contents of resource must still be correct,
7702 * any handels to other resource held by the caller must be closed
7703 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7704 *****************************************************/
7705 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7707 ResourceList* resourceList;
7709 TRACE("(%p) : resource %p\n", This, resource);
7710 #if 0
7711 EnterCriticalSection(&resourceStoreCriticalSection);
7712 #endif
7713 /* add a new texture to the frot of the linked list */
7714 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7715 resourceList->resource = resource;
7717 /* Get the old head */
7718 resourceList->next = This->resources;
7720 This->resources = resourceList;
7721 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7723 #if 0
7724 LeaveCriticalSection(&resourceStoreCriticalSection);
7725 #endif
7726 return;
7729 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7731 ResourceList* resourceList = NULL;
7732 ResourceList* previousResourceList = NULL;
7734 TRACE("(%p) : resource %p\n", This, resource);
7736 #if 0
7737 EnterCriticalSection(&resourceStoreCriticalSection);
7738 #endif
7739 resourceList = This->resources;
7741 while (resourceList != NULL) {
7742 if(resourceList->resource == resource) break;
7743 previousResourceList = resourceList;
7744 resourceList = resourceList->next;
7747 if (resourceList == NULL) {
7748 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7749 #if 0
7750 LeaveCriticalSection(&resourceStoreCriticalSection);
7751 #endif
7752 return;
7753 } else {
7754 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7756 /* make sure we don't leave a hole in the list */
7757 if (previousResourceList != NULL) {
7758 previousResourceList->next = resourceList->next;
7759 } else {
7760 This->resources = resourceList->next;
7763 #if 0
7764 LeaveCriticalSection(&resourceStoreCriticalSection);
7765 #endif
7766 return;
7770 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7772 int counter;
7774 TRACE("(%p) : resource %p\n", This, resource);
7775 switch(IWineD3DResource_GetType(resource)){
7776 case WINED3DRTYPE_SURFACE:
7777 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7778 break;
7779 case WINED3DRTYPE_TEXTURE:
7780 case WINED3DRTYPE_CUBETEXTURE:
7781 case WINED3DRTYPE_VOLUMETEXTURE:
7782 for (counter = 0; counter < GL_LIMITS(textures); counter++) {
7783 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7784 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7785 This->stateBlock->textures[counter] = NULL;
7787 if (This->updateStateBlock != This->stateBlock ){
7788 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7789 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7790 This->updateStateBlock->textures[counter] = NULL;
7794 break;
7795 case WINED3DRTYPE_VOLUME:
7796 /* TODO: nothing really? */
7797 break;
7798 case WINED3DRTYPE_VERTEXBUFFER:
7799 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7801 int streamNumber;
7802 TRACE("Cleaning up stream pointers\n");
7804 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7805 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7806 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7808 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7809 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7810 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7811 This->updateStateBlock->streamSource[streamNumber] = 0;
7812 /* Set changed flag? */
7815 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) */
7816 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7817 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7818 This->stateBlock->streamSource[streamNumber] = 0;
7821 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7822 else { /* This shouldn't happen */
7823 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7825 #endif
7829 break;
7830 case WINED3DRTYPE_INDEXBUFFER:
7831 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7832 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7833 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7834 This->updateStateBlock->pIndexData = NULL;
7837 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7838 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7839 This->stateBlock->pIndexData = NULL;
7843 break;
7844 default:
7845 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7846 break;
7850 /* Remove the resoruce from the resourceStore */
7851 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7853 TRACE("Resource released\n");
7857 /**********************************************************
7858 * IWineD3DDevice VTbl follows
7859 **********************************************************/
7861 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7863 /*** IUnknown methods ***/
7864 IWineD3DDeviceImpl_QueryInterface,
7865 IWineD3DDeviceImpl_AddRef,
7866 IWineD3DDeviceImpl_Release,
7867 /*** IWineD3DDevice methods ***/
7868 IWineD3DDeviceImpl_GetParent,
7869 /*** Creation methods**/
7870 IWineD3DDeviceImpl_CreateVertexBuffer,
7871 IWineD3DDeviceImpl_CreateIndexBuffer,
7872 IWineD3DDeviceImpl_CreateStateBlock,
7873 IWineD3DDeviceImpl_CreateSurface,
7874 IWineD3DDeviceImpl_CreateTexture,
7875 IWineD3DDeviceImpl_CreateVolumeTexture,
7876 IWineD3DDeviceImpl_CreateVolume,
7877 IWineD3DDeviceImpl_CreateCubeTexture,
7878 IWineD3DDeviceImpl_CreateQuery,
7879 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7880 IWineD3DDeviceImpl_CreateVertexDeclaration,
7881 IWineD3DDeviceImpl_CreateVertexShader,
7882 IWineD3DDeviceImpl_CreatePixelShader,
7883 IWineD3DDeviceImpl_CreatePalette,
7884 /*** Odd functions **/
7885 IWineD3DDeviceImpl_Init3D,
7886 IWineD3DDeviceImpl_Uninit3D,
7887 IWineD3DDeviceImpl_EnumDisplayModes,
7888 IWineD3DDeviceImpl_EvictManagedResources,
7889 IWineD3DDeviceImpl_GetAvailableTextureMem,
7890 IWineD3DDeviceImpl_GetBackBuffer,
7891 IWineD3DDeviceImpl_GetCreationParameters,
7892 IWineD3DDeviceImpl_GetDeviceCaps,
7893 IWineD3DDeviceImpl_GetDirect3D,
7894 IWineD3DDeviceImpl_GetDisplayMode,
7895 IWineD3DDeviceImpl_SetDisplayMode,
7896 IWineD3DDeviceImpl_GetHWND,
7897 IWineD3DDeviceImpl_SetHWND,
7898 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7899 IWineD3DDeviceImpl_GetRasterStatus,
7900 IWineD3DDeviceImpl_GetSwapChain,
7901 IWineD3DDeviceImpl_Reset,
7902 IWineD3DDeviceImpl_SetDialogBoxMode,
7903 IWineD3DDeviceImpl_SetCursorProperties,
7904 IWineD3DDeviceImpl_SetCursorPosition,
7905 IWineD3DDeviceImpl_ShowCursor,
7906 IWineD3DDeviceImpl_TestCooperativeLevel,
7907 IWineD3DDeviceImpl_EnumZBufferFormats,
7908 IWineD3DDeviceImpl_EnumTextureFormats,
7909 /*** Getters and setters **/
7910 IWineD3DDeviceImpl_SetClipPlane,
7911 IWineD3DDeviceImpl_GetClipPlane,
7912 IWineD3DDeviceImpl_SetClipStatus,
7913 IWineD3DDeviceImpl_GetClipStatus,
7914 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7915 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7916 IWineD3DDeviceImpl_SetDepthStencilSurface,
7917 IWineD3DDeviceImpl_GetDepthStencilSurface,
7918 IWineD3DDeviceImpl_SetFVF,
7919 IWineD3DDeviceImpl_GetFVF,
7920 IWineD3DDeviceImpl_SetGammaRamp,
7921 IWineD3DDeviceImpl_GetGammaRamp,
7922 IWineD3DDeviceImpl_SetIndices,
7923 IWineD3DDeviceImpl_GetIndices,
7924 IWineD3DDeviceImpl_SetLight,
7925 IWineD3DDeviceImpl_GetLight,
7926 IWineD3DDeviceImpl_SetLightEnable,
7927 IWineD3DDeviceImpl_GetLightEnable,
7928 IWineD3DDeviceImpl_SetMaterial,
7929 IWineD3DDeviceImpl_GetMaterial,
7930 IWineD3DDeviceImpl_SetNPatchMode,
7931 IWineD3DDeviceImpl_GetNPatchMode,
7932 IWineD3DDeviceImpl_SetPaletteEntries,
7933 IWineD3DDeviceImpl_GetPaletteEntries,
7934 IWineD3DDeviceImpl_SetPixelShader,
7935 IWineD3DDeviceImpl_GetPixelShader,
7936 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7937 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7938 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7939 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7940 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7941 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7942 IWineD3DDeviceImpl_SetRenderState,
7943 IWineD3DDeviceImpl_GetRenderState,
7944 IWineD3DDeviceImpl_SetRenderTarget,
7945 IWineD3DDeviceImpl_GetRenderTarget,
7946 IWineD3DDeviceImpl_SetFrontBackBuffers,
7947 IWineD3DDeviceImpl_SetSamplerState,
7948 IWineD3DDeviceImpl_GetSamplerState,
7949 IWineD3DDeviceImpl_SetScissorRect,
7950 IWineD3DDeviceImpl_GetScissorRect,
7951 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7952 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7953 IWineD3DDeviceImpl_SetStreamSource,
7954 IWineD3DDeviceImpl_GetStreamSource,
7955 IWineD3DDeviceImpl_SetStreamSourceFreq,
7956 IWineD3DDeviceImpl_GetStreamSourceFreq,
7957 IWineD3DDeviceImpl_SetTexture,
7958 IWineD3DDeviceImpl_GetTexture,
7959 IWineD3DDeviceImpl_SetTextureStageState,
7960 IWineD3DDeviceImpl_GetTextureStageState,
7961 IWineD3DDeviceImpl_SetTransform,
7962 IWineD3DDeviceImpl_GetTransform,
7963 IWineD3DDeviceImpl_SetVertexDeclaration,
7964 IWineD3DDeviceImpl_GetVertexDeclaration,
7965 IWineD3DDeviceImpl_SetVertexShader,
7966 IWineD3DDeviceImpl_GetVertexShader,
7967 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7968 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7969 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7970 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7971 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7972 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7973 IWineD3DDeviceImpl_SetViewport,
7974 IWineD3DDeviceImpl_GetViewport,
7975 IWineD3DDeviceImpl_MultiplyTransform,
7976 IWineD3DDeviceImpl_ValidateDevice,
7977 IWineD3DDeviceImpl_ProcessVertices,
7978 /*** State block ***/
7979 IWineD3DDeviceImpl_BeginStateBlock,
7980 IWineD3DDeviceImpl_EndStateBlock,
7981 /*** Scene management ***/
7982 IWineD3DDeviceImpl_BeginScene,
7983 IWineD3DDeviceImpl_EndScene,
7984 IWineD3DDeviceImpl_Present,
7985 IWineD3DDeviceImpl_Clear,
7986 /*** Drawing ***/
7987 IWineD3DDeviceImpl_DrawPrimitive,
7988 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7989 IWineD3DDeviceImpl_DrawPrimitiveUP,
7990 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7991 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7992 IWineD3DDeviceImpl_DrawRectPatch,
7993 IWineD3DDeviceImpl_DrawTriPatch,
7994 IWineD3DDeviceImpl_DeletePatch,
7995 IWineD3DDeviceImpl_ColorFill,
7996 IWineD3DDeviceImpl_UpdateTexture,
7997 IWineD3DDeviceImpl_UpdateSurface,
7998 IWineD3DDeviceImpl_CopyRects,
7999 IWineD3DDeviceImpl_StretchRect,
8000 IWineD3DDeviceImpl_GetRenderTargetData,
8001 IWineD3DDeviceImpl_GetFrontBufferData,
8002 /*** Internal use IWineD3DDevice methods ***/
8003 IWineD3DDeviceImpl_SetupTextureStates,
8004 /*** object tracking ***/
8005 IWineD3DDeviceImpl_ResourceReleased
8009 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8010 WINED3DRS_ALPHABLENDENABLE ,
8011 WINED3DRS_ALPHAFUNC ,
8012 WINED3DRS_ALPHAREF ,
8013 WINED3DRS_ALPHATESTENABLE ,
8014 WINED3DRS_BLENDOP ,
8015 WINED3DRS_COLORWRITEENABLE ,
8016 WINED3DRS_DESTBLEND ,
8017 WINED3DRS_DITHERENABLE ,
8018 WINED3DRS_FILLMODE ,
8019 WINED3DRS_FOGDENSITY ,
8020 WINED3DRS_FOGEND ,
8021 WINED3DRS_FOGSTART ,
8022 WINED3DRS_LASTPIXEL ,
8023 WINED3DRS_SHADEMODE ,
8024 WINED3DRS_SRCBLEND ,
8025 WINED3DRS_STENCILENABLE ,
8026 WINED3DRS_STENCILFAIL ,
8027 WINED3DRS_STENCILFUNC ,
8028 WINED3DRS_STENCILMASK ,
8029 WINED3DRS_STENCILPASS ,
8030 WINED3DRS_STENCILREF ,
8031 WINED3DRS_STENCILWRITEMASK ,
8032 WINED3DRS_STENCILZFAIL ,
8033 WINED3DRS_TEXTUREFACTOR ,
8034 WINED3DRS_WRAP0 ,
8035 WINED3DRS_WRAP1 ,
8036 WINED3DRS_WRAP2 ,
8037 WINED3DRS_WRAP3 ,
8038 WINED3DRS_WRAP4 ,
8039 WINED3DRS_WRAP5 ,
8040 WINED3DRS_WRAP6 ,
8041 WINED3DRS_WRAP7 ,
8042 WINED3DRS_ZENABLE ,
8043 WINED3DRS_ZFUNC ,
8044 WINED3DRS_ZWRITEENABLE
8047 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8048 WINED3DTSS_ADDRESSW ,
8049 WINED3DTSS_ALPHAARG0 ,
8050 WINED3DTSS_ALPHAARG1 ,
8051 WINED3DTSS_ALPHAARG2 ,
8052 WINED3DTSS_ALPHAOP ,
8053 WINED3DTSS_BUMPENVLOFFSET ,
8054 WINED3DTSS_BUMPENVLSCALE ,
8055 WINED3DTSS_BUMPENVMAT00 ,
8056 WINED3DTSS_BUMPENVMAT01 ,
8057 WINED3DTSS_BUMPENVMAT10 ,
8058 WINED3DTSS_BUMPENVMAT11 ,
8059 WINED3DTSS_COLORARG0 ,
8060 WINED3DTSS_COLORARG1 ,
8061 WINED3DTSS_COLORARG2 ,
8062 WINED3DTSS_COLOROP ,
8063 WINED3DTSS_RESULTARG ,
8064 WINED3DTSS_TEXCOORDINDEX ,
8065 WINED3DTSS_TEXTURETRANSFORMFLAGS
8068 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8069 WINED3DSAMP_ADDRESSU ,
8070 WINED3DSAMP_ADDRESSV ,
8071 WINED3DSAMP_ADDRESSW ,
8072 WINED3DSAMP_BORDERCOLOR ,
8073 WINED3DSAMP_MAGFILTER ,
8074 WINED3DSAMP_MINFILTER ,
8075 WINED3DSAMP_MIPFILTER ,
8076 WINED3DSAMP_MIPMAPLODBIAS ,
8077 WINED3DSAMP_MAXMIPLEVEL ,
8078 WINED3DSAMP_MAXANISOTROPY ,
8079 WINED3DSAMP_SRGBTEXTURE ,
8080 WINED3DSAMP_ELEMENTINDEX
8083 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8084 WINED3DRS_AMBIENT ,
8085 WINED3DRS_AMBIENTMATERIALSOURCE ,
8086 WINED3DRS_CLIPPING ,
8087 WINED3DRS_CLIPPLANEENABLE ,
8088 WINED3DRS_COLORVERTEX ,
8089 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8090 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8091 WINED3DRS_FOGDENSITY ,
8092 WINED3DRS_FOGEND ,
8093 WINED3DRS_FOGSTART ,
8094 WINED3DRS_FOGTABLEMODE ,
8095 WINED3DRS_FOGVERTEXMODE ,
8096 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8097 WINED3DRS_LIGHTING ,
8098 WINED3DRS_LOCALVIEWER ,
8099 WINED3DRS_MULTISAMPLEANTIALIAS ,
8100 WINED3DRS_MULTISAMPLEMASK ,
8101 WINED3DRS_NORMALIZENORMALS ,
8102 WINED3DRS_PATCHEDGESTYLE ,
8103 WINED3DRS_POINTSCALE_A ,
8104 WINED3DRS_POINTSCALE_B ,
8105 WINED3DRS_POINTSCALE_C ,
8106 WINED3DRS_POINTSCALEENABLE ,
8107 WINED3DRS_POINTSIZE ,
8108 WINED3DRS_POINTSIZE_MAX ,
8109 WINED3DRS_POINTSIZE_MIN ,
8110 WINED3DRS_POINTSPRITEENABLE ,
8111 WINED3DRS_RANGEFOGENABLE ,
8112 WINED3DRS_SPECULARMATERIALSOURCE ,
8113 WINED3DRS_TWEENFACTOR ,
8114 WINED3DRS_VERTEXBLEND
8117 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8118 WINED3DTSS_TEXCOORDINDEX ,
8119 WINED3DTSS_TEXTURETRANSFORMFLAGS
8122 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8123 WINED3DSAMP_DMAPOFFSET