wined3d: Add and use GL_EXT_fog_coord defines.
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob1feb072662a24a749fa025bd5ae3e281fad1b1d6
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 HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
618 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
619 IUnknown *parent) {
620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
621 IWineD3DVertexBufferImpl *object;
622 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
623 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
625 /*TODO: use VBO's */
626 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
627 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
629 object->fvf = FVF;
631 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
632 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
634 return WINED3D_OK;
637 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
638 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
639 HANDLE *sharedHandle, IUnknown *parent) {
640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
641 IWineD3DIndexBufferImpl *object;
642 TRACE("(%p) Creating index buffer\n", This);
644 /* Allocate the storage for the device */
645 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
647 /*TODO: use VBO's */
648 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
649 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
652 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
653 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
654 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
656 return WINED3D_OK;
659 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
662 IWineD3DStateBlockImpl *object;
663 int i, j;
665 D3DCREATEOBJECTINSTANCE(object, StateBlock)
666 object->blockType = Type;
668 /* Special case - Used during initialization to produce a placeholder stateblock
669 so other functions called can update a state block */
670 if (Type == WINED3DSBT_INIT) {
671 /* Don't bother increasing the reference count otherwise a device will never
672 be freed due to circular dependencies */
673 return WINED3D_OK;
676 /* Otherwise, might as well set the whole state block to the appropriate values */
677 if ( This->stateBlock != NULL) {
678 memcpy(object, This->stateBlock, sizeof(IWineD3DStateBlockImpl));
679 } else {
680 memset(object->streamFreq, 1, sizeof(object->streamFreq));
683 /* Reset the ref and type after kludging it */
684 object->wineD3DDevice = This;
685 object->ref = 1;
686 object->blockType = Type;
688 TRACE("Updating changed flags appropriate for type %d\n", Type);
690 if (Type == WINED3DSBT_ALL) {
692 TRACE("ALL => Pretend everything has changed\n");
693 memset(&object->changed, TRUE, sizeof(This->stateBlock->changed));
694 } else if (Type == WINED3DSBT_PIXELSTATE) {
696 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
697 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
699 object->changed.pixelShader = TRUE;
701 /* Pixel Shader Constants */
702 for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
703 object->changed.pixelShaderConstantsF[i] = TRUE;
704 object->changed.pixelShaderConstantsB[i] = TRUE;
705 object->changed.pixelShaderConstantsI[i] = TRUE;
707 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
708 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
710 for (j = 0; j < GL_LIMITS(textures); j++) {
711 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
712 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
715 for (j = 0 ; j < 16; j++) {
716 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
718 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
722 } else if (Type == WINED3DSBT_VERTEXSTATE) {
724 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
725 memset(&object->changed, FALSE, sizeof(This->stateBlock->changed));
727 object->changed.vertexShader = TRUE;
729 /* Vertex Shader Constants */
730 for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
731 object->changed.vertexShaderConstantsF[i] = TRUE;
732 object->changed.vertexShaderConstantsB[i] = TRUE;
733 object->changed.vertexShaderConstantsI[i] = TRUE;
735 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
736 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
738 for (j = 0; j < GL_LIMITS(textures); j++) {
739 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
740 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
743 for (j = 0 ; j < 16; j++){
744 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
745 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
749 /* Duplicate light chain */
751 PLIGHTINFOEL *src = NULL;
752 PLIGHTINFOEL *dst = NULL;
753 PLIGHTINFOEL *newEl = NULL;
754 src = This->stateBlock->lights;
755 object->lights = NULL;
758 while (src) {
759 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
760 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
761 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
762 newEl->prev = dst;
763 newEl->changed = TRUE;
764 newEl->enabledChanged = TRUE;
765 if (dst == NULL) {
766 object->lights = newEl;
767 } else {
768 dst->next = newEl;
770 dst = newEl;
771 src = src->next;
776 } else {
777 FIXME("Unrecognized state block type %d\n", Type);
780 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
781 return WINED3D_OK;
785 /* ************************************
786 MSDN:
787 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
789 Discard
790 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
792 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.
794 ******************************** */
796 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) {
797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
798 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
799 unsigned int pow2Width, pow2Height;
800 unsigned int Size = 1;
801 TRACE("(%p) Create surface\n",This);
803 /** FIXME: Check ranges on the inputs are valid
804 * MSDN
805 * MultisampleQuality
806 * [in] Quality level. The valid range is between zero and one less than the level
807 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
808 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
809 * values of paired render targets, depth stencil surfaces, and the MultiSample type
810 * must all match.
811 *******************************/
815 * TODO: Discard MSDN
816 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
818 * If this flag is set, the contents of the depth stencil buffer will be
819 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
820 * with a different depth surface.
822 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
823 ***************************/
825 if(MultisampleQuality < 0) {
826 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
827 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
830 if(MultisampleQuality > 0) {
831 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
832 MultisampleQuality=0;
835 /** FIXME: Check that the format is supported
836 * by the device.
837 *******************************/
839 /* Non-power2 support */
841 /* Find the nearest pow2 match */
842 pow2Width = pow2Height = 1;
843 while (pow2Width < Width) pow2Width <<= 1;
844 while (pow2Height < Height) pow2Height <<= 1;
846 if (pow2Width > Width || pow2Height > Height) {
847 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
848 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
849 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
850 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
851 This, Width, Height);
852 return WINED3DERR_NOTAVAILABLE;
856 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
857 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
858 * space!
859 *********************************/
860 if (WINED3DFMT_UNKNOWN == Format) {
861 Size = 0;
862 } else if (Format == WINED3DFMT_DXT1) {
863 /* DXT1 is half byte per pixel */
864 Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4)) >> 1;
866 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
867 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
868 Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4));
869 } else {
870 Size = (pow2Width * D3DFmtGetBpp(This, Format)) * pow2Height;
873 /** Create and initialise the surface resource **/
874 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
875 /* "Standalone" surface */
876 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
878 object->currentDesc.Width = Width;
879 object->currentDesc.Height = Height;
880 object->currentDesc.MultiSampleType = MultiSample;
881 object->currentDesc.MultiSampleQuality = MultisampleQuality;
883 /* Setup some glformat defaults */
884 if (WINED3DFMT_UNKNOWN != Format) {
885 object->glDescription.glFormat = D3DFmt2GLFmt(This, object->resource.format);
886 object->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This, object->resource.format);
887 object->glDescription.glType = D3DFmt2GLType(This, object->resource.format);
888 } else {
889 object->glDescription.glFormat = 0;
890 object->glDescription.glFormatInternal = 0;
891 object->glDescription.glType = 0;
894 object->glDescription.textureName = 0;
895 object->glDescription.level = Level;
896 object->glDescription.target = GL_TEXTURE_2D;
898 /* Internal data */
899 object->pow2Width = pow2Width;
900 object->pow2Height = pow2Height;
902 /* Flags */
903 object->Flags = 0; /* We start without flags set */
904 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
905 object->Flags |= Discard ? SFLAG_DISCARD : 0;
906 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
907 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
910 if (WINED3DFMT_UNKNOWN != Format) {
911 object->bytesPerPixel = D3DFmtGetBpp(This, Format);
912 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
913 } else {
914 object->bytesPerPixel = 0;
915 object->pow2Size = 0;
918 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
920 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
922 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
923 * this function is too deap to need to care about things like this.
924 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
925 * ****************************************/
926 switch(Pool) {
927 case WINED3DPOOL_SCRATCH:
928 if(Lockable == FALSE)
929 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
930 which are mutually exclusive, setting lockable to true\n");
931 Lockable = TRUE;
932 break;
933 case WINED3DPOOL_SYSTEMMEM:
934 if(Lockable == FALSE) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
935 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
936 case WINED3DPOOL_MANAGED:
937 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
938 Usage of DYNAMIC which are mutually exclusive, not doing \
939 anything just telling you.\n");
940 break;
941 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
942 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
943 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
944 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
945 break;
946 default:
947 FIXME("(%p) Unknown pool %d\n", This, Pool);
948 break;
951 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
952 FIXME("Trying to create a render target that isn't in the default pool\n");
955 /* mark the texture as dirty so that it get's loaded first time around*/
956 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
957 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
958 This, Width, Height, Format, debug_d3dformat(Format),
959 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
961 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
962 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
963 This->ddraw_primary = (IWineD3DSurface *) object;
965 /* Look at the implementation and set the correct Vtable */
966 switch(Impl) {
967 case SURFACE_OPENGL:
968 /* Nothing to do, it's set already */
969 break;
971 case SURFACE_GDI:
972 object->lpVtbl = &IWineGDISurface_Vtbl;
973 break;
975 default:
976 /* To be sure to catch this */
977 ERR("Unknown requested surface implementation %d!\n", Impl);
978 IWineD3DSurface_Release((IWineD3DSurface *) object);
979 return WINED3DERR_INVALIDCALL;
982 /* Call the private setup routine */
983 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
987 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
988 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
989 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
990 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
993 IWineD3DTextureImpl *object;
994 unsigned int i;
995 UINT tmpW;
996 UINT tmpH;
997 HRESULT hr;
998 unsigned int pow2Width = Width;
999 unsigned int pow2Height = Height;
1002 TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) ....\n", This, Width, Height, Levels, Usage);
1004 /* TODO: It should only be possible to create textures for formats
1005 that are reported as supported */
1006 if (WINED3DFMT_UNKNOWN >= Format) {
1007 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1008 return WINED3DERR_INVALIDCALL;
1011 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1012 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1013 object->width = Width;
1014 object->height = Height;
1016 /** Non-power2 support **/
1017 /* Find the nearest pow2 match */
1018 pow2Width = pow2Height = 1;
1019 while (pow2Width < Width) pow2Width <<= 1;
1020 while (pow2Height < Height) pow2Height <<= 1;
1022 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1023 /* Precalculated scaling for 'faked' non power of two texture coords */
1024 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1025 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1026 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1028 /* Calculate levels for mip mapping */
1029 if (Levels == 0) {
1030 TRACE("calculating levels %d\n", object->baseTexture.levels);
1031 object->baseTexture.levels++;
1032 tmpW = Width;
1033 tmpH = Height;
1034 while (tmpW > 1 || tmpH > 1) {
1035 tmpW = max(1, tmpW >> 1);
1036 tmpH = max(1, tmpH >> 1);
1037 object->baseTexture.levels++;
1039 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1042 /* Generate all the surfaces */
1043 tmpW = Width;
1044 tmpH = Height;
1045 for (i = 0; i < object->baseTexture.levels; i++)
1047 /* use the callback to create the texture surface */
1048 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1049 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1050 FIXME("Failed to create surface %p\n", object);
1051 /* clean up */
1052 object->surfaces[i] = NULL;
1053 IWineD3DTexture_Release((IWineD3DTexture *)object);
1055 *ppTexture = NULL;
1056 return hr;
1059 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1060 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1061 /* calculate the next mipmap level */
1062 tmpW = max(1, tmpW >> 1);
1063 tmpH = max(1, tmpH >> 1);
1066 TRACE("(%p) : Created texture %p\n", This, object);
1067 return WINED3D_OK;
1070 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1071 UINT Width, UINT Height, UINT Depth,
1072 UINT Levels, DWORD Usage,
1073 WINED3DFORMAT Format, WINED3DPOOL Pool,
1074 IWineD3DVolumeTexture **ppVolumeTexture,
1075 HANDLE *pSharedHandle, IUnknown *parent,
1076 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DVolumeTextureImpl *object;
1080 unsigned int i;
1081 UINT tmpW;
1082 UINT tmpH;
1083 UINT tmpD;
1085 /* TODO: It should only be possible to create textures for formats
1086 that are reported as supported */
1087 if (WINED3DFMT_UNKNOWN >= Format) {
1088 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1089 return WINED3DERR_INVALIDCALL;
1092 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1093 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1095 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1096 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1098 object->width = Width;
1099 object->height = Height;
1100 object->depth = Depth;
1102 /* Calculate levels for mip mapping */
1103 if (Levels == 0) {
1104 object->baseTexture.levels++;
1105 tmpW = Width;
1106 tmpH = Height;
1107 tmpD = Depth;
1108 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1109 tmpW = max(1, tmpW >> 1);
1110 tmpH = max(1, tmpH >> 1);
1111 tmpD = max(1, tmpD >> 1);
1112 object->baseTexture.levels++;
1114 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1117 /* Generate all the surfaces */
1118 tmpW = Width;
1119 tmpH = Height;
1120 tmpD = Depth;
1122 for (i = 0; i < object->baseTexture.levels; i++)
1124 /* Create the volume */
1125 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1126 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1128 /* Set it's container to this object */
1129 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1131 /* calcualte the next mipmap level */
1132 tmpW = max(1, tmpW >> 1);
1133 tmpH = max(1, tmpH >> 1);
1134 tmpD = max(1, tmpD >> 1);
1137 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1138 TRACE("(%p) : Created volume texture %p\n", This, object);
1139 return WINED3D_OK;
1142 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1143 UINT Width, UINT Height, UINT Depth,
1144 DWORD Usage,
1145 WINED3DFORMAT Format, WINED3DPOOL Pool,
1146 IWineD3DVolume** ppVolume,
1147 HANDLE* pSharedHandle, IUnknown *parent) {
1149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1150 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1152 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * D3DFmtGetBpp(This, Format)) * Height * Depth))
1154 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1155 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1157 object->currentDesc.Width = Width;
1158 object->currentDesc.Height = Height;
1159 object->currentDesc.Depth = Depth;
1160 object->bytesPerPixel = D3DFmtGetBpp(This, Format);
1162 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1163 object->lockable = TRUE;
1164 object->locked = FALSE;
1165 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1166 object->dirty = TRUE;
1168 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1171 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1172 UINT Levels, DWORD Usage,
1173 WINED3DFORMAT Format, WINED3DPOOL Pool,
1174 IWineD3DCubeTexture **ppCubeTexture,
1175 HANDLE *pSharedHandle, IUnknown *parent,
1176 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1180 unsigned int i, j;
1181 UINT tmpW;
1182 HRESULT hr;
1183 unsigned int pow2EdgeLength = EdgeLength;
1185 /* TODO: It should only be possible to create textures for formats
1186 that are reported as supported */
1187 if (WINED3DFMT_UNKNOWN >= Format) {
1188 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1189 return WINED3DERR_INVALIDCALL;
1192 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1193 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1195 TRACE("(%p) Create Cube Texture\n", This);
1197 /** Non-power2 support **/
1199 /* Find the nearest pow2 match */
1200 pow2EdgeLength = 1;
1201 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1203 object->edgeLength = EdgeLength;
1204 /* TODO: support for native non-power 2 */
1205 /* Precalculated scaling for 'faked' non power of two texture coords */
1206 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1208 /* Calculate levels for mip mapping */
1209 if (Levels == 0) {
1210 object->baseTexture.levels++;
1211 tmpW = EdgeLength;
1212 while (tmpW > 1) {
1213 tmpW = max(1, tmpW >> 1);
1214 object->baseTexture.levels++;
1216 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1219 /* Generate all the surfaces */
1220 tmpW = EdgeLength;
1221 for (i = 0; i < object->baseTexture.levels; i++) {
1223 /* Create the 6 faces */
1224 for (j = 0; j < 6; j++) {
1226 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1227 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1229 if(hr!= WINED3D_OK) {
1230 /* clean up */
1231 int k;
1232 int l;
1233 for (l = 0; l < j; l++) {
1234 IWineD3DSurface_Release(object->surfaces[j][i]);
1236 for (k = 0; k < i; k++) {
1237 for (l = 0; l < 6; l++) {
1238 IWineD3DSurface_Release(object->surfaces[l][j]);
1242 FIXME("(%p) Failed to create surface\n",object);
1243 HeapFree(GetProcessHeap(),0,object);
1244 *ppCubeTexture = NULL;
1245 return hr;
1247 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1248 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1250 tmpW = max(1, tmpW >> 1);
1253 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1254 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1255 return WINED3D_OK;
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1260 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1262 if (NULL == ppQuery) {
1263 /* Just a check to see if we support this type of query */
1264 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1265 switch(Type) {
1266 case WINED3DQUERYTYPE_OCCLUSION:
1267 TRACE("(%p) occlusion query\n", This);
1268 if (GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY))
1269 hr = WINED3D_OK;
1270 else
1271 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1272 break;
1273 case WINED3DQUERYTYPE_VCACHE:
1274 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1275 case WINED3DQUERYTYPE_VERTEXSTATS:
1276 case WINED3DQUERYTYPE_EVENT:
1277 case WINED3DQUERYTYPE_TIMESTAMP:
1278 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1279 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1280 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1281 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1282 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1283 case WINED3DQUERYTYPE_PIXELTIMINGS:
1284 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1285 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1286 default:
1287 FIXME("(%p) Unhandled query type %d\n", This, Type);
1289 return hr;
1292 D3DCREATEOBJECTINSTANCE(object, Query)
1293 object->type = Type;
1294 /* allocated the 'extended' data based on the type of query requested */
1295 switch(Type){
1296 case D3DQUERYTYPE_OCCLUSION:
1297 if(GL_SUPPORT(ARB_OCCLUSION_QUERY) || GL_SUPPORT(NV_OCCLUSION_QUERY)) {
1298 TRACE("(%p) Allocating data for an occlusion query\n", This);
1299 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1300 break;
1302 case D3DQUERYTYPE_VCACHE:
1303 case D3DQUERYTYPE_RESOURCEMANAGER:
1304 case D3DQUERYTYPE_VERTEXSTATS:
1305 case D3DQUERYTYPE_EVENT:
1306 case D3DQUERYTYPE_TIMESTAMP:
1307 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1308 case D3DQUERYTYPE_TIMESTAMPFREQ:
1309 case D3DQUERYTYPE_PIPELINETIMINGS:
1310 case D3DQUERYTYPE_INTERFACETIMINGS:
1311 case D3DQUERYTYPE_VERTEXTIMINGS:
1312 case D3DQUERYTYPE_PIXELTIMINGS:
1313 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1314 case D3DQUERYTYPE_CACHEUTILIZATION:
1315 default:
1316 object->extendedData = 0;
1317 FIXME("(%p) Unhandled query type %d\n",This , Type);
1319 TRACE("(%p) : Created Query %p\n", This, object);
1320 return WINED3D_OK;
1323 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1325 IUnknown* parent,
1326 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1327 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1330 HDC hDc;
1331 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1332 int num;
1333 XVisualInfo template;
1334 GLXContext oldContext;
1335 Drawable oldDrawable;
1336 HRESULT hr = WINED3D_OK;
1338 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1340 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1341 * does a device hold a reference to a swap chain giving them a lifetime of the device
1342 * or does the swap chain notify the device of its destruction.
1343 *******************************/
1345 /* Check the params */
1346 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1347 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1348 return WINED3DERR_INVALIDCALL;
1349 } else if (*pPresentationParameters->BackBufferCount > 1) {
1350 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");
1353 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1355 /*********************
1356 * Lookup the window Handle and the relating X window handle
1357 ********************/
1359 /* Setup hwnd we are using, plus which display this equates to */
1360 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1361 if (!object->win_handle) {
1362 object->win_handle = This->createParms.hFocusWindow;
1365 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1366 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1367 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1368 return WINED3DERR_NOTAVAILABLE;
1370 hDc = GetDC(object->win_handle);
1371 object->display = get_display(hDc);
1372 ReleaseDC(object->win_handle, hDc);
1373 TRACE("Using a display of %p %p\n", object->display, hDc);
1375 if (NULL == object->display || NULL == hDc) {
1376 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1377 return WINED3DERR_NOTAVAILABLE;
1380 if (object->win == 0) {
1381 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1382 return WINED3DERR_NOTAVAILABLE;
1385 * Create an opengl context for the display visual
1386 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1387 * use different properties after that point in time. FIXME: How to handle when requested format
1388 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1389 * it chooses is identical to the one already being used!
1390 **********************************/
1392 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1393 ENTER_GL();
1395 /* Create a new context for this swapchain */
1396 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1397 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1398 (or the best possible if none is requested) */
1399 TRACE("Found x visual ID : %ld\n", template.visualid);
1401 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1402 if (NULL == object->visInfo) {
1403 ERR("cannot really get XVisual\n");
1404 LEAVE_GL();
1405 return WINED3DERR_NOTAVAILABLE;
1406 } else {
1407 int n, value;
1408 /* Write out some debug info about the visual/s */
1409 TRACE("Using x visual ID : %ld\n", template.visualid);
1410 TRACE(" visual info: %p\n", object->visInfo);
1411 TRACE(" num items : %d\n", num);
1412 for (n = 0;n < num; n++) {
1413 TRACE("=====item=====: %d\n", n + 1);
1414 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1415 TRACE(" screen : %d\n", object->visInfo[n].screen);
1416 TRACE(" depth : %u\n", object->visInfo[n].depth);
1417 TRACE(" class : %d\n", object->visInfo[n].class);
1418 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1419 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1420 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1421 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1422 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1423 /* log some extra glx info */
1424 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1425 TRACE(" gl_aux_buffers : %d\n", value);
1426 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1427 TRACE(" gl_buffer_size : %d\n", value);
1428 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1429 TRACE(" gl_red_size : %d\n", value);
1430 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1431 TRACE(" gl_green_size : %d\n", value);
1432 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1433 TRACE(" gl_blue_size : %d\n", value);
1434 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1435 TRACE(" gl_alpha_size : %d\n", value);
1436 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1437 TRACE(" gl_depth_size : %d\n", value);
1438 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1439 TRACE(" gl_stencil_size : %d\n", value);
1441 /* Now choose a simila visual ID*/
1443 #ifdef USE_CONTEXT_MANAGER
1445 /** TODO: use a context mamager **/
1446 #endif
1449 IWineD3DSwapChain *implSwapChain;
1450 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1451 /* The first time around we create the context that is shared with all other swapchains and render targets */
1452 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1453 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1454 } else {
1456 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1457 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1458 /* and create a new context with the implicit swapchains context as the shared context */
1459 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1460 IWineD3DSwapChain_Release(implSwapChain);
1464 /* Cleanup */
1465 XFree(object->visInfo);
1466 object->visInfo = NULL;
1468 if (NULL == object->glCtx) {
1469 ERR("cannot create glxContext\n");
1470 LEAVE_GL();
1471 return WINED3DERR_NOTAVAILABLE;
1474 LEAVE_GL();
1475 if (object->glCtx == NULL) {
1476 ERR("Error in context creation !\n");
1477 return WINED3DERR_INVALIDCALL;
1478 } else {
1479 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1480 object->win_handle, object->glCtx, object->win, object->visInfo);
1483 /*********************
1484 * Windowed / Fullscreen
1485 *******************/
1488 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1489 * so we should really check to see if there is a fullscreen swapchain already
1490 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1491 **************************************/
1493 if (!*(pPresentationParameters->Windowed)) {
1495 DEVMODEW devmode;
1496 HDC hdc;
1497 int bpp = 0;
1499 /* Get info on the current display setup */
1500 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1501 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1502 DeleteDC(hdc);
1504 /* Change the display settings */
1505 memset(&devmode, 0, sizeof(DEVMODEW));
1506 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1507 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1508 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1509 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1510 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1511 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1513 /* Make popup window */
1514 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1515 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1516 *(pPresentationParameters->BackBufferWidth),
1517 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1519 /* For GetDisplayMode */
1520 This->ddraw_width = devmode.dmPelsWidth;
1521 This->ddraw_height = devmode.dmPelsHeight;
1522 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1526 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1527 * then the corresponding dimension of the client area of the hDeviceWindow
1528 * (or the focus window, if hDeviceWindow is NULL) is taken.
1529 **********************/
1531 if (*(pPresentationParameters->Windowed) &&
1532 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1533 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1535 RECT Rect;
1536 GetClientRect(object->win_handle, &Rect);
1538 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1539 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1540 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1542 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1543 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1544 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1548 /*********************
1549 * finish off parameter initialization
1550 *******************/
1552 /* Put the correct figures in the presentation parameters */
1553 TRACE("Coppying accross presentaion paraneters\n");
1554 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1555 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1556 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1557 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1558 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1559 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1560 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1561 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1562 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1563 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1564 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1565 object->presentParms.Flags = *(pPresentationParameters->Flags);
1566 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1567 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1570 /*********************
1571 * Create the back, front and stencil buffers
1572 *******************/
1574 TRACE("calling rendertarget CB\n");
1575 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1576 object->presentParms.BackBufferWidth,
1577 object->presentParms.BackBufferHeight,
1578 object->presentParms.BackBufferFormat,
1579 object->presentParms.MultiSampleType,
1580 object->presentParms.MultiSampleQuality,
1581 TRUE /* Lockable */,
1582 &object->frontBuffer,
1583 NULL /* pShared (always null)*/);
1584 if (object->frontBuffer != NULL)
1585 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1587 if(object->presentParms.BackBufferCount > 0) {
1588 int i;
1590 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1591 if(!object->backBuffer) {
1592 ERR("Out of memory\n");
1594 if (object->frontBuffer) {
1595 IUnknown *bufferParent;
1596 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1597 IUnknown_Release(bufferParent); /* once for the get parent */
1598 if (IUnknown_Release(bufferParent) > 0) {
1599 FIXME("(%p) Something's still holding the front buffer\n",This);
1602 HeapFree(GetProcessHeap(), 0, object);
1603 return E_OUTOFMEMORY;
1606 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1607 TRACE("calling rendertarget CB\n");
1608 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1609 object->presentParms.BackBufferWidth,
1610 object->presentParms.BackBufferHeight,
1611 object->presentParms.BackBufferFormat,
1612 object->presentParms.MultiSampleType,
1613 object->presentParms.MultiSampleQuality,
1614 TRUE /* Lockable */,
1615 &object->backBuffer[i],
1616 NULL /* pShared (always null)*/);
1617 if(hr == WINED3D_OK && object->backBuffer[i]) {
1618 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1619 } else {
1620 break;
1623 } else {
1624 object->backBuffer = NULL;
1627 if (object->backBuffer != NULL) {
1628 ENTER_GL();
1629 glDrawBuffer(GL_BACK);
1630 checkGLcall("glDrawBuffer(GL_BACK)");
1631 LEAVE_GL();
1632 } else {
1633 /* Single buffering - draw to front buffer */
1634 ENTER_GL();
1635 glDrawBuffer(GL_FRONT);
1636 checkGLcall("glDrawBuffer(GL_FRONT)");
1637 LEAVE_GL();
1640 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1641 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1642 TRACE("Creating depth stencil buffer\n");
1643 if (This->depthStencilBuffer == NULL ) {
1644 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1645 object->presentParms.BackBufferWidth,
1646 object->presentParms.BackBufferHeight,
1647 object->presentParms.AutoDepthStencilFormat,
1648 object->presentParms.MultiSampleType,
1649 object->presentParms.MultiSampleQuality,
1650 FALSE /* FIXME: Discard */,
1651 &This->depthStencilBuffer,
1652 NULL /* pShared (always null)*/ );
1653 if (This->depthStencilBuffer != NULL)
1654 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1657 /** TODO: A check on width, height and multisample types
1658 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1659 ****************************/
1660 object->wantsDepthStencilBuffer = TRUE;
1661 } else {
1662 object->wantsDepthStencilBuffer = FALSE;
1665 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? NULL : object->backBuffer[0], object->wantsDepthStencilBuffer);
1668 /*********************
1669 * init the default renderTarget management
1670 *******************/
1671 object->drawable = object->win;
1672 object->render_ctx = object->glCtx;
1674 if (hr == WINED3D_OK) {
1675 /*********************
1676 * Setup some defaults and clear down the buffers
1677 *******************/
1678 ENTER_GL();
1679 /** save current context and drawable **/
1680 oldContext = glXGetCurrentContext();
1681 oldDrawable = glXGetCurrentDrawable();
1683 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1684 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1685 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1687 checkGLcall("glXMakeCurrent");
1689 TRACE("Setting up the screen\n");
1690 /* Clear the screen */
1691 glClearColor(1.0, 0.0, 0.0, 0.0);
1692 checkGLcall("glClearColor");
1693 glClearIndex(0);
1694 glClearDepth(1);
1695 glClearStencil(0xffff);
1697 checkGLcall("glClear");
1699 glColor3f(1.0, 1.0, 1.0);
1700 checkGLcall("glColor3f");
1702 glEnable(GL_LIGHTING);
1703 checkGLcall("glEnable");
1705 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1706 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1708 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1709 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1711 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1712 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1714 /* switch back to the original context (if there was one)*/
1715 if (This->swapchains) {
1716 /** TODO: restore the context and drawable **/
1717 glXMakeCurrent(object->display, oldDrawable, oldContext);
1720 LEAVE_GL();
1722 TRACE("Set swapchain to %p\n", object);
1723 } else { /* something went wrong so clean up */
1724 IUnknown* bufferParent;
1725 if (object->frontBuffer) {
1727 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1728 IUnknown_Release(bufferParent); /* once for the get parent */
1729 if (IUnknown_Release(bufferParent) > 0) {
1730 FIXME("(%p) Something's still holding the front buffer\n",This);
1733 if (object->backBuffer) {
1734 int i;
1735 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1736 if(object->backBuffer[i]) {
1737 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1738 IUnknown_Release(bufferParent); /* once for the get parent */
1739 if (IUnknown_Release(bufferParent) > 0) {
1740 FIXME("(%p) Something's still holding the back buffer\n",This);
1744 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1745 object->backBuffer = NULL;
1747 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1748 /* Clean up the context */
1749 /* check that we are the current context first (we shouldn't be though!) */
1750 if (object->glCtx != 0) {
1751 if(glXGetCurrentContext() == object->glCtx) {
1752 glXMakeCurrent(object->display, None, NULL);
1754 glXDestroyContext(object->display, object->glCtx);
1756 HeapFree(GetProcessHeap(), 0, object);
1760 return hr;
1763 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1764 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1766 TRACE("(%p)\n", This);
1768 return This->NumberOfSwapChains;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1773 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1775 if(iSwapChain < This->NumberOfSwapChains) {
1776 *pSwapChain = This->swapchains[iSwapChain];
1777 IWineD3DSwapChain_AddRef(*pSwapChain);
1778 TRACE("(%p) returning %p\n", This, *pSwapChain);
1779 return WINED3D_OK;
1780 } else {
1781 TRACE("Swapchain out of range\n");
1782 *pSwapChain = NULL;
1783 return WINED3DERR_INVALIDCALL;
1787 /*****
1788 * Vertex Declaration
1789 *****/
1790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1792 IWineD3DVertexDeclarationImpl *object = NULL;
1793 HRESULT hr = WINED3D_OK;
1794 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1795 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1796 object->allFVF = 0;
1798 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1800 return hr;
1803 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1804 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1806 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1807 HRESULT hr = WINED3D_OK;
1808 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1809 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1811 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1813 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1814 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1815 if (pDeclaration != NULL) {
1816 IWineD3DVertexDeclaration *vertexDeclaration;
1817 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1818 if (WINED3D_OK == hr) {
1819 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1820 object->vertexDeclaration = vertexDeclaration;
1821 } else {
1822 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1823 IWineD3DVertexShader_Release(*ppVertexShader);
1824 return WINED3DERR_INVALIDCALL;
1828 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1830 if (WINED3D_OK != hr) {
1831 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1832 IWineD3DVertexShader_Release(*ppVertexShader);
1833 return WINED3DERR_INVALIDCALL;
1836 #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. */
1837 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1838 /* Foo */
1839 } else {
1840 /* Bar */
1843 #endif
1845 return WINED3D_OK;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1850 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1851 HRESULT hr = WINED3D_OK;
1853 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1854 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1855 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1856 if (WINED3D_OK == hr) {
1857 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1858 } else {
1859 WARN("(%p) : Failed to create pixel shader\n", This);
1862 return hr;
1865 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1867 IWineD3DPaletteImpl *object;
1868 HRESULT hr;
1869 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1871 /* Create the new object */
1872 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1873 if(!object) {
1874 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1875 return E_OUTOFMEMORY;
1878 object->lpVtbl = &IWineD3DPalette_Vtbl;
1879 object->ref = 1;
1880 object->Flags = Flags;
1881 object->parent = Parent;
1882 object->wineD3DDevice = This;
1883 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1885 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1887 if(!object->hpal) {
1888 HeapFree( GetProcessHeap(), 0, object);
1889 return E_OUTOFMEMORY;
1892 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1893 if(FAILED(hr)) {
1894 IWineD3DPalette_Release((IWineD3DPalette *) object);
1895 return hr;
1898 *Palette = (IWineD3DPalette *) object;
1900 return WINED3D_OK;
1903 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1905 IWineD3DSwapChainImpl *swapchain;
1907 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1908 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1910 /* TODO: Test if OpenGL is compiled in and loaded */
1912 /* Setup the implicit swapchain */
1913 TRACE("Creating implicit swapchain\n");
1914 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
1915 WARN("Failed to create implicit swapchain\n");
1916 return WINED3DERR_INVALIDCALL;
1919 This->NumberOfSwapChains = 1;
1920 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1921 if(!This->swapchains) {
1922 ERR("Out of memory!\n");
1923 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1924 return E_OUTOFMEMORY;
1926 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1928 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1929 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1930 This->renderTarget = swapchain->backBuffer[0];
1932 else {
1933 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1934 This->renderTarget = swapchain->frontBuffer;
1936 IWineD3DSurface_AddRef(This->renderTarget);
1937 /* Depth Stencil support */
1938 This->stencilBufferTarget = This->depthStencilBuffer;
1939 if (NULL != This->stencilBufferTarget) {
1940 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1943 /* Set up some starting GL setup */
1944 ENTER_GL();
1946 * Initialize openGL extension related variables
1947 * with Default values
1950 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( &((IWineD3DImpl *) This->wineD3D)->gl_info, swapchain->display);
1951 /* Setup all the devices defaults */
1952 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1953 #if 0
1954 IWineD3DImpl_CheckGraphicsMemory();
1955 #endif
1956 LEAVE_GL();
1958 /* Initialize our list of GLSL programs */
1959 list_init(&This->glsl_shader_progs);
1961 { /* Set a default viewport */
1962 D3DVIEWPORT9 vp;
1963 vp.X = 0;
1964 vp.Y = 0;
1965 vp.Width = *(pPresentationParameters->BackBufferWidth);
1966 vp.Height = *(pPresentationParameters->BackBufferHeight);
1967 vp.MinZ = 0.0f;
1968 vp.MaxZ = 1.0f;
1969 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1972 /* Initialize the current view state */
1973 This->modelview_valid = 1;
1974 This->proj_valid = 0;
1975 This->view_ident = 1;
1976 This->last_was_rhw = 0;
1977 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1978 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1980 /* Clear the screen */
1981 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
1983 This->d3d_initialized = TRUE;
1984 return WINED3D_OK;
1987 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
1988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1989 int texstage;
1990 IUnknown* stencilBufferParent;
1991 IUnknown* swapChainParent;
1992 uint i;
1993 TRACE("(%p)\n", This);
1995 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1997 for(texstage = 0; texstage < GL_LIMITS(textures); texstage++) {
1998 IWineD3DDevice_SetTexture(iface, texstage, NULL);
2001 /* Release the buffers (with sanity checks)*/
2002 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2003 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2004 if(This->depthStencilBuffer != This->stencilBufferTarget)
2005 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2007 This->stencilBufferTarget = NULL;
2009 TRACE("Releasing the render target at %p\n", This->renderTarget);
2010 if(IWineD3DSurface_Release(This->renderTarget) >0){
2011 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2013 TRACE("Setting rendertarget to NULL\n");
2014 This->renderTarget = NULL;
2016 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2017 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2018 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2019 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2021 This->depthStencilBuffer = NULL;
2023 for(i=0; i < This->NumberOfSwapChains; i++) {
2024 TRACE("Releasing the implicit swapchain %d\n", i);
2025 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2026 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2027 IUnknown_Release(swapChainParent); /* once for the get parent */
2028 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2029 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2033 HeapFree(GetProcessHeap(), 0, This->swapchains);
2034 This->swapchains = NULL;
2035 This->NumberOfSwapChains = 0;
2037 This->d3d_initialized = FALSE;
2038 return WINED3D_OK;
2041 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2044 DEVMODEW DevModeW;
2045 int i;
2047 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2049 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2050 /* Ignore some modes if a description was passed */
2051 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2052 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2053 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( D3DFmtGetBpp(NULL, pixelformat) != DevModeW.dmBitsPerPel) ) continue;
2055 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2057 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2058 return D3D_OK;
2061 return D3D_OK;
2064 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2065 DEVMODEW devmode;
2066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2067 LONG ret;
2069 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2071 /* Resize the screen even without a window:
2072 * The app could have unset it with SetCooperativeLevel, but not called
2073 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2074 * but we don't have any hwnd
2077 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2078 devmode.dmBitsPerPel = D3DFmtGetBpp(This, pMode->Format) * 8;
2079 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2080 devmode.dmPelsWidth = pMode->Width;
2081 devmode.dmPelsHeight = pMode->Height;
2083 devmode.dmDisplayFrequency = pMode->RefreshRate;
2084 if (pMode->RefreshRate != 0) {
2085 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2088 /* Only change the mode if necessary */
2089 if( (This->ddraw_width == pMode->Width) &&
2090 (This->ddraw_height == pMode->Height) &&
2091 (This->ddraw_format == pMode->Format) &&
2092 (pMode->RefreshRate == 0) ) {
2093 return D3D_OK;
2096 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2097 if (ret != DISP_CHANGE_SUCCESSFUL) {
2098 if(devmode.dmDisplayFrequency != 0) {
2099 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2100 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2101 devmode.dmDisplayFrequency = 0;
2102 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2104 if(ret != DISP_CHANGE_SUCCESSFUL) {
2105 return DDERR_INVALIDMODE;
2109 /* Store the new values */
2110 This->ddraw_width = pMode->Width;
2111 This->ddraw_height = pMode->Height;
2112 This->ddraw_format = pMode->Format;
2114 /* Only do this with a window of course */
2115 if(This->ddraw_window)
2116 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2118 return WINED3D_OK;
2121 static HRESULT WINAPI IWineD3DDeviceImpl_EnumZBufferFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2123 HRESULT ret;
2124 int i = 0;
2125 WINED3DFORMAT FormatList[] = {
2126 WINED3DFMT_D16,
2127 WINED3DFMT_D32,
2128 WINED3DFMT_D24X4S4,
2129 WINED3DFMT_D24S8,
2130 WINED3DFMT_D24X8,
2131 WINED3DFMT_D15S1,
2132 WINED3DFMT_UNKNOWN /* Terminate the list */
2135 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2137 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2138 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2139 ret = Callback((IUnknown *) This, FormatList[i], Context);
2140 if(ret != DDENUMRET_OK) {
2141 TRACE("Enumeration cancelled by Application\n");
2142 return WINED3D_OK;
2144 i++;
2147 TRACE("End of Enumeration\n");
2149 return WINED3D_OK;
2152 static HRESULT WINAPI IWineD3DDeviceImpl_EnumTextureFormats(IWineD3DDevice *iface, D3DCB_ENUMPIXELFORMATS Callback, void *Context) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2154 HRESULT ret;
2155 int i = 0;
2157 /* From old ddraw:
2158 * WINED3DFMT_A1R5G5B5 needs to be the first 16 bit format, as some dumb apps depend on this
2160 * Do not enumerate RGBA pixel formats: "some games choose the first 16 bit texture format
2161 * with alpha they find enumerated, others the last one. And both want to have the ARGB one."
2162 * But WineD3D doesn't support RGBA formats anyway...
2165 WINED3DFORMAT FormatList[] = {
2166 /* 32 bit */
2167 WINED3DFMT_A8R8G8B8,
2168 WINED3DFMT_X8R8G8B8,
2169 /* 24 bit */
2170 WINED3DFMT_R8G8B8,
2171 /* 16 Bit */
2172 WINED3DFMT_A1R5G5B5,
2173 WINED3DFMT_A4R4G4B4,
2174 WINED3DFMT_R5G6B5,
2175 WINED3DFMT_X1R5G5B5,
2176 /* 8 Bit */
2177 WINED3DFMT_R3G3B2,
2178 WINED3DFMT_P8,
2179 /* FOURCC codes */
2180 WINED3DFMT_DXT1,
2181 WINED3DFMT_DXT3,
2182 WINED3DFMT_DXT5,
2183 /* Terminate the list */
2184 WINED3DFMT_UNKNOWN
2187 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
2189 while(FormatList[i] != WINED3DFMT_UNKNOWN) {
2190 TRACE("Enumerating %s\n", debug_d3dformat(FormatList[i]));
2191 ret = Callback((IUnknown *) This, FormatList[i], Context);
2192 if(ret != DDENUMRET_OK) {
2193 TRACE("Enumeration cancelled by Application\n");
2194 return WINED3D_OK;
2196 i++;
2199 TRACE("End of Enumeration\n");
2201 return WINED3D_OK;
2204 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2206 *ppD3D= This->wineD3D;
2207 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2208 IWineD3D_AddRef(*ppD3D);
2209 return WINED3D_OK;
2212 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2213 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2214 * Into the video ram as possible and seeing how many fit
2215 * you can also get the correct initial value from via X and ATI's driver
2216 *******************/
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 static BOOL showfixmes = TRUE;
2219 if (showfixmes) {
2220 FIXME("(%p) : stub, emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2221 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2222 showfixmes = FALSE;
2224 TRACE("(%p) : emulating %dMB for now, returning %dMB\n", This, (emulated_textureram/(1024*1024)),
2225 ((emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2226 /* videomemory is simulated videomemory + AGP memory left */
2227 return (emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2232 /*****
2233 * Get / Set FVF
2234 *****/
2235 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2237 HRESULT hr = WINED3D_OK;
2239 /* Update the current state block */
2240 This->updateStateBlock->fvf = fvf;
2241 This->updateStateBlock->changed.fvf = TRUE;
2242 This->updateStateBlock->set.fvf = TRUE;
2244 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2246 if (0 != fvf) {
2247 /* clear down the vertex declaration
2248 NOTE: Axis and Allies doesn't work properly otherwise
2249 (may be a stateblock problem though!)
2251 hr = IWineD3DDevice_SetVertexDeclaration(iface, NULL);
2254 return hr;
2258 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2261 *pfvf = This->stateBlock->fvf;
2262 return WINED3D_OK;
2265 /*****
2266 * Get / Set Stream Source
2267 *****/
2268 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2270 IWineD3DVertexBuffer *oldSrc;
2272 /**TODO: instance and index data, see
2273 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2275 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2276 **************/
2278 /* D3d9 only, but shouldn't hurt d3d8 */
2279 UINT streamFlags;
2281 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2282 if (streamFlags) {
2283 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2284 FIXME("stream index data not supported\n");
2286 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2287 FIXME("stream instance data not supported\n");
2291 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2293 if (StreamNumber >= MAX_STREAMS) {
2294 WARN("Stream out of range %d\n", StreamNumber);
2295 return WINED3DERR_INVALIDCALL;
2298 oldSrc = This->stateBlock->streamSource[StreamNumber];
2299 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2301 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2302 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2303 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2304 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2305 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2306 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2308 /* Handle recording of state blocks */
2309 if (This->isRecordingState) {
2310 TRACE("Recording... not performing anything\n");
2311 return WINED3D_OK;
2314 /* Not recording... */
2315 /* Need to do a getParent and pass the reffs up */
2316 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2317 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2318 so for now, just count internally */
2319 if (pStreamData != NULL) {
2320 IWineD3DVertexBuffer_AddRef(pStreamData);
2322 if (oldSrc != NULL) {
2323 IWineD3DVertexBuffer_Release(oldSrc);
2326 return WINED3D_OK;
2329 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 UINT streamFlags;
2333 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2334 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2337 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2338 if (streamFlags) {
2339 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2340 FIXME("stream index data not supported\n");
2342 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2343 FIXME("stream instance data not supported\n");
2347 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2349 if (StreamNumber >= MAX_STREAMS) {
2350 WARN("Stream out of range %d\n", StreamNumber);
2351 return WINED3DERR_INVALIDCALL;
2353 *pStream = This->stateBlock->streamSource[StreamNumber];
2354 *pStride = This->stateBlock->streamStride[StreamNumber];
2355 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2357 if (*pStream == NULL) {
2358 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2359 return WINED3DERR_INVALIDCALL;
2362 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2363 return WINED3D_OK;
2366 /*Should be quite easy, just an extension of vertexdata
2367 ref...
2368 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2370 The divider is a bit odd though
2372 VertexOffset = StartVertex / Divider * StreamStride +
2373 VertexIndex / Divider * StreamStride + StreamOffset
2376 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2380 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2382 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2383 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2384 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2386 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2387 FIXME("Stream indexing not fully supported\n");
2390 return WINED3D_OK;
2393 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2396 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2397 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2399 TRACE("(%p) : returning %d\n", This, *Divider);
2401 return WINED3D_OK;
2404 /*****
2405 * Get / Set & Multiply Transform
2406 *****/
2407 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2410 /* Most of this routine, comments included copied from ddraw tree initially: */
2411 TRACE("(%p) : Transform State=%d\n", This, d3dts);
2413 /* Handle recording of state blocks */
2414 if (This->isRecordingState) {
2415 TRACE("Recording... not performing anything\n");
2416 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2417 This->updateStateBlock->set.transform[d3dts] = TRUE;
2418 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2419 return WINED3D_OK;
2423 * If the new matrix is the same as the current one,
2424 * we cut off any further processing. this seems to be a reasonable
2425 * optimization because as was noticed, some apps (warcraft3 for example)
2426 * tend towards setting the same matrix repeatedly for some reason.
2428 * From here on we assume that the new matrix is different, wherever it matters.
2430 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2431 TRACE("The app is setting the same matrix over again\n");
2432 return WINED3D_OK;
2433 } else {
2434 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2438 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2439 where ViewMat = Camera space, WorldMat = world space.
2441 In OpenGL, camera and world space is combined into GL_MODELVIEW
2442 matrix. The Projection matrix stay projection matrix.
2445 /* Capture the times we can just ignore the change for now */
2446 if (d3dts == D3DTS_WORLDMATRIX(0)) {
2447 This->modelview_valid = FALSE;
2448 return WINED3D_OK;
2450 } else if (d3dts == D3DTS_PROJECTION) {
2451 This->proj_valid = FALSE;
2452 return WINED3D_OK;
2454 } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) {
2455 /* Indexed Vertex Blending Matrices 256 -> 511 */
2456 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2457 FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n");
2458 return WINED3D_OK;
2461 /* Now we really are going to have to change a matrix */
2462 ENTER_GL();
2464 if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */
2465 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2466 } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */
2467 unsigned int k;
2469 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2470 * NOTE: We have to reset the positions even if the light/plane is not currently
2471 * enabled, since the call to enable it will not reset the position.
2472 * NOTE2: Apparently texture transforms do NOT need reapplying
2475 PLIGHTINFOEL *lightChain = NULL;
2476 This->modelview_valid = FALSE;
2477 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2479 glMatrixMode(GL_MODELVIEW);
2480 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2481 glPushMatrix();
2482 glLoadMatrixf((float *)lpmatrix);
2483 checkGLcall("glLoadMatrixf(...)");
2485 /* Reset lights */
2486 lightChain = This->stateBlock->lights;
2487 while (lightChain && lightChain->glIndex != -1) {
2488 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2489 checkGLcall("glLightfv posn");
2490 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2491 checkGLcall("glLightfv dirn");
2492 lightChain = lightChain->next;
2495 /* Reset Clipping Planes if clipping is enabled */
2496 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2497 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2498 checkGLcall("glClipPlane");
2500 glPopMatrix();
2502 } else { /* What was requested!?? */
2503 WARN("invalid matrix specified: %i\n", d3dts);
2506 /* Release lock, all done */
2507 LEAVE_GL();
2508 return WINED3D_OK;
2511 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 TRACE("(%p) : for Transform State %d\n", This, State);
2514 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2515 return WINED3D_OK;
2518 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2519 D3DMATRIX *mat = NULL;
2520 D3DMATRIX temp;
2522 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2523 * below means it will be recorded in a state block change, but it
2524 * works regardless where it is recorded.
2525 * If this is found to be wrong, change to StateBlock.
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 TRACE("(%p) : For state %u\n", This, State);
2530 if (State < HIGHEST_TRANSFORMSTATE)
2532 mat = &This->updateStateBlock->transforms[State];
2533 } else {
2534 FIXME("Unhandled transform state!!\n");
2537 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2539 /* Apply change via set transform - will reapply to eg. lights this way */
2540 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2543 /*****
2544 * Get / Set Light
2545 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2546 *****/
2547 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2548 you can reference any indexes you want as long as that number max are enabled at any
2549 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2550 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2551 but when recording, just build a chain pretty much of commands to be replayed. */
2553 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2554 float rho;
2555 PLIGHTINFOEL *object, *temp;
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2560 /* If recording state block, just add to end of lights chain */
2561 if (This->isRecordingState) {
2562 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2563 if (NULL == object) {
2564 return WINED3DERR_OUTOFVIDEOMEMORY;
2566 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2567 object->OriginalIndex = Index;
2568 object->glIndex = -1;
2569 object->changed = TRUE;
2571 /* Add to the END of the chain of lights changes to be replayed */
2572 if (This->updateStateBlock->lights == NULL) {
2573 This->updateStateBlock->lights = object;
2574 } else {
2575 temp = This->updateStateBlock->lights;
2576 while (temp->next != NULL) temp=temp->next;
2577 temp->next = object;
2579 TRACE("Recording... not performing anything more\n");
2580 return WINED3D_OK;
2583 /* Ok, not recording any longer so do real work */
2584 object = This->stateBlock->lights;
2585 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2587 /* If we didn't find it in the list of lights, time to add it */
2588 if (object == NULL) {
2589 PLIGHTINFOEL *insertAt,*prevPos;
2591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2592 if (NULL == object) {
2593 return WINED3DERR_OUTOFVIDEOMEMORY;
2595 object->OriginalIndex = Index;
2596 object->glIndex = -1;
2598 /* Add it to the front of list with the idea that lights will be changed as needed
2599 BUT after any lights currently assigned GL indexes */
2600 insertAt = This->stateBlock->lights;
2601 prevPos = NULL;
2602 while (insertAt != NULL && insertAt->glIndex != -1) {
2603 prevPos = insertAt;
2604 insertAt = insertAt->next;
2607 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2608 This->stateBlock->lights = object;
2609 } else if (insertAt == NULL) { /* End of list */
2610 prevPos->next = object;
2611 object->prev = prevPos;
2612 } else { /* Middle of chain */
2613 if (prevPos == NULL) {
2614 This->stateBlock->lights = object;
2615 } else {
2616 prevPos->next = object;
2618 object->prev = prevPos;
2619 object->next = insertAt;
2620 insertAt->prev = object;
2624 /* Initialize the object */
2625 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,
2626 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2627 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2628 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2629 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2630 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2631 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2633 /* Save away the information */
2634 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2636 switch (pLight->Type) {
2637 case D3DLIGHT_POINT:
2638 /* Position */
2639 object->lightPosn[0] = pLight->Position.x;
2640 object->lightPosn[1] = pLight->Position.y;
2641 object->lightPosn[2] = pLight->Position.z;
2642 object->lightPosn[3] = 1.0f;
2643 object->cutoff = 180.0f;
2644 /* FIXME: Range */
2645 break;
2647 case D3DLIGHT_DIRECTIONAL:
2648 /* Direction */
2649 object->lightPosn[0] = -pLight->Direction.x;
2650 object->lightPosn[1] = -pLight->Direction.y;
2651 object->lightPosn[2] = -pLight->Direction.z;
2652 object->lightPosn[3] = 0.0;
2653 object->exponent = 0.0f;
2654 object->cutoff = 180.0f;
2655 break;
2657 case D3DLIGHT_SPOT:
2658 /* Position */
2659 object->lightPosn[0] = pLight->Position.x;
2660 object->lightPosn[1] = pLight->Position.y;
2661 object->lightPosn[2] = pLight->Position.z;
2662 object->lightPosn[3] = 1.0;
2664 /* Direction */
2665 object->lightDirn[0] = pLight->Direction.x;
2666 object->lightDirn[1] = pLight->Direction.y;
2667 object->lightDirn[2] = pLight->Direction.z;
2668 object->lightDirn[3] = 1.0;
2671 * opengl-ish and d3d-ish spot lights use too different models for the
2672 * light "intensity" as a function of the angle towards the main light direction,
2673 * so we only can approximate very roughly.
2674 * however spot lights are rather rarely used in games (if ever used at all).
2675 * furthermore if still used, probably nobody pays attention to such details.
2677 if (pLight->Falloff == 0) {
2678 rho = 6.28f;
2679 } else {
2680 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2682 if (rho < 0.0001) rho = 0.0001f;
2683 object->exponent = -0.3/log(cos(rho/2));
2684 object->cutoff = pLight->Phi*90/M_PI;
2686 /* FIXME: Range */
2687 break;
2689 default:
2690 FIXME("Unrecognized light type %d\n", pLight->Type);
2693 /* Update the live definitions if the light is currently assigned a glIndex */
2694 if (object->glIndex != -1) {
2695 setup_light(iface, object->glIndex, object);
2697 return WINED3D_OK;
2700 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2701 PLIGHTINFOEL *lightInfo = NULL;
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2705 /* Locate the light in the live lights */
2706 lightInfo = This->stateBlock->lights;
2707 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2709 if (lightInfo == NULL) {
2710 TRACE("Light information requested but light not defined\n");
2711 return WINED3DERR_INVALIDCALL;
2714 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2715 return WINED3D_OK;
2718 /*****
2719 * Get / Set Light Enable
2720 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2721 *****/
2722 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2723 PLIGHTINFOEL *lightInfo = NULL;
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2727 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2728 if (This->isRecordingState) {
2729 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2730 if (NULL == lightInfo) {
2731 return WINED3DERR_OUTOFVIDEOMEMORY;
2733 lightInfo->OriginalIndex = Index;
2734 lightInfo->glIndex = -1;
2735 lightInfo->enabledChanged = TRUE;
2737 /* Add to the END of the chain of lights changes to be replayed */
2738 if (This->updateStateBlock->lights == NULL) {
2739 This->updateStateBlock->lights = lightInfo;
2740 } else {
2741 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2742 while (temp->next != NULL) temp=temp->next;
2743 temp->next = lightInfo;
2745 TRACE("Recording... not performing anything more\n");
2746 return WINED3D_OK;
2749 /* Not recording... So, locate the light in the live lights */
2750 lightInfo = This->stateBlock->lights;
2751 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2753 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2754 if (lightInfo == NULL) {
2756 TRACE("Light enabled requested but light not defined, so defining one!\n");
2757 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2759 /* Search for it again! Should be fairly quick as near head of list */
2760 lightInfo = This->stateBlock->lights;
2761 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2762 if (lightInfo == NULL) {
2763 FIXME("Adding default lights has failed dismally\n");
2764 return WINED3DERR_INVALIDCALL;
2768 /* OK, we now have a light... */
2769 if (Enable == FALSE) {
2771 /* If we are disabling it, check it was enabled, and
2772 still only do something if it has assigned a glIndex (which it should have!) */
2773 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2774 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2775 ENTER_GL();
2776 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2777 checkGLcall("glDisable GL_LIGHT0+Index");
2778 LEAVE_GL();
2779 } else {
2780 TRACE("Nothing to do as light was not enabled\n");
2782 lightInfo->lightEnabled = FALSE;
2783 } else {
2785 /* We are enabling it. If it is enabled, it's really simple */
2786 if (lightInfo->lightEnabled) {
2787 /* nop */
2788 TRACE("Nothing to do as light was enabled\n");
2790 /* If it already has a glIndex, it's still simple */
2791 } else if (lightInfo->glIndex != -1) {
2792 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2793 lightInfo->lightEnabled = TRUE;
2794 ENTER_GL();
2795 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2796 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2797 LEAVE_GL();
2799 /* Otherwise got to find space - lights are ordered gl indexes first */
2800 } else {
2801 PLIGHTINFOEL *bsf = NULL;
2802 PLIGHTINFOEL *pos = This->stateBlock->lights;
2803 PLIGHTINFOEL *prev = NULL;
2804 int Index= 0;
2805 int glIndex = -1;
2807 /* Try to minimize changes as much as possible */
2808 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2810 /* Try to remember which index can be replaced if necessary */
2811 if (bsf==NULL && pos->lightEnabled == FALSE) {
2812 /* Found a light we can replace, save as best replacement */
2813 bsf = pos;
2816 /* Step to next space */
2817 prev = pos;
2818 pos = pos->next;
2819 Index ++;
2822 /* If we have too many active lights, fail the call */
2823 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2824 FIXME("Program requests too many concurrent lights\n");
2825 return WINED3DERR_INVALIDCALL;
2827 /* If we have allocated all lights, but not all are enabled,
2828 reuse one which is not enabled */
2829 } else if (Index == This->maxConcurrentLights) {
2830 /* use bsf - Simply swap the new light and the BSF one */
2831 PLIGHTINFOEL *bsfNext = bsf->next;
2832 PLIGHTINFOEL *bsfPrev = bsf->prev;
2834 /* Sort out ends */
2835 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2836 if (bsf->prev != NULL) {
2837 bsf->prev->next = lightInfo;
2838 } else {
2839 This->stateBlock->lights = lightInfo;
2842 /* If not side by side, lots of chains to update */
2843 if (bsf->next != lightInfo) {
2844 lightInfo->prev->next = bsf;
2845 bsf->next->prev = lightInfo;
2846 bsf->next = lightInfo->next;
2847 bsf->prev = lightInfo->prev;
2848 lightInfo->next = bsfNext;
2849 lightInfo->prev = bsfPrev;
2851 } else {
2852 /* Simple swaps */
2853 bsf->prev = lightInfo;
2854 bsf->next = lightInfo->next;
2855 lightInfo->next = bsf;
2856 lightInfo->prev = bsfPrev;
2860 /* Update states */
2861 glIndex = bsf->glIndex;
2862 bsf->glIndex = -1;
2863 lightInfo->glIndex = glIndex;
2864 lightInfo->lightEnabled = TRUE;
2866 /* Finally set up the light in gl itself */
2867 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2868 ENTER_GL();
2869 setup_light(iface, glIndex, lightInfo);
2870 glEnable(GL_LIGHT0 + glIndex);
2871 checkGLcall("glEnable GL_LIGHT0 new setup");
2872 LEAVE_GL();
2874 /* If we reached the end of the allocated lights, with space in the
2875 gl lights, setup a new light */
2876 } else if (pos->glIndex == -1) {
2878 /* We reached the end of the allocated gl lights, so already
2879 know the index of the next one! */
2880 glIndex = Index;
2881 lightInfo->glIndex = glIndex;
2882 lightInfo->lightEnabled = TRUE;
2884 /* In an ideal world, it's already in the right place */
2885 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2886 /* No need to move it */
2887 } else {
2888 /* Remove this light from the list */
2889 lightInfo->prev->next = lightInfo->next;
2890 if (lightInfo->next != NULL) {
2891 lightInfo->next->prev = lightInfo->prev;
2894 /* Add in at appropriate place (inbetween prev and pos) */
2895 lightInfo->prev = prev;
2896 lightInfo->next = pos;
2897 if (prev == NULL) {
2898 This->stateBlock->lights = lightInfo;
2899 } else {
2900 prev->next = lightInfo;
2902 if (pos != NULL) {
2903 pos->prev = lightInfo;
2907 /* Finally set up the light in gl itself */
2908 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
2909 ENTER_GL();
2910 setup_light(iface, glIndex, lightInfo);
2911 glEnable(GL_LIGHT0 + glIndex);
2912 checkGLcall("glEnable GL_LIGHT0 new setup");
2913 LEAVE_GL();
2918 return WINED3D_OK;
2921 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2923 PLIGHTINFOEL *lightInfo = NULL;
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2925 TRACE("(%p) : for idx(%ld)\n", This, Index);
2927 /* Locate the light in the live lights */
2928 lightInfo = This->stateBlock->lights;
2929 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2931 if (lightInfo == NULL) {
2932 TRACE("Light enabled state requested but light not defined\n");
2933 return WINED3DERR_INVALIDCALL;
2935 *pEnable = lightInfo->lightEnabled;
2936 return WINED3D_OK;
2939 /*****
2940 * Get / Set Clip Planes
2941 *****/
2942 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2944 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
2946 /* Validate Index */
2947 if (Index >= GL_LIMITS(clipplanes)) {
2948 TRACE("Application has requested clipplane this device doesn't support\n");
2949 return WINED3DERR_INVALIDCALL;
2952 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2953 This->updateStateBlock->set.clipplane[Index] = TRUE;
2954 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2955 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2956 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2957 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2959 /* Handle recording of state blocks */
2960 if (This->isRecordingState) {
2961 TRACE("Recording... not performing anything\n");
2962 return WINED3D_OK;
2965 /* Apply it */
2967 ENTER_GL();
2969 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2970 glMatrixMode(GL_MODELVIEW);
2971 glPushMatrix();
2972 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
2974 TRACE("Clipplane [%f,%f,%f,%f]\n",
2975 This->updateStateBlock->clipplane[Index][0],
2976 This->updateStateBlock->clipplane[Index][1],
2977 This->updateStateBlock->clipplane[Index][2],
2978 This->updateStateBlock->clipplane[Index][3]);
2979 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2980 checkGLcall("glClipPlane");
2982 glPopMatrix();
2983 LEAVE_GL();
2985 return WINED3D_OK;
2988 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 TRACE("(%p) : for idx %ld\n", This, Index);
2992 /* Validate Index */
2993 if (Index >= GL_LIMITS(clipplanes)) {
2994 TRACE("Application has requested clipplane this device doesn't support\n");
2995 return WINED3DERR_INVALIDCALL;
2998 pPlane[0] = This->stateBlock->clipplane[Index][0];
2999 pPlane[1] = This->stateBlock->clipplane[Index][1];
3000 pPlane[2] = This->stateBlock->clipplane[Index][2];
3001 pPlane[3] = This->stateBlock->clipplane[Index][3];
3002 return WINED3D_OK;
3005 /*****
3006 * Get / Set Clip Plane Status
3007 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3008 *****/
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 FIXME("(%p) : stub\n", This);
3012 if (NULL == pClipStatus) {
3013 return WINED3DERR_INVALIDCALL;
3015 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3016 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3017 return WINED3D_OK;
3020 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 FIXME("(%p) : stub\n", This);
3023 if (NULL == pClipStatus) {
3024 return WINED3DERR_INVALIDCALL;
3026 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3027 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3028 return WINED3D_OK;
3031 /*****
3032 * Get / Set Material
3033 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3034 *****/
3035 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 This->updateStateBlock->changed.material = TRUE;
3039 This->updateStateBlock->set.material = TRUE;
3040 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3042 /* Handle recording of state blocks */
3043 if (This->isRecordingState) {
3044 TRACE("Recording... not performing anything\n");
3045 return WINED3D_OK;
3048 ENTER_GL();
3049 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3050 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3051 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3052 pMaterial->Ambient.b, pMaterial->Ambient.a);
3053 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3054 pMaterial->Specular.b, pMaterial->Specular.a);
3055 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3056 pMaterial->Emissive.b, pMaterial->Emissive.a);
3057 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3059 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3060 checkGLcall("glMaterialfv(GL_AMBIENT)");
3061 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3062 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3064 /* Only change material color if specular is enabled, otherwise it is set to black */
3065 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3066 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3067 checkGLcall("glMaterialfv(GL_SPECULAR");
3068 } else {
3069 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3070 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3071 checkGLcall("glMaterialfv(GL_SPECULAR");
3073 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3074 checkGLcall("glMaterialfv(GL_EMISSION)");
3075 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3076 checkGLcall("glMaterialf(GL_SHININESS");
3078 LEAVE_GL();
3079 return WINED3D_OK;
3082 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3085 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3086 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3087 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3088 pMaterial->Ambient.b, pMaterial->Ambient.a);
3089 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3090 pMaterial->Specular.b, pMaterial->Specular.a);
3091 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3092 pMaterial->Emissive.b, pMaterial->Emissive.a);
3093 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3095 return WINED3D_OK;
3098 /*****
3099 * Get / Set Indices
3100 *****/
3101 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3102 UINT BaseVertexIndex) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 IWineD3DIndexBuffer *oldIdxs;
3106 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3107 oldIdxs = This->updateStateBlock->pIndexData;
3109 This->updateStateBlock->changed.indices = TRUE;
3110 This->updateStateBlock->set.indices = TRUE;
3111 This->updateStateBlock->pIndexData = pIndexData;
3112 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3114 /* Handle recording of state blocks */
3115 if (This->isRecordingState) {
3116 TRACE("Recording... not performing anything\n");
3117 return WINED3D_OK;
3120 if (NULL != pIndexData) {
3121 IWineD3DIndexBuffer_AddRef(pIndexData);
3123 if (NULL != oldIdxs) {
3124 IWineD3DIndexBuffer_Release(oldIdxs);
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 *ppIndexData = This->stateBlock->pIndexData;
3134 /* up ref count on ppindexdata */
3135 if (*ppIndexData) {
3136 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3137 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3138 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3139 }else{
3140 TRACE("(%p) No index data set\n", This);
3142 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3144 return WINED3D_OK;
3147 /*****
3148 * Get / Set Viewports
3149 *****/
3150 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 TRACE("(%p)\n", This);
3154 This->updateStateBlock->changed.viewport = TRUE;
3155 This->updateStateBlock->set.viewport = TRUE;
3156 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3158 /* Handle recording of state blocks */
3159 if (This->isRecordingState) {
3160 TRACE("Recording... not performing anything\n");
3161 return WINED3D_OK;
3163 This->viewport_changed = TRUE;
3165 ENTER_GL();
3167 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3168 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3170 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3171 checkGLcall("glDepthRange");
3172 /* Note: GL requires lower left, DirectX supplies upper left */
3173 /* TODO: replace usage of renderTarget with context management */
3174 glViewport(pViewport->X,
3175 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3176 pViewport->Width, pViewport->Height);
3178 checkGLcall("glViewport");
3180 LEAVE_GL();
3182 return WINED3D_OK;
3186 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 TRACE("(%p)\n", This);
3189 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3190 return WINED3D_OK;
3193 static void renderstate_stencil_twosided(
3194 IWineD3DDeviceImpl *This,
3195 GLint face,
3196 GLint func,
3197 GLint ref,
3198 GLuint mask,
3199 GLint stencilFail,
3200 GLint depthFail,
3201 GLint stencilPass ) {
3202 #if 0 /* Don't use OpenGL 2.0 calls for now */
3203 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3204 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3205 checkGLcall("glStencilFuncSeparate(...)");
3206 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3207 checkGLcall("glStencilOpSeparate(...)");
3209 else
3210 #endif
3211 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3212 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3213 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3214 GL_EXTCALL(glActiveStencilFaceEXT(face));
3215 checkGLcall("glActiveStencilFaceEXT(...)");
3216 glStencilFunc(func, ref, mask);
3217 checkGLcall("glStencilFunc(...)");
3218 glStencilOp(stencilFail, depthFail, stencilPass);
3219 checkGLcall("glStencilOp(...)");
3220 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3221 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3222 checkGLcall("glStencilFuncSeparateATI(...)");
3223 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3224 checkGLcall("glStencilOpSeparateATI(...)");
3225 } else {
3226 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3230 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3231 DWORD onesided_enable = FALSE;
3232 DWORD twosided_enable = FALSE;
3233 GLint func = GL_ALWAYS;
3234 GLint func_ccw = GL_ALWAYS;
3235 GLint ref = 0;
3236 GLuint mask = 0;
3237 GLint stencilFail = GL_KEEP;
3238 GLint depthFail = GL_KEEP;
3239 GLint stencilPass = GL_KEEP;
3240 GLint stencilFail_ccw = GL_KEEP;
3241 GLint depthFail_ccw = GL_KEEP;
3242 GLint stencilPass_ccw = GL_KEEP;
3244 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3245 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3246 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3247 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3248 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3249 func = StencilFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]);
3250 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3251 func_ccw = StencilFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]);
3252 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3253 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3254 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3255 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3256 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3257 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3258 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3259 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3260 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3261 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3262 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3263 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3264 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3265 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3266 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3267 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3269 switch(State) {
3270 case WINED3DRS_STENCILENABLE :
3271 onesided_enable = Value;
3272 break;
3273 case WINED3DRS_TWOSIDEDSTENCILMODE :
3274 twosided_enable = Value;
3275 break;
3276 case WINED3DRS_STENCILFUNC :
3277 func = StencilFunc(Value);
3278 break;
3279 case WINED3DRS_CCW_STENCILFUNC :
3280 func_ccw = StencilFunc(Value);
3281 break;
3282 case WINED3DRS_STENCILREF :
3283 ref = Value;
3284 break;
3285 case WINED3DRS_STENCILMASK :
3286 mask = Value;
3287 break;
3288 case WINED3DRS_STENCILFAIL :
3289 stencilFail = StencilOp(Value);
3290 break;
3291 case WINED3DRS_STENCILZFAIL :
3292 depthFail = StencilOp(Value);
3293 break;
3294 case WINED3DRS_STENCILPASS :
3295 stencilPass = StencilOp(Value);
3296 break;
3297 case WINED3DRS_CCW_STENCILFAIL :
3298 stencilFail_ccw = StencilOp(Value);
3299 break;
3300 case WINED3DRS_CCW_STENCILZFAIL :
3301 depthFail_ccw = StencilOp(Value);
3302 break;
3303 case WINED3DRS_CCW_STENCILPASS :
3304 stencilPass_ccw = StencilOp(Value);
3305 break;
3306 default :
3307 ERR("This should not happen!");
3310 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3311 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3312 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3313 onesided_enable, twosided_enable, ref, mask,
3314 func, stencilFail, depthFail, stencilPass,
3315 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3317 if (twosided_enable) {
3318 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3319 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3320 } else {
3321 if (onesided_enable) {
3322 glEnable(GL_STENCIL_TEST);
3323 checkGLcall("glEnable GL_STENCIL_TEST");
3324 glStencilFunc(func, ref, mask);
3325 checkGLcall("glStencilFunc(...)");
3326 glStencilOp(stencilFail, depthFail, stencilPass);
3327 checkGLcall("glStencilOp(...)");
3328 } else {
3329 glDisable(GL_STENCIL_TEST);
3330 checkGLcall("glDisable GL_STENCIL_TEST");
3335 /*****
3336 * Get / Set Render States
3337 * TODO: Verify against dx9 definitions
3338 *****/
3339 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342 DWORD OldValue = This->stateBlock->renderState[State];
3344 /* Simple way of referring to either a DWORD or a 4 byte float */
3345 union {
3346 DWORD d;
3347 float f;
3348 } tmpvalue;
3350 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3351 This->updateStateBlock->changed.renderState[State] = TRUE;
3352 This->updateStateBlock->set.renderState[State] = TRUE;
3353 This->updateStateBlock->renderState[State] = Value;
3355 /* Handle recording of state blocks */
3356 if (This->isRecordingState) {
3357 TRACE("Recording... not performing anything\n");
3358 return WINED3D_OK;
3361 ENTER_GL();
3363 switch (State) {
3364 case WINED3DRS_FILLMODE :
3365 switch ((D3DFILLMODE) Value) {
3366 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3367 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3368 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3369 default:
3370 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3372 checkGLcall("glPolygonMode (fillmode)");
3373 break;
3375 case WINED3DRS_LIGHTING :
3376 if (Value) {
3377 glEnable(GL_LIGHTING);
3378 checkGLcall("glEnable GL_LIGHTING");
3379 } else {
3380 glDisable(GL_LIGHTING);
3381 checkGLcall("glDisable GL_LIGHTING");
3383 break;
3385 case WINED3DRS_ZENABLE :
3386 switch ((D3DZBUFFERTYPE) Value) {
3387 case D3DZB_FALSE:
3388 glDisable(GL_DEPTH_TEST);
3389 checkGLcall("glDisable GL_DEPTH_TEST");
3390 break;
3391 case D3DZB_TRUE:
3392 glEnable(GL_DEPTH_TEST);
3393 checkGLcall("glEnable GL_DEPTH_TEST");
3394 break;
3395 case D3DZB_USEW:
3396 glEnable(GL_DEPTH_TEST);
3397 checkGLcall("glEnable GL_DEPTH_TEST");
3398 FIXME("W buffer is not well handled\n");
3399 break;
3400 default:
3401 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3403 break;
3405 case WINED3DRS_CULLMODE :
3407 /* If we are culling "back faces with clockwise vertices" then
3408 set front faces to be counter clockwise and enable culling
3409 of back faces */
3410 switch ((D3DCULL) Value) {
3411 case D3DCULL_NONE:
3412 glDisable(GL_CULL_FACE);
3413 checkGLcall("glDisable GL_CULL_FACE");
3414 break;
3415 case D3DCULL_CW:
3416 glEnable(GL_CULL_FACE);
3417 checkGLcall("glEnable GL_CULL_FACE");
3418 if (This->renderUpsideDown) {
3419 glFrontFace(GL_CW);
3420 checkGLcall("glFrontFace GL_CW");
3421 } else {
3422 glFrontFace(GL_CCW);
3423 checkGLcall("glFrontFace GL_CCW");
3425 glCullFace(GL_BACK);
3426 break;
3427 case D3DCULL_CCW:
3428 glEnable(GL_CULL_FACE);
3429 checkGLcall("glEnable GL_CULL_FACE");
3430 if (This->renderUpsideDown) {
3431 glFrontFace(GL_CCW);
3432 checkGLcall("glFrontFace GL_CCW");
3433 } else {
3434 glFrontFace(GL_CW);
3435 checkGLcall("glFrontFace GL_CW");
3437 glCullFace(GL_BACK);
3438 break;
3439 default:
3440 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3442 break;
3444 case WINED3DRS_SHADEMODE :
3445 switch ((D3DSHADEMODE) Value) {
3446 case D3DSHADE_FLAT:
3447 glShadeModel(GL_FLAT);
3448 checkGLcall("glShadeModel");
3449 break;
3450 case D3DSHADE_GOURAUD:
3451 glShadeModel(GL_SMOOTH);
3452 checkGLcall("glShadeModel");
3453 break;
3454 case D3DSHADE_PHONG:
3455 FIXME("D3DSHADE_PHONG isn't supported?\n");
3457 LEAVE_GL();
3458 return WINED3DERR_INVALIDCALL;
3459 default:
3460 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3462 break;
3464 case WINED3DRS_DITHERENABLE :
3465 if (Value) {
3466 glEnable(GL_DITHER);
3467 checkGLcall("glEnable GL_DITHER");
3468 } else {
3469 glDisable(GL_DITHER);
3470 checkGLcall("glDisable GL_DITHER");
3472 break;
3474 case WINED3DRS_ZWRITEENABLE :
3475 if (Value) {
3476 glDepthMask(1);
3477 checkGLcall("glDepthMask");
3478 } else {
3479 glDepthMask(0);
3480 checkGLcall("glDepthMask");
3482 break;
3484 case WINED3DRS_ZFUNC :
3486 int glParm = GL_LESS;
3488 switch ((D3DCMPFUNC) Value) {
3489 case D3DCMP_NEVER: glParm=GL_NEVER; break;
3490 case D3DCMP_LESS: glParm=GL_LESS; break;
3491 case D3DCMP_EQUAL: glParm=GL_EQUAL; break;
3492 case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break;
3493 case D3DCMP_GREATER: glParm=GL_GREATER; break;
3494 case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break;
3495 case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break;
3496 case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break;
3497 default:
3498 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3500 glDepthFunc(glParm);
3501 checkGLcall("glDepthFunc");
3503 break;
3505 case WINED3DRS_AMBIENT :
3507 float col[4];
3508 D3DCOLORTOGLFLOAT4(Value, col);
3509 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3510 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3511 checkGLcall("glLightModel for MODEL_AMBIENT");
3514 break;
3516 case WINED3DRS_ALPHABLENDENABLE :
3517 if (Value) {
3518 glEnable(GL_BLEND);
3519 checkGLcall("glEnable GL_BLEND");
3520 } else {
3521 glDisable(GL_BLEND);
3522 checkGLcall("glDisable GL_BLEND");
3524 break;
3526 case WINED3DRS_SRCBLEND :
3527 case WINED3DRS_DESTBLEND :
3529 int newVal = GL_ZERO;
3530 switch (Value) {
3531 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3532 case D3DBLEND_ONE : newVal = GL_ONE; break;
3533 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3534 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3535 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3536 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3537 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3538 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3539 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3540 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3541 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3543 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3544 This->srcBlend = newVal;
3545 This->dstBlend = newVal;
3546 break;
3548 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3549 This->srcBlend = newVal;
3550 This->dstBlend = newVal;
3551 break;
3552 default:
3553 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3556 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3557 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3558 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3559 glBlendFunc(This->srcBlend, This->dstBlend);
3561 checkGLcall("glBlendFunc");
3563 break;
3565 case WINED3DRS_ALPHATESTENABLE :
3566 case WINED3DRS_ALPHAFUNC :
3567 case WINED3DRS_ALPHAREF :
3568 case WINED3DRS_COLORKEYENABLE :
3570 int glParm = 0.0;
3571 float ref = GL_LESS;
3572 BOOL enable_ckey = FALSE;
3574 IWineD3DSurfaceImpl *surf;
3576 /* Find out if the texture on the first stage has a ckey set */
3577 if(This->stateBlock->textures[0]) {
3578 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3579 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3582 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3583 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3584 glEnable(GL_ALPHA_TEST);
3585 checkGLcall("glEnable GL_ALPHA_TEST");
3586 } else {
3587 glDisable(GL_ALPHA_TEST);
3588 checkGLcall("glDisable GL_ALPHA_TEST");
3589 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3590 * enable call
3592 break;
3595 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3596 glParm = GL_NOTEQUAL;
3597 ref = 0.0;
3598 } else {
3599 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3601 switch ((D3DCMPFUNC) This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]) {
3602 case D3DCMP_NEVER: glParm = GL_NEVER; break;
3603 case D3DCMP_LESS: glParm = GL_LESS; break;
3604 case D3DCMP_EQUAL: glParm = GL_EQUAL; break;
3605 case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break;
3606 case D3DCMP_GREATER: glParm = GL_GREATER; break;
3607 case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break;
3608 case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break;
3609 case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break;
3610 default:
3611 FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value);
3614 This->alphafunc = glParm;
3615 glAlphaFunc(glParm, ref);
3616 checkGLcall("glAlphaFunc");
3618 break;
3620 case WINED3DRS_CLIPPLANEENABLE :
3621 case WINED3DRS_CLIPPING :
3623 /* Ensure we only do the changed clip planes */
3624 DWORD enable = 0xFFFFFFFF;
3625 DWORD disable = 0x00000000;
3627 /* If enabling / disabling all */
3628 if (State == WINED3DRS_CLIPPING) {
3629 if (Value) {
3630 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3631 disable = 0x00;
3632 } else {
3633 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3634 enable = 0x00;
3636 } else {
3637 enable = Value & ~OldValue;
3638 disable = ~Value & OldValue;
3641 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3642 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3643 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3644 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3645 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3646 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3648 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3649 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3650 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3651 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3652 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3653 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3655 /** update clipping status */
3656 if (enable) {
3657 This->stateBlock->clip_status.ClipUnion = 0;
3658 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3659 } else {
3660 This->stateBlock->clip_status.ClipUnion = 0;
3661 This->stateBlock->clip_status.ClipIntersection = 0;
3664 break;
3666 case WINED3DRS_BLENDOP :
3668 int glParm = GL_FUNC_ADD;
3670 switch ((D3DBLENDOP) Value) {
3671 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3672 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3673 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3674 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3675 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3676 default:
3677 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3680 if(GL_SUPPORT(ARB_IMAGING)) {
3681 TRACE("glBlendEquation(%x)\n", glParm);
3682 GL_EXTCALL(glBlendEquation(glParm));
3683 checkGLcall("glBlendEquation");
3684 } else {
3685 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3688 break;
3690 case WINED3DRS_TEXTUREFACTOR :
3692 unsigned int i;
3694 /* Note the texture color applies to all textures whereas
3695 GL_TEXTURE_ENV_COLOR applies to active only */
3696 float col[4];
3697 D3DCOLORTOGLFLOAT4(Value, col);
3698 /* Set the default alpha blend color */
3699 if (GL_SUPPORT(ARB_IMAGING)) {
3700 GL_EXTCALL(glBlendColor(col[0], col[1], col[2], col[3]));
3701 checkGLcall("glBlendColor");
3702 } else {
3703 WARN("Unsupported in local OpenGL implementation: glBlendColor\n");
3706 /* And now the default texture color as well */
3707 for (i = 0; i < GL_LIMITS(textures); i++) {
3709 /* Note the D3DRS value applies to all textures, but GL has one
3710 per texture, so apply it now ready to be used! */
3711 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3712 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3713 checkGLcall("glActiveTextureARB");
3714 } else if (i>0) {
3715 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3718 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3719 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3722 break;
3724 case WINED3DRS_SPECULARENABLE :
3726 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3727 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3728 specular color. This is wrong:
3729 Separate specular color means the specular colour is maintained separately, whereas
3730 single color means it is merged in. However in both cases they are being used to
3731 some extent.
3732 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3733 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3734 running 1.4 yet!
3736 if (Value) {
3737 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3738 checkGLcall("glMaterialfv");
3739 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3740 glEnable(GL_COLOR_SUM_EXT);
3741 } else {
3742 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3744 checkGLcall("glEnable(GL_COLOR_SUM)");
3745 } else {
3746 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3748 /* for the case of enabled lighting: */
3749 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3750 checkGLcall("glMaterialfv");
3752 /* for the case of disabled lighting: */
3753 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3754 glDisable(GL_COLOR_SUM_EXT);
3755 } else {
3756 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3758 checkGLcall("glDisable(GL_COLOR_SUM)");
3761 break;
3763 case WINED3DRS_STENCILENABLE :
3764 case WINED3DRS_TWOSIDEDSTENCILMODE :
3765 case WINED3DRS_STENCILFUNC :
3766 case WINED3DRS_CCW_STENCILFUNC :
3767 case WINED3DRS_STENCILREF :
3768 case WINED3DRS_STENCILMASK :
3769 case WINED3DRS_STENCILFAIL :
3770 case WINED3DRS_STENCILZFAIL :
3771 case WINED3DRS_STENCILPASS :
3772 case WINED3DRS_CCW_STENCILFAIL :
3773 case WINED3DRS_CCW_STENCILZFAIL :
3774 case WINED3DRS_CCW_STENCILPASS :
3775 renderstate_stencil(This, State, Value);
3776 break;
3777 case WINED3DRS_STENCILWRITEMASK :
3779 glStencilMask(Value);
3780 TRACE("glStencilMask(%lu)\n", Value);
3781 checkGLcall("glStencilMask");
3783 break;
3785 case WINED3DRS_FOGENABLE :
3787 if (Value) {
3788 glEnable(GL_FOG);
3789 checkGLcall("glEnable GL_FOG");
3790 } else {
3791 glDisable(GL_FOG);
3792 checkGLcall("glDisable GL_FOG");
3795 break;
3797 case WINED3DRS_RANGEFOGENABLE :
3799 if (Value) {
3800 TRACE("Enabled RANGEFOG");
3801 } else {
3802 TRACE("Disabled RANGEFOG");
3805 break;
3807 case WINED3DRS_FOGCOLOR :
3809 float col[4];
3810 D3DCOLORTOGLFLOAT4(Value, col);
3811 /* Set the default alpha blend color */
3812 glFogfv(GL_FOG_COLOR, &col[0]);
3813 checkGLcall("glFog GL_FOG_COLOR");
3815 break;
3817 case WINED3DRS_FOGTABLEMODE :
3818 case WINED3DRS_FOGVERTEXMODE :
3820 /* 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." */
3821 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3822 glHint(GL_FOG_HINT, GL_FASTEST);
3823 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3824 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3825 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3826 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3828 case D3DFOG_EXP: {
3829 if(!This->last_was_rhw) {
3830 glFogi(GL_FOG_MODE, GL_EXP);
3831 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3832 if(GL_SUPPORT(EXT_FOG_COORD)) {
3833 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3834 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3835 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3836 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3838 break;
3841 case D3DFOG_EXP2: {
3842 if(!This->last_was_rhw) {
3843 glFogi(GL_FOG_MODE, GL_EXP2);
3844 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3845 if(GL_SUPPORT(EXT_FOG_COORD)) {
3846 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3847 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3848 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3849 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3851 break;
3854 case D3DFOG_LINEAR: {
3855 if(!This->last_was_rhw) {
3856 glFogi(GL_FOG_MODE, GL_LINEAR);
3857 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3858 if(GL_SUPPORT(EXT_FOG_COORD)) {
3859 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3860 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3861 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3862 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3864 break;
3867 case D3DFOG_NONE: {
3868 /* Both are none? According to msdn the alpha channel of the specular
3869 * color contains a fog factor. Set it in drawStridedSlow.
3870 * Same happens with Vertexfog on transformed vertices
3872 if(GL_SUPPORT(EXT_FOG_COORD)) {
3873 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3874 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3875 glFogi(GL_FOG_MODE, GL_LINEAR);
3876 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3877 glFogf(GL_FOG_START, (float) 0xff);
3878 checkGLcall("glFogfv GL_FOG_START");
3879 glFogf(GL_FOG_END, 0.0);
3880 checkGLcall("glFogfv GL_FOG_END");
3881 } else {
3882 /* Disable GL fog, handle this in software in drawStridedSlow */
3883 glDisable(GL_FOG);
3884 checkGLcall("glDisable(GL_FOG)");
3886 break;
3888 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3890 } else {
3891 glHint(GL_FOG_HINT, GL_NICEST);
3892 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3893 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3894 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3895 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3896 if(GL_SUPPORT(EXT_FOG_COORD)) {
3897 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3898 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3899 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3900 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3902 break;
3903 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3904 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3905 if(GL_SUPPORT(EXT_FOG_COORD)) {
3906 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3907 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3908 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3909 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3911 break;
3912 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3913 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3914 if(GL_SUPPORT(EXT_FOG_COORD)) {
3915 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3916 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3917 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3918 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3920 break;
3921 case D3DFOG_NONE: /* Won't happen */
3922 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3925 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3926 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3929 break;
3931 case WINED3DRS_FOGSTART :
3933 tmpvalue.d = Value;
3934 glFogfv(GL_FOG_START, &tmpvalue.f);
3935 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
3936 TRACE("Fog Start == %f\n", tmpvalue.f);
3938 break;
3940 case WINED3DRS_FOGEND :
3942 tmpvalue.d = Value;
3943 glFogfv(GL_FOG_END, &tmpvalue.f);
3944 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
3945 TRACE("Fog End == %f\n", tmpvalue.f);
3947 break;
3949 case WINED3DRS_FOGDENSITY :
3951 tmpvalue.d = Value;
3952 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
3953 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
3955 break;
3957 case WINED3DRS_VERTEXBLEND :
3959 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
3960 TRACE("Vertex Blending state to %ld\n", Value);
3962 break;
3964 case WINED3DRS_TWEENFACTOR :
3966 tmpvalue.d = Value;
3967 This->updateStateBlock->tween_factor = tmpvalue.f;
3968 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
3970 break;
3972 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
3974 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
3976 break;
3978 case WINED3DRS_COLORVERTEX :
3979 case WINED3DRS_DIFFUSEMATERIALSOURCE :
3980 case WINED3DRS_SPECULARMATERIALSOURCE :
3981 case WINED3DRS_AMBIENTMATERIALSOURCE :
3982 case WINED3DRS_EMISSIVEMATERIALSOURCE :
3984 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
3986 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
3987 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
3988 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
3989 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
3990 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
3991 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
3993 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
3994 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
3995 Parm = GL_AMBIENT_AND_DIFFUSE;
3996 } else {
3997 Parm = GL_DIFFUSE;
3999 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4000 Parm = GL_AMBIENT;
4001 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4002 Parm = GL_EMISSION;
4003 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4004 Parm = GL_SPECULAR;
4005 } else {
4006 Parm = -1;
4009 if (Parm == -1) {
4010 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4011 } else {
4012 This->tracking_color = NEEDS_TRACKING;
4013 This->tracking_parm = Parm;
4016 } else {
4017 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4020 break;
4022 case WINED3DRS_LINEPATTERN :
4024 union {
4025 DWORD d;
4026 D3DLINEPATTERN lp;
4027 } tmppattern;
4028 tmppattern.d = Value;
4030 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4032 if (tmppattern.lp.wRepeatFactor) {
4033 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4034 checkGLcall("glLineStipple(repeat, linepattern)");
4035 glEnable(GL_LINE_STIPPLE);
4036 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4037 } else {
4038 glDisable(GL_LINE_STIPPLE);
4039 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4042 break;
4044 case WINED3DRS_ZBIAS : /* D3D8 only */
4046 if (Value) {
4047 tmpvalue.d = Value;
4048 TRACE("ZBias value %f\n", tmpvalue.f);
4049 glPolygonOffset(0, -tmpvalue.f);
4050 checkGLcall("glPolygonOffset(0, -Value)");
4051 glEnable(GL_POLYGON_OFFSET_FILL);
4052 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4053 glEnable(GL_POLYGON_OFFSET_LINE);
4054 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4055 glEnable(GL_POLYGON_OFFSET_POINT);
4056 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4057 } else {
4058 glDisable(GL_POLYGON_OFFSET_FILL);
4059 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4060 glDisable(GL_POLYGON_OFFSET_LINE);
4061 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4062 glDisable(GL_POLYGON_OFFSET_POINT);
4063 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4066 break;
4068 case WINED3DRS_NORMALIZENORMALS :
4069 if (Value) {
4070 glEnable(GL_NORMALIZE);
4071 checkGLcall("glEnable(GL_NORMALIZE);");
4072 } else {
4073 glDisable(GL_NORMALIZE);
4074 checkGLcall("glDisable(GL_NORMALIZE);");
4076 break;
4078 case WINED3DRS_POINTSIZE :
4079 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4080 tmpvalue.d = Value;
4081 TRACE("Set point size to %f\n", tmpvalue.f);
4082 glPointSize(tmpvalue.f);
4083 checkGLcall("glPointSize(...);");
4084 break;
4086 case WINED3DRS_POINTSIZE_MIN :
4087 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4088 tmpvalue.d = Value;
4089 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4090 checkGLcall("glPointParameterfEXT(...);");
4091 } else {
4092 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4094 break;
4096 case WINED3DRS_POINTSIZE_MAX :
4097 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4098 tmpvalue.d = Value;
4099 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4100 checkGLcall("glPointParameterfEXT(...);");
4101 } else {
4102 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4104 break;
4106 case WINED3DRS_POINTSCALE_A :
4107 case WINED3DRS_POINTSCALE_B :
4108 case WINED3DRS_POINTSCALE_C :
4109 case WINED3DRS_POINTSCALEENABLE :
4112 * POINTSCALEENABLE controls how point size value is treated. If set to
4113 * true, the point size is scaled with respect to height of viewport.
4114 * When set to false point size is in pixels.
4116 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4119 /* Default values */
4120 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4123 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4124 * This means that OpenGL will clamp really small point sizes to 1.0f.
4125 * To correct for this we need to multiply by the scale factor when sizes
4126 * are less than 1.0f. scale_factor = 1.0f / point_size.
4128 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4129 if(pointSize > 0.0f) {
4130 GLfloat scaleFactor;
4132 if(pointSize < 1.0f) {
4133 scaleFactor = pointSize * pointSize;
4134 } else {
4135 scaleFactor = 1.0f;
4138 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4139 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4140 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4141 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4142 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4143 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4144 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4148 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4149 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4150 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4152 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4153 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4154 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4155 } else {
4156 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4158 break;
4160 case WINED3DRS_COLORWRITEENABLE :
4162 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4163 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4164 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4165 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4166 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4167 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4168 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4169 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4170 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4171 checkGLcall("glColorMask(...)");
4173 break;
4175 case WINED3DRS_LOCALVIEWER :
4177 GLint state = (Value) ? 1 : 0;
4178 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4179 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4181 break;
4183 case WINED3DRS_LASTPIXEL :
4185 if (Value) {
4186 TRACE("Last Pixel Drawing Enabled\n");
4187 } else {
4188 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4191 break;
4193 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4195 if (Value) {
4196 TRACE("Software Processing Enabled\n");
4197 } else {
4198 TRACE("Software Processing Disabled\n");
4201 break;
4203 /** not supported */
4204 case WINED3DRS_ZVISIBLE :
4206 LEAVE_GL();
4207 return WINED3DERR_INVALIDCALL;
4209 case WINED3DRS_POINTSPRITEENABLE :
4211 /* TODO: NV_POINT_SPRITE */
4212 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4213 TRACE("Point sprites not supported\n");
4214 break;
4218 * Point sprites are always enabled. Value controls texture coordinate
4219 * replacement mode. Must be set true for point sprites to use
4220 * textures.
4222 glEnable(GL_POINT_SPRITE_ARB);
4223 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4225 if (Value) {
4226 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4227 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4228 } else {
4229 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4230 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4232 break;
4234 case WINED3DRS_EDGEANTIALIAS :
4236 if(Value) {
4237 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4238 glEnable(GL_BLEND);
4239 checkGLcall("glEnable(GL_BLEND)");
4240 glEnable(GL_LINE_SMOOTH);
4241 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4242 } else {
4243 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4244 glDisable(GL_BLEND);
4245 checkGLcall("glDisable(GL_BLEND)");
4247 glDisable(GL_LINE_SMOOTH);
4248 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4250 break;
4252 case WINED3DRS_WRAP0 :
4253 case WINED3DRS_WRAP1 :
4254 case WINED3DRS_WRAP2 :
4255 case WINED3DRS_WRAP3 :
4256 case WINED3DRS_WRAP4 :
4257 case WINED3DRS_WRAP5 :
4258 case WINED3DRS_WRAP6 :
4259 case WINED3DRS_WRAP7 :
4260 case WINED3DRS_WRAP8 :
4261 case WINED3DRS_WRAP9 :
4262 case WINED3DRS_WRAP10 :
4263 case WINED3DRS_WRAP11 :
4264 case WINED3DRS_WRAP12 :
4265 case WINED3DRS_WRAP13 :
4266 case WINED3DRS_WRAP14 :
4267 case WINED3DRS_WRAP15 :
4269 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4270 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4271 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4272 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4273 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4275 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4277 TRACE("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4278 break;
4279 case WINED3DRS_MULTISAMPLEANTIALIAS :
4281 if (!GL_SUPPORT(ARB_MULTISAMPLE)) {
4282 TRACE("Multisample antialiasing not supported\n");
4283 break;
4286 if(Value) {
4287 glEnable(GL_MULTISAMPLE_ARB);
4288 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4289 } else {
4290 glDisable(GL_MULTISAMPLE_ARB);
4291 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4293 break;
4295 case WINED3DRS_SCISSORTESTENABLE :
4297 if(Value) {
4298 glEnable(GL_SCISSOR_TEST);
4299 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4300 } else {
4301 glDisable(GL_SCISSOR_TEST);
4302 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4304 break;
4306 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4308 if(Value) {
4309 tmpvalue.d = Value;
4310 glEnable(GL_POLYGON_OFFSET_FILL);
4311 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4312 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4313 checkGLcall("glPolygonOffset(...)");
4314 } else {
4315 glDisable(GL_POLYGON_OFFSET_FILL);
4316 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4318 break;
4320 case WINED3DRS_ANTIALIASEDLINEENABLE :
4322 if(Value) {
4323 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4324 glEnable(GL_BLEND);
4325 checkGLcall("glEnable(GL_BLEND)");
4326 glEnable(GL_LINE_SMOOTH);
4327 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4328 } else {
4329 glDisable(GL_BLEND);
4330 checkGLcall("glDisable(GL_BLEND)");
4331 glDisable(GL_LINE_SMOOTH);
4332 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4334 break;
4336 case WINED3DRS_DEPTHBIAS :
4338 if(Value) {
4339 tmpvalue.d = Value;
4340 glEnable(GL_POLYGON_OFFSET_FILL);
4341 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4342 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4343 checkGLcall("glPolygonOffset(...)");
4344 } else {
4345 glDisable(GL_POLYGON_OFFSET_FILL);
4346 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4348 break;
4351 case WINED3DRS_TEXTUREPERSPECTIVE :
4353 if (Value)
4354 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4355 else
4356 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4357 break;
4360 case WINED3DRS_STIPPLEDALPHA :
4362 if (Value)
4363 ERR(" Stippled Alpha not supported yet.\n");
4364 break;
4366 case WINED3DRS_ANTIALIAS :
4368 if (Value)
4369 ERR(" Antialias not supported yet.\n");
4370 break;
4372 default:
4373 FIXME("(%p)->(%s,%ld) not handled yet\n", This, debug_d3drenderstate(State), Value);
4376 LEAVE_GL();
4378 return WINED3D_OK;
4381 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4384 *pValue = This->stateBlock->renderState[State];
4385 return WINED3D_OK;
4388 /*****
4389 * Get / Set Sampler States
4390 * TODO: Verify against dx9 definitions
4391 *****/
4393 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4396 * SetSampler is designed to allow for more than the standard up to 8 textures
4397 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4398 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4400 * http://developer.nvidia.com/object/General_FAQ.html#t6
4402 * There are two new settings for GForce
4403 * the sampler one:
4404 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4405 * and the texture one:
4406 * GL_MAX_TEXTURE_COORDS_ARB.
4407 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4408 ******************/
4409 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4410 if(Sampler > GL_LIMITS(samplers) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4411 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4412 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(samplers), WINED3D_HIGHEST_SAMPLER_STATE);
4413 return WINED3DERR_INVALIDCALL;
4416 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4417 debug_d3dsamplerstate(Type), Type, Value);
4418 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4419 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4420 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4422 /* Handle recording of state blocks */
4423 if (This->isRecordingState) {
4424 TRACE("Recording... not performing anything\n");
4425 return WINED3D_OK;
4428 return WINED3D_OK;
4431 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4433 /** TODO: check that sampler is in range **/
4434 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4435 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4437 return WINED3D_OK;
4440 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 ENTER_GL();
4444 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4445 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4446 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4447 LEAVE_GL();
4449 return WINED3D_OK;
4452 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4454 GLint scissorBox[4];
4456 ENTER_GL();
4457 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4458 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4459 pRect->left = scissorBox[1];
4460 pRect->top = scissorBox[2];
4461 pRect->right = scissorBox[1] + scissorBox[3];
4462 pRect->bottom = scissorBox[2] + scissorBox[4];
4463 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4464 LEAVE_GL();
4465 return WINED3D_OK;
4468 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4470 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4472 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4474 This->updateStateBlock->vertexDecl = pDecl;
4475 This->updateStateBlock->changed.vertexDecl = TRUE;
4476 This->updateStateBlock->set.vertexDecl = TRUE;
4478 if (This->isRecordingState) {
4479 TRACE("Recording... not performing anything\n");
4482 if (NULL != pDecl) {
4483 IWineD3DVertexDeclaration_AddRef(pDecl);
4485 if (NULL != oldDecl) {
4486 IWineD3DVertexDeclaration_Release(oldDecl);
4488 return WINED3D_OK;
4491 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4494 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4496 *ppDecl = This->stateBlock->vertexDecl;
4497 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4498 return WINED3D_OK;
4501 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4505 This->updateStateBlock->vertexShader = pShader;
4506 This->updateStateBlock->changed.vertexShader = TRUE;
4507 This->updateStateBlock->set.vertexShader = TRUE;
4509 if (This->isRecordingState) {
4510 TRACE("Recording... not performing anything\n");
4513 if (NULL != pShader) {
4514 IWineD3DVertexShader_AddRef(pShader);
4516 if (NULL != oldShader) {
4517 IWineD3DVertexShader_Release(oldShader);
4520 if (pShader != NULL && ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration != NULL) {
4521 TRACE("(%p) : setting vertexDeclaration(%p)\n", This, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4522 IWineD3DDevice_SetVertexDeclaration(iface, ((IWineD3DVertexShaderImpl *)pShader)->vertexDeclaration);
4525 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4527 * TODO: merge HAL shaders context switching from prototype
4529 return WINED3D_OK;
4532 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4535 if (NULL == ppShader) {
4536 return WINED3DERR_INVALIDCALL;
4538 *ppShader = This->stateBlock->vertexShader;
4539 if( NULL != *ppShader)
4540 IWineD3DVertexShader_AddRef(*ppShader);
4542 TRACE("(%p) : returning %p\n", This, *ppShader);
4543 return WINED3D_OK;
4546 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4547 IWineD3DDevice *iface,
4548 UINT start,
4549 CONST BOOL *srcData,
4550 UINT count) {
4552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4553 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4555 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4556 iface, srcData, start, count);
4558 if (srcData == NULL || cnt < 0)
4559 return WINED3DERR_INVALIDCALL;
4561 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4563 for (i = start; i < cnt + start; ++i) {
4564 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4565 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4568 return WINED3D_OK;
4571 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4572 IWineD3DDevice *iface,
4573 UINT start,
4574 BOOL *dstData,
4575 UINT count) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4580 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4581 iface, dstData, start, count);
4583 if (dstData == NULL || cnt < 0)
4584 return WINED3DERR_INVALIDCALL;
4586 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4587 return WINED3D_OK;
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4591 IWineD3DDevice *iface,
4592 UINT start,
4593 CONST int *srcData,
4594 UINT count) {
4596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4599 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4600 iface, srcData, start, count);
4602 if (srcData == NULL || cnt < 0)
4603 return WINED3DERR_INVALIDCALL;
4605 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4607 for (i = start; i < cnt + start; ++i) {
4608 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4609 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4612 return WINED3D_OK;
4615 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4616 IWineD3DDevice *iface,
4617 UINT start,
4618 int *dstData,
4619 UINT count) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4624 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4625 iface, dstData, start, count);
4627 if (dstData == NULL || cnt < 0)
4628 return WINED3DERR_INVALIDCALL;
4630 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4631 return WINED3D_OK;
4634 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4635 IWineD3DDevice *iface,
4636 UINT start,
4637 CONST float *srcData,
4638 UINT count) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4643 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4644 iface, srcData, start, count);
4646 if (srcData == NULL || cnt < 0)
4647 return WINED3DERR_INVALIDCALL;
4649 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4651 for (i = start; i < cnt + start; ++i) {
4652 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4653 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4656 return WINED3D_OK;
4659 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4660 IWineD3DDevice *iface,
4661 UINT start,
4662 float *dstData,
4663 UINT count) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
4668 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4669 iface, dstData, start, count);
4671 if (dstData == NULL || cnt < 0)
4672 return WINED3DERR_INVALIDCALL;
4674 memcpy(dstData, &This->updateStateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4675 return WINED3D_OK;
4678 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4680 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4681 This->updateStateBlock->pixelShader = pShader;
4682 This->updateStateBlock->changed.pixelShader = TRUE;
4683 This->updateStateBlock->set.pixelShader = TRUE;
4685 /* Handle recording of state blocks */
4686 if (This->isRecordingState) {
4687 TRACE("Recording... not performing anything\n");
4690 if (NULL != pShader) {
4691 IWineD3DPixelShader_AddRef(pShader);
4693 if (NULL != oldShader) {
4694 IWineD3DPixelShader_Release(oldShader);
4697 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4699 * TODO: merge HAL shaders context switching from prototype
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 if (NULL == ppShader) {
4708 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4709 return WINED3DERR_INVALIDCALL;
4712 *ppShader = This->stateBlock->pixelShader;
4713 if (NULL != *ppShader) {
4714 IWineD3DPixelShader_AddRef(*ppShader);
4716 TRACE("(%p) : returning %p\n", This, *ppShader);
4717 return WINED3D_OK;
4720 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4721 IWineD3DDevice *iface,
4722 UINT start,
4723 CONST BOOL *srcData,
4724 UINT count) {
4726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4727 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4729 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4730 iface, srcData, start, count);
4732 if (srcData == NULL || cnt < 0)
4733 return WINED3DERR_INVALIDCALL;
4735 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4737 for (i = start; i < cnt + start; ++i) {
4738 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4739 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4742 return WINED3D_OK;
4745 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4746 IWineD3DDevice *iface,
4747 UINT start,
4748 BOOL *dstData,
4749 UINT count) {
4751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4752 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4754 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4755 iface, dstData, start, count);
4757 if (dstData == NULL || cnt < 0)
4758 return WINED3DERR_INVALIDCALL;
4760 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4761 return WINED3D_OK;
4764 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4765 IWineD3DDevice *iface,
4766 UINT start,
4767 CONST int *srcData,
4768 UINT count) {
4770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4773 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4774 iface, srcData, start, count);
4776 if (srcData == NULL || cnt < 0)
4777 return WINED3DERR_INVALIDCALL;
4779 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4781 for (i = start; i < cnt + start; ++i) {
4782 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4783 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4786 return WINED3D_OK;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4790 IWineD3DDevice *iface,
4791 UINT start,
4792 int *dstData,
4793 UINT count) {
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4799 iface, dstData, start, count);
4801 if (dstData == NULL || cnt < 0)
4802 return WINED3DERR_INVALIDCALL;
4804 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4805 return WINED3D_OK;
4808 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4809 IWineD3DDevice *iface,
4810 UINT start,
4811 CONST float *srcData,
4812 UINT count) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4817 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4818 iface, srcData, start, count);
4820 if (srcData == NULL || cnt < 0)
4821 return WINED3DERR_INVALIDCALL;
4823 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4825 for (i = start; i < cnt + start; ++i) {
4826 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4827 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4830 return WINED3D_OK;
4833 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4834 IWineD3DDevice *iface,
4835 UINT start,
4836 float *dstData,
4837 UINT count) {
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
4842 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4843 iface, dstData, start, count);
4845 if (dstData == NULL || cnt < 0)
4846 return WINED3DERR_INVALIDCALL;
4848 memcpy(dstData, &This->updateStateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4849 return WINED3D_OK;
4852 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4853 static HRESULT
4854 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4855 char *dest_ptr;
4856 unsigned int i;
4857 DWORD DestFVF = dest->fvf;
4858 D3DVIEWPORT9 vp;
4859 D3DMATRIX mat, proj_mat, view_mat, world_mat;
4860 BOOL doClip;
4861 int numTextures;
4863 if (SrcFVF & D3DFVF_NORMAL) {
4864 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4867 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
4868 ERR("Source has no position mask\n");
4869 return WINED3DERR_INVALIDCALL;
4872 if (dest->resource.allocatedMemory == NULL) {
4873 ERR("Destination buffer has no memory allocated\n");
4874 return WINED3DERR_INVALIDCALL;
4877 /* Should I clip?
4878 * a) D3DRS_CLIPPING is enabled
4879 * b) WINED3DVOP_CLIP is passed
4881 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4882 static BOOL warned = FALSE;
4884 * The clipping code is not quite correct. Some things need
4885 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4886 * so disable clipping for now.
4887 * (The graphics in Half-Life are broken, and my processvertices
4888 * test crashes with IDirect3DDevice3)
4889 doClip = TRUE;
4891 doClip = FALSE;
4892 if(!warned) {
4893 warned = TRUE;
4894 FIXME("Clipping is broken and disabled for now\n");
4896 } else doClip = FALSE;
4897 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4899 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4900 D3DTS_VIEW,
4901 &view_mat);
4902 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4903 D3DTS_PROJECTION,
4904 &proj_mat);
4905 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4906 D3DTS_WORLDMATRIX(0),
4907 &world_mat);
4909 TRACE("View mat: \n");
4910 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); \
4911 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); \
4912 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); \
4913 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); \
4915 TRACE("Proj mat: \n");
4916 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); \
4917 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); \
4918 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); \
4919 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); \
4921 TRACE("World mat: \n");
4922 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); \
4923 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); \
4924 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); \
4925 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); \
4927 /* Get the viewport */
4928 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4929 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
4930 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4932 multiply_matrix(&mat,&view_mat,&world_mat);
4933 multiply_matrix(&mat,&proj_mat,&mat);
4935 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
4937 for (i = 0; i < dwCount; i+= 1) {
4938 unsigned int tex_index;
4940 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
4941 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
4942 /* The position first */
4943 float *p =
4944 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4945 float x, y, z, rhw;
4946 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4948 /* Multiplication with world, view and projection matrix */
4949 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);
4950 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);
4951 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);
4952 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);
4954 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4956 /* WARNING: The following things are taken from d3d7 and were not yet checked
4957 * against d3d8 or d3d9!
4960 /* Clipping conditions: From
4961 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4963 * A vertex is clipped if it does not match the following requirements
4964 * -rhw < x <= rhw
4965 * -rhw < y <= rhw
4966 * 0 < z <= rhw
4967 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4969 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4970 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4974 if( doClip == FALSE ||
4975 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4976 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4977 ( rhw > eps ) ) ) {
4979 /* "Normal" viewport transformation (not clipped)
4980 * 1) The values are divided trough rhw
4981 * 2) The y axis is negative, so multiply it with -1
4982 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4983 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4984 * 4) Multiply x with Width/2 and add Width/2
4985 * 5) The same for the height
4986 * 6) Add the viewpoint X and Y to the 2D coordinates and
4987 * The minimum Z value to z
4988 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4990 * Well, basically it's simply a linear transformation into viewport
4991 * coordinates
4994 x /= rhw;
4995 y /= rhw;
4996 z /= rhw;
4998 y *= -1;
5000 x *= vp.Width / 2;
5001 y *= vp.Height / 2;
5002 z *= vp.MaxZ - vp.MinZ;
5004 x += vp.Width / 2 + vp.X;
5005 y += vp.Height / 2 + vp.Y;
5006 z += vp.MinZ;
5008 rhw = 1 / rhw;
5009 } else {
5010 /* That vertex got clipped
5011 * Contrary to OpenGL it is not dropped completely, it just
5012 * undergoes a different calculation.
5014 TRACE("Vertex got clipped\n");
5015 x += rhw;
5016 y += rhw;
5018 x /= 2;
5019 y /= 2;
5021 /* Msdn mentiones that Direct3D9 keeps a list of clipped vertices
5022 * outside of the main vertex buffer memory. That needs some more
5023 * investigation...
5027 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5030 ( (float *) dest_ptr)[0] = x;
5031 ( (float *) dest_ptr)[1] = y;
5032 ( (float *) dest_ptr)[2] = z;
5033 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5035 dest_ptr += 3 * sizeof(float);
5037 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5038 dest_ptr += sizeof(float);
5041 if (DestFVF & D3DFVF_PSIZE) {
5042 dest_ptr += sizeof(DWORD);
5044 if (DestFVF & D3DFVF_NORMAL) {
5045 float *normal =
5046 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5047 /* AFAIK this should go into the lighting information */
5048 FIXME("Didn't expect the destination to have a normal\n");
5049 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5052 if (DestFVF & D3DFVF_DIFFUSE) {
5053 DWORD *color_d =
5054 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5055 if(!color_d) {
5056 static BOOL warned = FALSE;
5058 if(warned == FALSE) {
5059 ERR("No diffuse color in source, but destination has one\n");
5060 warned = TRUE;
5063 *( (DWORD *) dest_ptr) = 0xffffffff;
5064 dest_ptr += sizeof(DWORD);
5066 else
5067 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5070 if (DestFVF & D3DFVF_SPECULAR) {
5071 /* What's the color value in the feedback buffer? */
5072 DWORD *color_s =
5073 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5074 if(!color_s) {
5075 static BOOL warned = FALSE;
5077 if(warned == FALSE) {
5078 ERR("No specular color in source, but destination has one\n");
5079 warned = TRUE;
5082 *( (DWORD *) dest_ptr) = 0xFF000000;
5083 dest_ptr += sizeof(DWORD);
5085 else {
5086 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5090 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5091 float *tex_coord =
5092 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5093 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5094 if(!tex_coord) {
5095 ERR("No source texture, but destination requests one\n");
5096 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5098 else {
5099 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5104 return WINED3D_OK;
5106 #undef copy_and_next
5108 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5111 WineDirect3DVertexStridedData strided;
5112 HRESULT hr;
5113 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5115 hr = IWineD3DDevice_SetFVF(iface, SrcImpl->fvf);
5116 hr = IWineD3DDevice_SetStreamSource(iface, 0, pVertexDecl, get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, get_flexible_vertex_size(SrcImpl->fvf));
5118 memset(&strided, 0, sizeof(strided));
5119 primitiveConvertToStridedData(iface, &strided, 0);
5121 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5124 /*****
5125 * Apply / Get / Set Texture Stage States
5126 * TODO: Verify against dx9 definitions
5127 *****/
5129 /* 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 */
5130 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5132 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5133 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5135 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5137 /* Check that the stage is within limits */
5138 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
5139 TRACE("Attempt to access invalid texture rejected\n");
5140 return;
5143 ENTER_GL();
5145 switch (Type) {
5146 case WINED3DTSS_ALPHAOP :
5147 case WINED3DTSS_COLOROP :
5148 /* nothing to do as moved to drawprim for now */
5149 break;
5150 case WINED3DTSS_ADDRESSW :
5151 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5152 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5153 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5155 } else {
5156 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5157 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5158 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5159 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5161 #endif
5162 case WINED3DTSS_TEXCOORDINDEX :
5164 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5166 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5167 one flag, you can still specify an index value, which the system uses to
5168 determine the texture wrapping mode.
5169 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5170 means use the vertex position (camera-space) as the input texture coordinates
5171 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5172 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5173 to the TEXCOORDINDEX value */
5176 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5178 switch (Value & 0xFFFF0000) {
5179 case D3DTSS_TCI_PASSTHRU:
5180 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5181 glDisable(GL_TEXTURE_GEN_S);
5182 glDisable(GL_TEXTURE_GEN_T);
5183 glDisable(GL_TEXTURE_GEN_R);
5184 glDisable(GL_TEXTURE_GEN_Q);
5185 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5186 break;
5188 case D3DTSS_TCI_CAMERASPACEPOSITION:
5189 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5190 as the input texture coordinates for this stage's texture transformation. This
5191 equates roughly to EYE_LINEAR */
5193 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5194 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5195 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5196 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5197 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5199 glMatrixMode(GL_MODELVIEW);
5200 glPushMatrix();
5201 glLoadIdentity();
5202 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5203 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5204 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5205 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5206 glPopMatrix();
5208 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5209 glEnable(GL_TEXTURE_GEN_S);
5210 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5211 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5212 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5213 glEnable(GL_TEXTURE_GEN_T);
5214 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5215 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5216 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5217 glEnable(GL_TEXTURE_GEN_R);
5218 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5219 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5220 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5222 break;
5224 case D3DTSS_TCI_CAMERASPACENORMAL:
5226 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5227 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5228 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5229 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5230 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5231 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5233 glMatrixMode(GL_MODELVIEW);
5234 glPushMatrix();
5235 glLoadIdentity();
5236 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5237 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5238 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5239 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5240 glPopMatrix();
5242 glEnable(GL_TEXTURE_GEN_S);
5243 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5244 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5245 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5246 glEnable(GL_TEXTURE_GEN_T);
5247 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5248 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5249 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5250 glEnable(GL_TEXTURE_GEN_R);
5251 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5252 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5253 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5256 break;
5258 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5260 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5261 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5262 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5263 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5264 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5265 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5267 glMatrixMode(GL_MODELVIEW);
5268 glPushMatrix();
5269 glLoadIdentity();
5270 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5271 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5272 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5273 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5274 glPopMatrix();
5276 glEnable(GL_TEXTURE_GEN_S);
5277 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5278 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5279 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5280 glEnable(GL_TEXTURE_GEN_T);
5281 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5282 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5283 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5284 glEnable(GL_TEXTURE_GEN_R);
5285 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5286 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5287 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5290 break;
5292 /* Unhandled types: */
5293 default:
5294 /* Todo: */
5295 /* ? disable GL_TEXTURE_GEN_n ? */
5296 glDisable(GL_TEXTURE_GEN_S);
5297 glDisable(GL_TEXTURE_GEN_T);
5298 glDisable(GL_TEXTURE_GEN_R);
5299 glDisable(GL_TEXTURE_GEN_Q);
5300 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5301 break;
5304 break;
5306 /* Unhandled */
5307 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5308 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);
5309 break;
5311 case WINED3DTSS_BUMPENVMAT00 :
5312 case WINED3DTSS_BUMPENVMAT01 :
5313 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5314 break;
5315 case WINED3DTSS_BUMPENVMAT10 :
5316 case WINED3DTSS_BUMPENVMAT11 :
5317 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5318 break;
5320 case WINED3DTSS_BUMPENVLSCALE :
5321 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5322 break;
5324 case WINED3DTSS_BUMPENVLOFFSET :
5325 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5326 break;
5328 case WINED3DTSS_RESULTARG :
5329 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5330 break;
5332 default:
5333 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5334 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5337 LEAVE_GL();
5339 return;
5342 /*****
5343 * Get / Set Texture Stage States
5344 * TODO: Verify against dx9 definitions
5345 *****/
5346 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5349 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5351 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5353 /* Reject invalid texture units */
5354 if (Stage >= GL_LIMITS(textures)) {
5355 TRACE("Attempt to access invalid texture rejected\n");
5356 return WINED3DERR_INVALIDCALL;
5359 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5360 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5361 This->updateStateBlock->textureState[Stage][Type] = Value;
5363 return WINED3D_OK;
5366 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5369 *pValue = This->updateStateBlock->textureState[Stage][Type];
5370 return WINED3D_OK;
5373 /*****
5374 * Get / Set Texture
5375 *****/
5376 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5379 IWineD3DBaseTexture *oldTexture;
5381 oldTexture = This->updateStateBlock->textures[Stage];
5382 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5384 #if 0 /* TODO: check so vertex textures */
5385 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5386 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5387 return WINED3D_OK;
5389 #endif
5391 /* Reject invalid texture units */
5392 if (Stage >= GL_LIMITS(textures) || Stage < 0) {
5393 WARN("Attempt to access invalid texture rejected\n");
5394 return WINED3DERR_INVALIDCALL;
5397 if(pTexture != NULL) {
5398 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5400 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5401 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5402 return WINED3DERR_INVALIDCALL;
5406 oldTexture = This->updateStateBlock->textures[Stage];
5407 TRACE("GL_LIMITS %d\n",GL_LIMITS(textures));
5408 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5410 This->updateStateBlock->set.textures[Stage] = TRUE;
5411 This->updateStateBlock->changed.textures[Stage] = TRUE;
5412 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5413 This->updateStateBlock->textures[Stage] = pTexture;
5415 /* Handle recording of state blocks */
5416 if (This->isRecordingState) {
5417 TRACE("Recording... not performing anything\n");
5418 return WINED3D_OK;
5421 /** NOTE: MSDN says that setTexture increases the reference count,
5422 * and the the application nust set the texture back to null (or have a leaky application),
5423 * This means we should pass the refcount up to the parent
5424 *******************************/
5425 if (NULL != This->updateStateBlock->textures[Stage]) {
5426 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5429 if (NULL != oldTexture) {
5430 IWineD3DBaseTexture_Release(oldTexture);
5433 /* Reset color keying */
5434 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5435 BOOL enable_ckey = FALSE;
5437 if(pTexture) {
5438 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5439 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5442 if(enable_ckey) {
5443 glAlphaFunc(GL_NOTEQUAL, 0.0);
5444 checkGLcall("glAlphaFunc");
5448 return WINED3D_OK;
5451 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5455 /* Reject invalid texture units */
5456 if (Stage >= GL_LIMITS(textures)) {
5457 TRACE("Attempt to access invalid texture rejected\n");
5458 return WINED3DERR_INVALIDCALL;
5460 *ppTexture=This->updateStateBlock->textures[Stage];
5461 if (*ppTexture)
5462 IWineD3DBaseTexture_AddRef(*ppTexture);
5463 else
5464 return WINED3DERR_INVALIDCALL;
5465 return WINED3D_OK;
5468 /*****
5469 * Get Back Buffer
5470 *****/
5471 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5472 IWineD3DSurface **ppBackBuffer) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 IWineD3DSwapChain *swapChain;
5475 HRESULT hr;
5477 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5479 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5480 if (hr == WINED3D_OK) {
5481 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5482 IWineD3DSwapChain_Release(swapChain);
5483 } else {
5484 *ppBackBuffer = NULL;
5486 return hr;
5489 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 WARN("(%p) : stub, calling idirect3d for now\n", This);
5492 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5495 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5497 IWineD3DSwapChain *swapChain;
5498 HRESULT hr;
5500 if(iSwapChain > 0) {
5501 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5502 if (hr == WINED3D_OK) {
5503 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5504 IWineD3DSwapChain_Release(swapChain);
5505 } else {
5506 FIXME("(%p) Error getting display mode\n", This);
5508 } else {
5509 /* Don't read the real display mode,
5510 but return the stored mode instead. X11 can't change the color
5511 depth, and some apps are pretty angry if they SetDisplayMode from
5512 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5514 Also don't relay to the swapchain because with ddraw it's possible
5515 that there isn't a swapchain at all */
5516 pMode->Width = This->ddraw_width;
5517 pMode->Height = This->ddraw_height;
5518 pMode->Format = This->ddraw_format;
5519 pMode->RefreshRate = 0;
5520 hr = WINED3D_OK;
5523 return hr;
5526 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 TRACE("(%p)->(%p)\n", This, hWnd);
5530 This->ddraw_window = hWnd;
5531 return WINED3D_OK;
5534 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5536 TRACE("(%p)->(%p)\n", This, hWnd);
5538 *hWnd = This->ddraw_window;
5539 return WINED3D_OK;
5542 /*****
5543 * Stateblock related functions
5544 *****/
5546 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5548 IWineD3DStateBlockImpl *object;
5549 TRACE("(%p)", This);
5551 if (This->isRecordingState) {
5552 return WINED3DERR_INVALIDCALL;
5555 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5556 if (NULL == object ) {
5557 FIXME("(%p)Error allocating memory for stateblock\n", This);
5558 return E_OUTOFMEMORY;
5560 TRACE("(%p) creted object %p\n", This, object);
5561 object->wineD3DDevice= This;
5562 /** FIXME: object->parent = parent; **/
5563 object->parent = NULL;
5564 object->blockType = WINED3DSBT_ALL;
5565 object->ref = 1;
5566 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5568 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5569 This->updateStateBlock = object;
5570 This->isRecordingState = TRUE;
5572 TRACE("(%p) recording stateblock %p\n",This , object);
5573 return WINED3D_OK;
5576 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5579 if (!This->isRecordingState) {
5580 FIXME("(%p) not recording! returning error\n", This);
5581 *ppStateBlock = NULL;
5582 return WINED3DERR_INVALIDCALL;
5585 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5586 This->isRecordingState = FALSE;
5587 This->updateStateBlock = This->stateBlock;
5588 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5589 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5590 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5591 return WINED3D_OK;
5594 /*****
5595 * Scene related functions
5596 *****/
5597 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5598 /* At the moment we have no need for any functionality at the beginning
5599 of a scene */
5600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5601 TRACE("(%p) : stub\n", This);
5602 return WINED3D_OK;
5605 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5607 TRACE("(%p)\n", This);
5608 ENTER_GL();
5609 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5610 glFlush();
5611 checkGLcall("glFlush");
5613 TRACE("End Scene\n");
5614 if(This->renderTarget != NULL) {
5616 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5617 IUnknown *targetContainer = NULL;
5618 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5619 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5620 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5621 /** always dirtify for now. we must find a better way to see that surface have been modified
5622 (Modifications should will only occur via draw-primitive, but we do need better locking
5623 switching to render-to-texture should remove the overhead though.
5625 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5626 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5627 IWineD3DSurface_PreLoad(This->renderTarget);
5628 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5629 IUnknown_Release(targetContainer);
5632 This->sceneEnded = TRUE;
5633 LEAVE_GL();
5634 return WINED3D_OK;
5637 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5638 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5639 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 IWineD3DSwapChain *swapChain = NULL;
5642 int i;
5643 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5645 TRACE("(%p) Presenting the frame\n", This);
5647 for(i = 0 ; i < swapchains ; i ++) {
5649 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
5650 TRACE("presentinng chain %d, %p\n", i, swapChain);
5651 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5652 IWineD3DSwapChain_Release(swapChain);
5655 return WINED3D_OK;
5658 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
5659 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
5663 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
5664 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5665 GLbitfield glMask = 0;
5666 GLboolean old_ztest;
5667 GLfloat old_z_clear_value;
5668 GLint old_stencil_clear_value;
5669 GLfloat old_color_clear_value[4];
5670 unsigned int i;
5671 CONST D3DRECT* curRect;
5673 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
5674 Count, pRects, Flags, Z, Stencil);
5676 ENTER_GL();
5678 glEnable(GL_SCISSOR_TEST);
5679 checkGLcall("glEnable GL_SCISSOR_TEST");
5681 if (Count > 0 && pRects) {
5682 curRect = pRects;
5683 } else {
5684 curRect = NULL;
5687 /* Only set the values up once, as they are not changing */
5688 if (Flags & D3DCLEAR_STENCIL) {
5689 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5690 glClearStencil(Stencil);
5691 checkGLcall("glClearStencil");
5692 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5693 glStencilMask(0xFFFFFFFF);
5696 if (Flags & D3DCLEAR_ZBUFFER) {
5697 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5698 glDepthMask(GL_TRUE);
5699 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5700 glClearDepth(Z);
5701 checkGLcall("glClearDepth");
5702 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5705 if (Flags & D3DCLEAR_TARGET) {
5706 TRACE("Clearing screen with glClear to color %lx\n", Color);
5707 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5708 glClearColor(D3DCOLOR_R(Color),
5709 D3DCOLOR_G(Color),
5710 D3DCOLOR_B(Color),
5711 D3DCOLOR_A(Color));
5712 checkGLcall("glClearColor");
5714 /* Clear ALL colors! */
5715 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5716 glMask = glMask | GL_COLOR_BUFFER_BIT;
5719 /* Now process each rect in turn */
5720 for (i = 0; i < Count || i == 0; i++) {
5722 if (curRect) {
5723 /* Note gl uses lower left, width/height */
5724 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
5725 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5726 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5727 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5728 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5729 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5730 checkGLcall("glScissor");
5731 } else {
5732 glScissor(This->stateBlock->viewport.X,
5733 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5734 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5735 This->stateBlock->viewport.Width,
5736 This->stateBlock->viewport.Height);
5737 checkGLcall("glScissor");
5740 /* Clear the selected rectangle (or full screen) */
5741 glClear(glMask);
5742 checkGLcall("glClear");
5744 /* Step to the next rectangle */
5745 if (curRect) curRect = curRect + sizeof(D3DRECT);
5748 /* Restore the old values (why..?) */
5749 if (Flags & D3DCLEAR_STENCIL) {
5750 glClearStencil(old_stencil_clear_value);
5751 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5753 if (Flags & D3DCLEAR_ZBUFFER) {
5754 glDepthMask(old_ztest);
5755 glClearDepth(old_z_clear_value);
5757 if (Flags & D3DCLEAR_TARGET) {
5758 glClearColor(old_color_clear_value[0],
5759 old_color_clear_value[1],
5760 old_color_clear_value[2],
5761 old_color_clear_value[3]);
5762 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5763 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5764 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5765 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5768 glDisable(GL_SCISSOR_TEST);
5769 checkGLcall("glDisable");
5770 LEAVE_GL();
5772 return WINED3D_OK;
5775 /*****
5776 * Drawing functions
5777 *****/
5778 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5779 UINT PrimitiveCount) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 This->stateBlock->streamIsUP = FALSE;
5784 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5785 debug_d3dprimitivetype(PrimitiveType),
5786 StartVertex, PrimitiveCount);
5787 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5788 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
5791 return WINED3D_OK;
5794 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5795 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5796 D3DPRIMITIVETYPE PrimitiveType,
5797 INT baseVIndex, UINT minIndex,
5798 UINT NumVertices, UINT startIndex, UINT primCount) {
5800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 UINT idxStride = 2;
5802 IWineD3DIndexBuffer *pIB;
5803 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5805 pIB = This->stateBlock->pIndexData;
5806 This->stateBlock->streamIsUP = FALSE;
5808 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
5809 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5810 minIndex, NumVertices, startIndex, baseVIndex, primCount);
5812 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5813 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5814 idxStride = 2;
5815 } else {
5816 idxStride = 4;
5819 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
5820 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
5822 return WINED3D_OK;
5825 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
5826 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5827 UINT VertexStreamZeroStride) {
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5830 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5831 debug_d3dprimitivetype(PrimitiveType),
5832 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5834 /* release the stream source */
5835 if (This->stateBlock->streamSource[0] != NULL) {
5836 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5839 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5840 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5841 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5842 This->stateBlock->streamIsUP = TRUE;
5844 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5845 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
5847 /* MSDN specifies stream zero settings must be set to NULL */
5848 This->stateBlock->streamStride[0] = 0;
5849 This->stateBlock->streamSource[0] = NULL;
5851 /*stream zero settings set to null at end, as per the msdn */
5852 return WINED3D_OK;
5855 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
5856 UINT MinVertexIndex, UINT NumVertices,
5857 UINT PrimitiveCount, CONST void* pIndexData,
5858 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5859 UINT VertexStreamZeroStride) {
5860 int idxStride;
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5864 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5865 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5866 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5868 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5869 idxStride = 2;
5870 } else {
5871 idxStride = 4;
5874 /* release the stream and index data */
5875 if (This->stateBlock->streamSource[0] != NULL) {
5876 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5878 if (This->stateBlock->pIndexData) {
5879 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
5882 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5883 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5884 This->stateBlock->streamIsUP = TRUE;
5885 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5887 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
5889 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5890 This->stateBlock->streamSource[0] = NULL;
5891 This->stateBlock->streamStride[0] = 0;
5892 This->stateBlock->pIndexData = NULL;
5894 return WINED3D_OK;
5897 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5899 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
5900 return WINED3D_OK;
5902 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5903 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5905 HRESULT hr = WINED3D_OK;
5906 WINED3DRESOURCETYPE sourceType;
5907 WINED3DRESOURCETYPE destinationType;
5908 int i ,levels;
5910 /* TODO: think about moving the code into IWineD3DBaseTexture */
5912 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5914 /* verify that the source and destination textures aren't NULL */
5915 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5916 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5917 This, pSourceTexture, pDestinationTexture);
5918 hr = WINED3DERR_INVALIDCALL;
5921 if (pSourceTexture == pDestinationTexture) {
5922 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5923 This, pSourceTexture, pDestinationTexture);
5924 hr = WINED3DERR_INVALIDCALL;
5926 /* Verify that the source and destination textures are the same type */
5927 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5928 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5930 if (sourceType != destinationType) {
5931 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5932 This);
5933 hr = WINED3DERR_INVALIDCALL;
5936 /* check that both textures have the identical numbers of levels */
5937 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5938 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5939 hr = WINED3DERR_INVALIDCALL;
5942 if (WINED3D_OK == hr) {
5944 /* Make sure that the destination texture is loaded */
5945 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5947 /* Update every surface level of the texture */
5948 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5950 switch (sourceType) {
5951 case WINED3DRTYPE_TEXTURE:
5953 IWineD3DSurface *srcSurface;
5954 IWineD3DSurface *destSurface;
5956 for (i = 0 ; i < levels ; ++i) {
5957 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5958 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5959 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5960 IWineD3DSurface_Release(srcSurface);
5961 IWineD3DSurface_Release(destSurface);
5962 if (WINED3D_OK != hr) {
5963 WARN("(%p) : Call to update surface failed\n", This);
5964 return hr;
5968 break;
5969 case WINED3DRTYPE_CUBETEXTURE:
5971 IWineD3DSurface *srcSurface;
5972 IWineD3DSurface *destSurface;
5973 WINED3DCUBEMAP_FACES faceType;
5975 for (i = 0 ; i < levels ; ++i) {
5976 /* Update each cube face */
5977 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5978 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5979 if (WINED3D_OK != hr) {
5980 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5981 } else {
5982 TRACE("Got srcSurface %p\n", srcSurface);
5984 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5985 if (WINED3D_OK != hr) {
5986 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5987 } else {
5988 TRACE("Got desrSurface %p\n", destSurface);
5990 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5991 IWineD3DSurface_Release(srcSurface);
5992 IWineD3DSurface_Release(destSurface);
5993 if (WINED3D_OK != hr) {
5994 WARN("(%p) : Call to update surface failed\n", This);
5995 return hr;
6000 break;
6001 #if 0 /* TODO: Add support for volume textures */
6002 case WINED3DRTYPE_VOLUMETEXTURE:
6004 IWineD3DVolume srcVolume = NULL;
6005 IWineD3DSurface destVolume = NULL;
6007 for (i = 0 ; i < levels ; ++i) {
6008 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6009 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6010 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6011 IWineD3DVolume_Release(srcSurface);
6012 IWineD3DVolume_Release(destSurface);
6013 if (WINED3D_OK != hr) {
6014 WARN("(%p) : Call to update volume failed\n", This);
6015 return hr;
6019 break;
6020 #endif
6021 default:
6022 FIXME("(%p) : Unsupported source and destination type\n", This);
6023 hr = WINED3DERR_INVALIDCALL;
6027 return hr;
6030 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6031 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6032 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 TRACE("(%p) : stub\n", This);
6036 return WINED3D_OK;
6038 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6041 * NOTE It may be best to move the code into surface to occomplish this
6042 ****************************************/
6044 WINED3DSURFACE_DESC surfaceDesc;
6045 unsigned int surfaceWidth, surfaceHeight;
6046 glDescriptor *targetGlDescription = NULL;
6047 glDescriptor *surfaceGlDescription = NULL;
6048 IWineD3DSwapChainImpl *container = NULL;
6050 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6051 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6052 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6054 surfaceDesc.Width = &surfaceWidth;
6055 surfaceDesc.Height = &surfaceHeight;
6056 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6057 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6059 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6060 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6061 ENTER_GL();
6062 /* TODO: opengl Context switching for swapchains etc... */
6063 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6064 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6065 glReadBuffer(GL_BACK);
6066 vcheckGLcall("glReadBuffer(GL_BACK)");
6067 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6068 glReadBuffer(GL_FRONT);
6069 vcheckGLcall("glReadBuffer(GL_FRONT)");
6070 } else if (pRenderTarget == This->depthStencilBuffer) {
6071 FIXME("Reading of depthstencil not yet supported\n");
6074 glReadPixels(surfaceGlDescription->target,
6075 surfaceGlDescription->level,
6076 surfaceWidth,
6077 surfaceHeight,
6078 surfaceGlDescription->glFormat,
6079 surfaceGlDescription->glType,
6080 (void *)IWineD3DSurface_GetData(pSurface));
6081 vcheckGLcall("glReadPixels(...)");
6082 if(NULL != container ){
6083 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6085 } else {
6086 IWineD3DBaseTexture *container;
6087 GLenum textureDimensions = GL_TEXTURE_2D;
6089 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6090 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6091 IWineD3DBaseTexture_Release(container);
6093 /* TODO: 2D -> Cube surface coppies etc.. */
6094 if (surfaceGlDescription->target != textureDimensions) {
6095 FIXME("(%p) : Texture dimension mismatch\n", This);
6097 glEnable(textureDimensions);
6098 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6099 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6100 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6101 vcheckGLcall("glBindTexture");
6102 glGetTexImage(surfaceGlDescription->target,
6103 surfaceGlDescription->level,
6104 surfaceGlDescription->glFormat,
6105 surfaceGlDescription->glType,
6106 (void *)IWineD3DSurface_GetData(pSurface));
6107 glDisable(textureDimensions);
6108 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6111 LEAVE_GL();
6112 return WINED3D_OK;
6115 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6116 IWineD3DSwapChain *swapChain;
6117 HRESULT hr;
6118 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6119 if(hr == WINED3D_OK) {
6120 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6121 IWineD3DSwapChain_Release(swapChain);
6123 return hr;
6126 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 /* return a sensible default */
6129 *pNumPasses = 1;
6130 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6131 FIXME("(%p) : stub\n", This);
6132 return WINED3D_OK;
6135 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6137 int j;
6138 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6139 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6140 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6141 return WINED3DERR_INVALIDCALL;
6143 for (j = 0; j < 256; ++j) {
6144 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6145 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6146 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6147 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6149 TRACE("(%p) : returning\n", This);
6150 return WINED3D_OK;
6153 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6155 int j;
6156 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6157 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6158 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6159 return WINED3DERR_INVALIDCALL;
6161 for (j = 0; j < 256; ++j) {
6162 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6163 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6164 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6165 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6167 TRACE("(%p) : returning\n", This);
6168 return WINED3D_OK;
6171 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6173 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6174 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6175 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6176 return WINED3DERR_INVALIDCALL;
6178 /*TODO: stateblocks */
6179 This->currentPalette = PaletteNumber;
6180 TRACE("(%p) : returning\n", This);
6181 return WINED3D_OK;
6184 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6186 if (PaletteNumber == NULL) {
6187 WARN("(%p) : returning Invalid Call\n", This);
6188 return WINED3DERR_INVALIDCALL;
6190 /*TODO: stateblocks */
6191 *PaletteNumber = This->currentPalette;
6192 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6193 return WINED3D_OK;
6196 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6198 static BOOL showFixmes = TRUE;
6199 if (showFixmes) {
6200 FIXME("(%p) : stub\n", This);
6201 showFixmes = FALSE;
6204 This->softwareVertexProcessing = bSoftware;
6205 return WINED3D_OK;
6209 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6211 static BOOL showFixmes = TRUE;
6212 if (showFixmes) {
6213 FIXME("(%p) : stub\n", This);
6214 showFixmes = FALSE;
6216 return This->softwareVertexProcessing;
6220 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6222 IWineD3DSwapChain *swapChain;
6223 HRESULT hr;
6225 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6227 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6228 if(hr == WINED3D_OK){
6229 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6230 IWineD3DSwapChain_Release(swapChain);
6231 }else{
6232 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6234 return hr;
6238 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6240 static BOOL showfixmes = TRUE;
6241 if(nSegments != 0.0f) {
6242 if( showfixmes) {
6243 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6244 showfixmes = FALSE;
6247 return WINED3D_OK;
6250 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6252 static BOOL showfixmes = TRUE;
6253 if( showfixmes) {
6254 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6255 showfixmes = FALSE;
6257 return 0.0f;
6260 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6262 /** TODO: remove casts to IWineD3DSurfaceImpl
6263 * NOTE: move code to surface to accomplish this
6264 ****************************************/
6265 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6266 int srcWidth, srcHeight;
6267 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6268 WINED3DFORMAT destFormat, srcFormat;
6269 UINT destSize;
6270 int destLeft, destTop;
6271 WINED3DPOOL srcPool, destPool;
6272 int offset = 0;
6273 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6274 glDescriptor *glDescription = NULL;
6275 GLenum textureDimensions = GL_TEXTURE_2D;
6276 IWineD3DBaseTexture *baseTexture;
6278 WINED3DSURFACE_DESC winedesc;
6280 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6281 memset(&winedesc, 0, sizeof(winedesc));
6282 winedesc.Width = &srcSurfaceWidth;
6283 winedesc.Height = &srcSurfaceHeight;
6284 winedesc.Pool = &srcPool;
6285 winedesc.Format = &srcFormat;
6287 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6289 winedesc.Width = &destSurfaceWidth;
6290 winedesc.Height = &destSurfaceHeight;
6291 winedesc.Pool = &destPool;
6292 winedesc.Format = &destFormat;
6293 winedesc.Size = &destSize;
6295 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6297 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6298 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6299 return WINED3DERR_INVALIDCALL;
6302 if (destFormat == WINED3DFMT_UNKNOWN) {
6303 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6304 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6306 /* Get the update surface description */
6307 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6310 /* Make sure the surface is loaded and up to date */
6311 IWineD3DSurface_PreLoad(pDestinationSurface);
6313 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6315 ENTER_GL();
6317 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6318 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6319 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6320 destLeft = pDestPoint ? pDestPoint->x : 0;
6321 destTop = pDestPoint ? pDestPoint->y : 0;
6324 /* This function doesn't support compressed textures
6325 the pitch is just bytesPerPixel * width */
6326 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6327 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6328 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6329 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6331 /* TODO DXT formats */
6333 if(pSourceRect != NULL && pSourceRect->top != 0){
6334 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6336 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6337 ,This
6338 ,glDescription->level
6339 ,destLeft
6340 ,destTop
6341 ,srcWidth
6342 ,srcHeight
6343 ,glDescription->glFormat
6344 ,glDescription->glType
6345 ,IWineD3DSurface_GetData(pSourceSurface)
6348 /* Sanity check */
6349 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6351 /* need to lock the surface to get the data */
6352 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6355 /* TODO: Cube and volume support */
6356 if(rowoffset != 0){
6357 /* not a whole row so we have to do it a line at a time */
6358 int j;
6360 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6361 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6363 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6365 glTexSubImage2D(glDescription->target
6366 ,glDescription->level
6367 ,destLeft
6369 ,srcWidth
6371 ,glDescription->glFormat
6372 ,glDescription->glType
6373 ,data /* could be quicker using */
6375 data += rowoffset;
6378 } else { /* Full width, so just write out the whole texture */
6380 if (WINED3DFMT_DXT1 == destFormat ||
6381 WINED3DFMT_DXT2 == destFormat ||
6382 WINED3DFMT_DXT3 == destFormat ||
6383 WINED3DFMT_DXT4 == destFormat ||
6384 WINED3DFMT_DXT5 == destFormat) {
6385 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6386 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6387 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6388 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6389 } if (destFormat != srcFormat) {
6390 FIXME("Updating mixed format compressed texture is not curretly support\n");
6391 } else {
6392 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6393 glDescription->level,
6394 glDescription->glFormatInternal,
6395 srcWidth,
6396 srcHeight,
6398 destSize,
6399 IWineD3DSurface_GetData(pSourceSurface));
6401 } else {
6402 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6406 } else {
6407 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6409 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6410 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6411 data returned by GetData non-power2 width/height with hardware non-power2
6412 pow2Width/height are set to surface width height, repacking isn't needed so it
6413 doesn't matter which function gets called. */
6414 glTexSubImage2D(glDescription->target
6415 ,glDescription->level
6416 ,destLeft
6417 ,destTop
6418 ,srcWidth
6419 ,srcHeight
6420 ,glDescription->glFormat
6421 ,glDescription->glType
6422 ,IWineD3DSurface_GetData(pSourceSurface)
6424 } else {
6426 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6427 glTexSubImage2D(glDescription->target
6428 ,glDescription->level
6429 ,destLeft
6430 ,destTop
6431 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6432 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6433 ,glDescription->glFormat
6434 ,glDescription->glType
6435 ,IWineD3DSurface_GetData(pSourceSurface)
6441 checkGLcall("glTexSubImage2D");
6443 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6444 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6445 * surface bigger than it needs to be hmm.. */
6446 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6447 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6448 IWineD3DBaseTexture_Release(baseTexture);
6451 glDisable(textureDimensions); /* This needs to be managed better.... */
6452 LEAVE_GL();
6454 return WINED3D_OK;
6457 /* Used by DirectX 8 */
6458 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6459 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6460 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6463 HRESULT hr = WINED3D_OK;
6464 WINED3DFORMAT srcFormat, destFormat;
6465 UINT srcWidth, destWidth;
6466 UINT srcHeight, destHeight;
6467 UINT srcSize;
6468 WINED3DSURFACE_DESC winedesc;
6470 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6471 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6474 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6475 memset(&winedesc, 0, sizeof(winedesc));
6477 winedesc.Format = &srcFormat;
6478 winedesc.Width = &srcWidth;
6479 winedesc.Height = &srcHeight;
6480 winedesc.Size = &srcSize;
6481 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6483 winedesc.Format = &destFormat;
6484 winedesc.Width = &destWidth;
6485 winedesc.Height = &destHeight;
6486 winedesc.Size = NULL;
6487 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6489 /* Check that the source and destination formats match */
6490 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6491 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6492 return WINED3DERR_INVALIDCALL;
6493 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6494 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6495 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6496 destFormat = srcFormat;
6499 /* Quick if complete copy ... */
6500 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6502 if (srcWidth == destWidth && srcHeight == destHeight) {
6503 WINED3DLOCKED_RECT lrSrc;
6504 WINED3DLOCKED_RECT lrDst;
6505 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6506 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6507 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6509 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6511 IWineD3DSurface_UnlockRect(pSourceSurface);
6512 IWineD3DSurface_UnlockRect(pDestinationSurface);
6513 TRACE("Unlocked src and dst\n");
6515 } else {
6517 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6518 hr = WINED3DERR_INVALIDCALL;
6521 } else {
6523 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6525 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6526 unsigned int i;
6528 /* Copy rect by rect */
6529 for (i = 0; i < cRects; ++i) {
6530 CONST RECT* r = &pSourceRectsArray[i];
6531 CONST POINT* p = &pDestPointsArray[i];
6532 int copyperline;
6533 int j;
6534 WINED3DLOCKED_RECT lrSrc;
6535 WINED3DLOCKED_RECT lrDst;
6536 RECT dest_rect;
6538 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6539 if (srcFormat == WINED3DFMT_DXT1) {
6540 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6541 } else {
6542 copyperline = ((r->right - r->left) * bytesPerPixel);
6545 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6546 dest_rect.left = p->x;
6547 dest_rect.top = p->y;
6548 dest_rect.right = p->x + (r->right - r->left);
6549 dest_rect.bottom= p->y + (r->bottom - r->top);
6550 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6551 TRACE("Locked src and dst\n");
6553 /* Find where to start */
6554 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6555 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6557 IWineD3DSurface_UnlockRect(pSourceSurface);
6558 IWineD3DSurface_UnlockRect(pDestinationSurface);
6559 TRACE("Unlocked src and dst\n");
6561 } else {
6562 FIXME("Wanted to copy partial surfaces not implemented, returning WINED3DERR_INVALIDCALL\n");
6563 hr = WINED3DERR_INVALIDCALL;
6567 return hr;
6570 /* Implementation details at http://developer.nvidia.com/attach/6494
6572 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6573 hmm.. no longer supported use
6574 OpenGL evaluators or tessellate surfaces within your application.
6577 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6578 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6580 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6581 FIXME("(%p) : Stub\n", This);
6582 return WINED3D_OK;
6586 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6587 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6589 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6590 FIXME("(%p) : Stub\n", This);
6591 return WINED3D_OK;
6594 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6596 TRACE("(%p) Handle(%d)\n", This, Handle);
6597 FIXME("(%p) : Stub\n", This);
6598 return WINED3D_OK;
6601 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6602 /* I couldn't find a 'really' quick way of doing this in openGl so here goes
6603 fill a surface with a block of color! */
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6605 /* TODO: get rid of the use of IWineD3DSurfaceImpl, move code into surface.c */
6606 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)pSurface;
6607 IWineD3DSwapChainImpl *container = NULL;
6608 BOOL isRenderTarget = FALSE;
6609 unsigned int width, height;
6610 unsigned int top, left;
6611 unsigned int u, v;
6612 DWORD *data;
6613 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6615 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6616 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6617 return WINED3DERR_INVALIDCALL;
6620 /* TODO: get rid of IWineD3DSwapChainImpl reference, a 'context' manager may help with this */
6621 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DSwapChain, (void **)&container) || pSurface == This->renderTarget) {
6622 if (WINED3DUSAGE_RENDERTARGET & surface->resource.usage) {
6623 /* TODO: make sure we set everything back to the way it was, and context management!
6624 glGetIntegerv(GL_READ_BUFFER, &prev_read);
6625 vcheckGLcall("glIntegerv");
6626 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
6627 vcheckGLcall("glIntegerv");
6629 TRACE("Color fill to render targets may cause some graphics issues\n");
6630 if (pSurface == container->frontBuffer) {
6631 glDrawBuffer(GL_FRONT);
6632 } else {
6633 glDrawBuffer(GL_BACK);
6635 } else {
6636 if (WINED3DUSAGE_DEPTHSTENCIL & surface->resource.usage) {
6637 FIXME("colouring of depth_stencil? %p buffers is not yet supported? %ld\n", surface, surface->resource.usage);
6638 } else {
6639 FIXME("(%p) : Regression %ld %p %p\n", This, surface->resource.usage, pSurface, This->renderTarget);
6641 if (container != NULL) {
6642 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6644 /* we can use GL_STENCIL_INDEX etc...*/
6645 return WINED3D_OK;
6647 if (container != NULL) {
6648 IWineD3DSwapChain_Release((IWineD3DSwapChain *)container);
6650 isRenderTarget = TRUE;
6652 /* TODO: drawing to GL_FRONT and GL_BACK */
6653 /* TODO: see if things can be speeded up by using the correct
6654 * colour model of the target texture from the start (16 bit graphics on 32 X are slow anyway!) */
6655 if (pRect == NULL) {
6656 top = 0;
6657 left = 0;
6658 width = surface->currentDesc.Width;
6659 height = surface->currentDesc.Height;
6660 } else {
6661 left = pRect->x1;
6662 top = pRect->y1;
6663 width = pRect->x2 - left;
6664 height = pRect->y2 - top;
6667 data = HeapAlloc(GetProcessHeap(), 0, 4 * width);
6668 /* Create a 'line' of color color, in the correct format for the surface */
6669 for (u = 0 ; u < width ; u ++) {
6670 data[u] = color;
6673 ENTER_GL();
6674 if (isRenderTarget == FALSE) {
6675 glDescriptor *glDesc;
6676 IWineD3DSurface_PreLoad(pSurface);
6678 /* draw a block of the coloured line on the sufrace */
6679 IWineD3DSurface_GetGlDesc(pSurface, &glDesc);
6680 for (v = 0 ; v< height;v++) {
6681 glTexSubImage2D(glDesc->target
6682 ,glDesc->level /* level */
6683 ,left
6684 ,top + v
6685 ,width
6686 ,1 /* height */
6687 ,GL_RGBA
6688 ,GL_UNSIGNED_BYTE
6689 ,data
6692 checkGLcall("glTexSubImage2D");
6693 /* clean up */
6694 glDisable(glDesc->target);
6695 } else {
6696 /** FIXME: Using GLClear may be faster **/
6697 glRasterPos2i(left, top);
6698 glPixelZoom((float)width ,(float)height);
6699 glDrawPixels(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
6700 checkGLcall("glDrawPixels");
6702 HeapFree(GetProcessHeap(), 0, data);
6703 LEAVE_GL();
6704 return WINED3D_OK;
6708 /* rendertarget and deptth stencil functions */
6709 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6712 /* FIXME: Implelent RenderTargetIndex >0 */
6713 if(RenderTargetIndex > 0)
6714 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
6716 *ppRenderTarget = This->renderTarget;
6717 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6718 /* Note inc ref on returned surface */
6719 if(*ppRenderTarget != NULL)
6720 IWineD3DSurface_AddRef(*ppRenderTarget);
6721 return WINED3D_OK;
6724 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6726 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6727 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6728 IWineD3DSwapChainImpl *Swapchain;
6729 HRESULT hr;
6731 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6733 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6734 if(hr != WINED3D_OK) {
6735 ERR("Can't get the swapchain\n");
6736 return hr;
6739 /* Make sure to release the swapchain */
6740 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6742 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6743 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6744 return WINED3DERR_INVALIDCALL;
6746 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6747 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6748 return WINED3DERR_INVALIDCALL;
6751 if(Swapchain->frontBuffer != Front) {
6752 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6754 if(Swapchain->frontBuffer)
6755 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6756 Swapchain->frontBuffer = Front;
6758 if(Swapchain->frontBuffer) {
6759 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6763 if(Back && !Swapchain->backBuffer) {
6764 /* We need memory for the back buffer array - only one back buffer this way */
6765 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6766 if(!Swapchain->backBuffer) {
6767 ERR("Out of memory\n");
6768 return E_OUTOFMEMORY;
6772 if(Swapchain->backBuffer[0] != Back) {
6773 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6774 ENTER_GL();
6775 if(!Swapchain->backBuffer[0]) {
6776 /* GL was told to draw to the front buffer at creation,
6777 * undo that
6779 glDrawBuffer(GL_BACK);
6780 checkGLcall("glDrawBuffer(GL_BACK)");
6781 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6782 Swapchain->presentParms.BackBufferCount = 1;
6783 } else if (!Back) {
6784 /* That makes problems - disable for now */
6785 /* glDrawBuffer(GL_FRONT); */
6786 checkGLcall("glDrawBuffer(GL_FRONT)");
6787 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6788 Swapchain->presentParms.BackBufferCount = 0;
6790 LEAVE_GL();
6792 if(Swapchain->backBuffer[0])
6793 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6794 Swapchain->backBuffer[0] = Back;
6796 if(Swapchain->backBuffer[0]) {
6797 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6798 } else {
6799 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6804 return WINED3D_OK;
6807 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6809 *ppZStencilSurface = This->depthStencilBuffer;
6810 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6812 if(*ppZStencilSurface != NULL) {
6813 /* Note inc ref on returned surface */
6814 IWineD3DSurface_AddRef(*ppZStencilSurface);
6816 return WINED3D_OK;
6819 /* internal static helper functions */
6820 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6821 IWineD3DSurface *RenderSurface);
6823 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6825 HRESULT hr = WINED3D_OK;
6826 WINED3DVIEWPORT viewport;
6828 TRACE("(%p) Swapping rendertarget\n",This);
6829 if (RenderTargetIndex > 0) {
6830 FIXME("(%p) Render targets other than the first are not supported\n",This);
6831 RenderTargetIndex = 0;
6834 /* MSDN says that null disables the render target
6835 but a device must always be associated with a render target
6836 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6838 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6839 for more details
6841 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6842 FIXME("Trying to set render target 0 to NULL\n");
6843 return WINED3DERR_INVALIDCALL;
6845 /* TODO: replace Impl* usage with interface usage */
6846 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6847 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);
6848 return WINED3DERR_INVALIDCALL;
6850 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
6851 * builds, but I think wine counts as a 'debug' build for now.
6852 ******************************/
6853 /* If we are trying to set what we already have, don't bother */
6854 if (pRenderTarget == This->renderTarget) {
6855 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6856 } else {
6857 /* Otherwise, set the render target up */
6859 if (FALSE == This->sceneEnded) {
6860 IWineD3DDevice_EndScene(iface);
6862 TRACE("clearing renderer\n");
6863 /* IWineD3DDeviceImpl_CleanRender(iface); */
6864 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6865 depending on the renter target implementation being used.
6866 A shared context implementation will share all buffers between all rendertargets (including swapchains),
6867 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6868 stencil buffer and incure an extra memory overhead */
6869 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
6872 if (SUCCEEDED(hr)) {
6873 /* Finally, reset the viewport as the MSDN states. */
6874 /* TODO: Replace impl usage */
6875 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
6876 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
6877 viewport.X = 0;
6878 viewport.Y = 0;
6879 viewport.MaxZ = 1.0f;
6880 viewport.MinZ = 0.0f;
6881 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6882 } else {
6883 FIXME("Unknown error setting the render target\n");
6885 This->sceneEnded = FALSE;
6886 return hr;
6889 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6891 HRESULT hr = WINED3D_OK;
6892 IWineD3DSurface *tmp;
6894 TRACE("(%p) Swapping z-buffer\n",This);
6896 if (pNewZStencil == This->stencilBufferTarget) {
6897 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6898 } else {
6899 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6900 * depending on the renter target implementation being used.
6901 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6902 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6903 * stencil buffer and incure an extra memory overhead
6904 ******************************************************/
6907 tmp = This->stencilBufferTarget;
6908 This->stencilBufferTarget = pNewZStencil;
6909 /* should we be calling the parent or the wined3d surface? */
6910 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6911 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6912 hr = WINED3D_OK;
6913 /** TODO: glEnable/glDisable on depth/stencil depending on
6914 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
6915 **********************************************************/
6918 return hr;
6922 #ifdef GL_VERSION_1_3
6923 /* Internal functions not in DirectX */
6924 /** TODO: move this off to the opengl context manager
6925 *(the swapchain doesn't need to know anything about offscreen rendering!)
6926 ****************************************************/
6928 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
6930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6932 TRACE("(%p), %p\n", This, swapchain);
6934 if (swapchain->win != swapchain->drawable) {
6935 /* Set everything back the way it ws */
6936 swapchain->render_ctx = swapchain->glCtx;
6937 swapchain->drawable = swapchain->win;
6939 return WINED3D_OK;
6942 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
6943 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
6944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6945 int i;
6946 unsigned int width;
6947 unsigned int height;
6948 WINED3DFORMAT format;
6949 WINED3DSURFACE_DESC surfaceDesc;
6950 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6951 surfaceDesc.Width = &width;
6952 surfaceDesc.Height = &height;
6953 surfaceDesc.Format = &format;
6954 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6955 *context = NULL;
6956 /* I need a get width/height function (and should do something with the format) */
6957 for (i = 0; i < CONTEXT_CACHE; ++i) {
6958 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
6959 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
6960 the pSurface can be set to 0 allowing it to be reused from cache **/
6961 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
6962 && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
6963 *context = &This->contextCache[i];
6964 break;
6966 if (This->contextCache[i].Width == 0) {
6967 This->contextCache[i].pSurface = pSurface;
6968 This->contextCache[i].Width = width;
6969 This->contextCache[i].Height = height;
6970 *context = &This->contextCache[i];
6971 break;
6974 if (i == CONTEXT_CACHE) {
6975 int minUsage = 0x7FFFFFFF; /* MAX_INT */
6976 glContext *dropContext = 0;
6977 for (i = 0; i < CONTEXT_CACHE; i++) {
6978 if (This->contextCache[i].usedcount < minUsage) {
6979 dropContext = &This->contextCache[i];
6980 minUsage = This->contextCache[i].usedcount;
6983 /* clean up the context (this doesn't work for ATI at the moment */
6984 #if 0
6985 glXDestroyContext(swapchain->display, dropContext->context);
6986 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
6987 #endif
6988 FIXME("Leak\n");
6989 dropContext->Width = 0;
6990 dropContext->pSurface = pSurface;
6991 *context = dropContext;
6992 } else {
6993 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
6994 for (i = 0; i < CONTEXT_CACHE; i++) {
6995 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
6999 if (*context != NULL)
7000 return WINED3D_OK;
7001 else
7002 return E_OUTOFMEMORY;
7004 #endif
7006 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7007 * the functionality needs splitting up so that we don't do more than we should do.
7008 * this only seems to impact performance a little.
7009 ******************************/
7010 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7011 IWineD3DSurface *RenderSurface) {
7012 HRESULT ret = WINED3DERR_INVALIDCALL;
7015 * Currently only active for GLX >= 1.3
7016 * for others versions we'll have to use GLXPixmaps
7018 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7019 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7020 * so only check OpenGL version
7021 * ..........................
7022 * I don't believe that it is a problem with NVidia headers,
7023 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7024 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7025 * ATI Note:
7026 * Your application will report GLX version 1.2 on glXQueryVersion.
7027 * However, it is safe to call the GLX 1.3 functions as described below.
7029 #if defined(GL_VERSION_1_3)
7031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7032 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7033 IWineD3DSurface *tmp;
7034 /** TODO: we only need to look up the configuration !IF! we are setting the target to a texture **/
7035 GLXFBConfig* cfgs = NULL;
7036 int nCfgs = 0;
7037 int attribs[256];
7038 int nAttribs = 0;
7039 IWineD3DSwapChain *currentSwapchain;
7040 IWineD3DSwapChainImpl *swapchain;
7041 /** TODO: get rid of Impl usage we should always create a zbuffer/stencil with our contexts if possible,
7042 * but switch them off if the StencilSurface is set to NULL
7043 ** *********************************************************/
7044 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7045 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7047 /**TODO:
7048 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7049 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7052 #define PUSH1(att) attribs[nAttribs++] = (att);
7053 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7055 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7057 /** TODO: remove the reff to Impl (context manager should fix this!) **/
7058 IWineD3DSwapChainImpl *impSwapChain;
7059 IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&impSwapChain);
7060 if (NULL == impSwapChain) { /* NOTE: This should NEVER fail */
7061 ERR("(%p) Failed to get a the implicit swapchain\n", iface);
7064 ENTER_GL();
7066 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7067 PUSH2(GLX_X_RENDERABLE, TRUE);
7068 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7069 TRACE("calling makeglcfg\n");
7070 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7071 PUSH1(None);
7073 TRACE("calling chooseFGConfig\n");
7074 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7075 attribs, &nCfgs);
7077 if (!cfgs) { /* OK we didn't find the exact config, so use any reasonable match */
7078 /* TODO: fill in the 'requested' and 'current' depths, also make sure that's
7079 why we failed and only show this message once! */
7080 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"); /**/
7081 nAttribs = 0;
7082 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7083 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7084 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7085 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7086 TRACE("calling makeglcfg\n");
7087 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7088 PUSH1(None);
7089 cfgs = glXChooseFBConfig(impSwapChain->display, DefaultScreen(impSwapChain->display),
7090 attribs, &nCfgs);
7093 if (NULL != cfgs) {
7094 #ifdef EXTRA_TRACES
7095 int i;
7096 for (i = 0; i < nCfgs; ++i) {
7097 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7098 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7099 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7102 if (NULL != This->renderTarget) {
7103 glFlush();
7104 vcheckGLcall("glFlush");
7105 /** This is only useful if the old render target was a swapchain,
7106 * we need to supercede this with a function that displays
7107 * the current buffer on the screen. This is easy to do in glx1.3 but
7108 * we need to do copy-write pixels in glx 1.2.
7109 ************************************************/
7110 glXSwapBuffers(impSwapChain->display, impSwapChain->drawable);
7112 printf("Hit Enter to get next frame ...\n");
7113 getchar();
7115 #endif
7118 if (IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain) != WINED3D_OK) {
7119 /* the selected render target doesn't belong to a swapchain, so use the devices implicit swapchain */
7120 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7124 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7125 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7126 **********************************************************************/
7127 if (IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void **)&swapchain) == WINED3D_OK) {
7128 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7129 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7130 TRACE("making swapchain active\n");
7131 if (RenderSurface != This->renderTarget) {
7132 BOOL backbuf = FALSE;
7133 int i;
7135 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7136 if(RenderSurface == swapchain->backBuffer[i]) {
7137 backbuf = TRUE;
7138 break;
7142 if (backbuf) {
7143 } else {
7144 /* This could be flagged so that some operations work directly with the front buffer */
7145 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7147 if (glXMakeCurrent(swapchain->display, swapchain->win, swapchain->glCtx)
7148 == False) {
7149 TRACE("Error in setting current context: context %p drawable %ld !\n",
7150 impSwapChain->glCtx, impSwapChain->win);
7153 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7155 checkGLcall("glXMakeContextCurrent");
7157 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7159 else if (pbuffer_support && cfgs != NULL /* && some test to make sure that opengl supports pbuffers */) {
7161 /** ********************************************************************
7162 * This is a quickly hacked out implementation of offscreen textures.
7163 * It will work in most cases but there may be problems if the client
7164 * modifies the texture directly, or expects the contents of the rendertarget
7165 * to be persistent.
7167 * There are some real speed vs compatibility issues here:
7168 * we should really use a new context for every texture, but that eats ram.
7169 * we should also be restoring the texture to the pbuffer but that eats CPU
7170 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7171 * but if this means reusing the display backbuffer then we need to make sure that
7172 * states are correctly preserved.
7173 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7174 * and gain a good performance increase at the cost of compatibility.
7175 * I would suggest that, when this is the case, a user configurable flag be made
7176 * available, allowing the user to choose the best emulated experience for them.
7177 *********************************************************************/
7179 XVisualInfo *visinfo;
7180 glContext *newContext;
7182 /* Here were using a shared context model */
7183 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7184 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7187 /* If the context doesn't exist then create a new one */
7188 /* TODO: This should really be part of findGlContext */
7189 if (NULL == newContext->context) {
7191 TRACE("making new buffer\n");
7192 nAttribs = 0;
7193 PUSH2(GLX_PBUFFER_WIDTH, newContext->Width);
7194 PUSH2(GLX_PBUFFER_HEIGHT, newContext->Height);
7195 PUSH1(None);
7197 newContext->drawable = glXCreatePbuffer(impSwapChain->display, cfgs[0], attribs);
7199 /** ****************************************
7200 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7201 *they note:
7202 * In future releases, we may provide the calls glXCreateNewContext,
7203 * glXQueryDrawable and glXMakeContextCurrent.
7204 * so until then we have to use glXGetVisualFromFBConfig &co..
7205 ********************************************/
7208 visinfo = glXGetVisualFromFBConfig(impSwapChain->display, cfgs[0]);
7209 if (!visinfo) {
7210 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7211 } else {
7212 newContext->context = glXCreateContext(impSwapChain->display, visinfo, impSwapChain->glCtx, GL_TRUE);
7213 XFree(visinfo);
7216 if (NULL == newContext || NULL == newContext->context) {
7217 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7218 } else {
7219 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7220 if (glXMakeCurrent(impSwapChain->display, newContext->drawable, newContext->context) == False) {
7221 TRACE("Error in setting current context: context %p drawable %ld\n", newContext->context, newContext->drawable);
7224 /* Clean up the old context */
7225 IWineD3DDeviceImpl_CleanRender(iface, (IWineD3DSwapChainImpl *)currentSwapchain);
7226 /* Set the current context of the swapchain to the new context */
7227 impSwapChain->drawable = newContext->drawable;
7228 impSwapChain->render_ctx = newContext->context;
7232 #if 1 /* Apply the stateblock to the new context
7233 FIXME: This is a bit of a hack, each context should know it's own state,
7234 the directX current directX state should then be applied to the context */
7236 BOOL oldRecording;
7237 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7238 oldUpdateStateBlock = This->updateStateBlock;
7239 oldRecording= This->isRecordingState;
7240 This->isRecordingState = FALSE;
7241 This->updateStateBlock = This->stateBlock;
7242 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7244 This->isRecordingState = oldRecording;
7245 This->updateStateBlock = oldUpdateStateBlock;
7247 #endif
7250 /* clean up the current rendertargets swapchain (if it belonged to one) */
7251 if (currentSwapchain != NULL) {
7252 IWineD3DSwapChain_Release((IWineD3DSwapChain *)currentSwapchain);
7255 /* Were done with the opengl context management, setup the rendertargets */
7257 tmp = This->renderTarget;
7258 This->renderTarget = RenderSurface;
7259 IWineD3DSurface_AddRef(This->renderTarget);
7260 IWineD3DSurface_Release(tmp);
7265 DWORD value;
7266 /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
7267 /* Check that the container is not a swapchain member */
7269 IWineD3DSwapChain *tmpSwapChain;
7270 if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
7271 This->renderUpsideDown = TRUE;
7272 }else{
7273 This->renderUpsideDown = FALSE;
7274 IWineD3DSwapChain_Release(tmpSwapChain);
7276 /* Force updating the cull mode */
7277 TRACE("setting render state\n");
7278 IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
7279 IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
7281 /* Force updating projection matrix */
7282 This->last_was_rhw = FALSE;
7283 This->proj_valid = FALSE;
7286 ret = WINED3D_OK;
7288 if (cfgs != NULL) {
7289 XFree(cfgs);
7290 } else {
7291 ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat,
7292 debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7295 #undef PUSH1
7296 #undef PUSH2
7297 if ( NULL != impSwapChain) {
7298 IWineD3DSwapChain_Release((IWineD3DSwapChain *)impSwapChain);
7300 LEAVE_GL();
7302 #endif
7303 return ret;
7306 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7307 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7309 /* TODO: the use of Impl is deprecated. */
7310 /* some basic validation checks */
7311 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7313 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7315 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7316 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7317 return WINED3DERR_INVALIDCALL;
7319 if (32 != pSur->currentDesc.Height || 32 != pSur->currentDesc.Width) {
7320 ERR("(%p) : surface(%p) has an invalid size\n", This, pCursorBitmap);
7321 return WINED3DERR_INVALIDCALL;
7323 /* TODO: make the cursor 'real' */
7325 This->xHotSpot = XHotSpot;
7326 This->yHotSpot = YHotSpot;
7328 return WINED3D_OK;
7331 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7333 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7335 This->xScreenSpace = XScreenSpace;
7336 This->yScreenSpace = YScreenSpace;
7338 return;
7342 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7344 TRACE("(%p) : visible(%d)\n", This, bShow);
7346 This->bCursorVisible = bShow;
7348 return WINED3D_OK;
7351 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7353 TRACE("(%p) : state (%lu)\n", This, This->state);
7354 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7355 switch (This->state) {
7356 case WINED3D_OK:
7357 return WINED3D_OK;
7358 case WINED3DERR_DEVICELOST:
7360 ResourceList *resourceList = This->resources;
7361 while (NULL != resourceList) {
7362 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7363 return WINED3DERR_DEVICENOTRESET;
7364 resourceList = resourceList->next;
7366 return WINED3DERR_DEVICELOST;
7368 case WINED3DERR_DRIVERINTERNALERROR:
7369 return WINED3DERR_DRIVERINTERNALERROR;
7372 /* Unknown state */
7373 return WINED3DERR_DRIVERINTERNALERROR;
7377 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7379 /** FIXME: Resource tracking needs to be done,
7380 * The closes we can do to this is set the priorities of all managed textures low
7381 * and then reset them.
7382 ***********************************************************/
7383 FIXME("(%p) : stub\n", This);
7384 return WINED3D_OK;
7387 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7389 /** FIXME: Resource trascking needs to be done.
7390 * in effect this pulls all non only default
7391 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7392 * and should clear down the context and set it up according to pPresentationParameters
7393 ***********************************************************/
7394 FIXME("(%p) : stub\n", This);
7395 return WINED3D_OK;
7398 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7400 /** FIXME: always true at the moment **/
7401 if(bEnableDialogs == FALSE) {
7402 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7404 return WINED3D_OK;
7408 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7410 TRACE("(%p) : pParameters %p\n", This, pParameters);
7412 *pParameters = This->createParms;
7413 return WINED3D_OK;
7416 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7417 IWineD3DSwapChain *swapchain;
7418 HRESULT hrc = WINED3D_OK;
7420 TRACE("Relaying to swapchain\n");
7422 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7423 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7424 IWineD3DSwapChain_Release(swapchain);
7426 return;
7429 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7430 IWineD3DSwapChain *swapchain;
7431 HRESULT hrc = WINED3D_OK;
7433 TRACE("Relaying to swapchain\n");
7435 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7436 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7437 IWineD3DSwapChain_Release(swapchain);
7439 return;
7443 /** ********************************************************
7444 * Notification functions
7445 ** ********************************************************/
7446 /** This function must be called in the release of a resource when ref == 0,
7447 * the contents of resource must still be correct,
7448 * any handels to other resource held by the caller must be closed
7449 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7450 *****************************************************/
7451 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7453 ResourceList* resourceList;
7455 TRACE("(%p) : resource %p\n", This, resource);
7456 #if 0
7457 EnterCriticalSection(&resourceStoreCriticalSection);
7458 #endif
7459 /* add a new texture to the frot of the linked list */
7460 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7461 resourceList->resource = resource;
7463 /* Get the old head */
7464 resourceList->next = This->resources;
7466 This->resources = resourceList;
7467 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7469 #if 0
7470 LeaveCriticalSection(&resourceStoreCriticalSection);
7471 #endif
7472 return;
7475 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7477 ResourceList* resourceList = NULL;
7478 ResourceList* previousResourceList = NULL;
7480 TRACE("(%p) : resource %p\n", This, resource);
7482 #if 0
7483 EnterCriticalSection(&resourceStoreCriticalSection);
7484 #endif
7485 resourceList = This->resources;
7487 while (resourceList != NULL) {
7488 if(resourceList->resource == resource) break;
7489 previousResourceList = resourceList;
7490 resourceList = resourceList->next;
7493 if (resourceList == NULL) {
7494 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7495 #if 0
7496 LeaveCriticalSection(&resourceStoreCriticalSection);
7497 #endif
7498 return;
7499 } else {
7500 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7502 /* make sure we don't leave a hole in the list */
7503 if (previousResourceList != NULL) {
7504 previousResourceList->next = resourceList->next;
7505 } else {
7506 This->resources = resourceList->next;
7509 #if 0
7510 LeaveCriticalSection(&resourceStoreCriticalSection);
7511 #endif
7512 return;
7516 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7518 int counter;
7520 TRACE("(%p) : resource %p\n", This, resource);
7521 switch(IWineD3DResource_GetType(resource)){
7522 case WINED3DRTYPE_SURFACE:
7523 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7524 break;
7525 case WINED3DRTYPE_TEXTURE:
7526 case WINED3DRTYPE_CUBETEXTURE:
7527 case WINED3DRTYPE_VOLUMETEXTURE:
7528 for (counter = 0; counter < GL_LIMITS(textures); counter++) {
7529 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7530 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7531 This->stateBlock->textures[counter] = NULL;
7533 if (This->updateStateBlock != This->stateBlock ){
7534 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7535 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7536 This->updateStateBlock->textures[counter] = NULL;
7540 break;
7541 case WINED3DRTYPE_VOLUME:
7542 /* TODO: nothing really? */
7543 break;
7544 case WINED3DRTYPE_VERTEXBUFFER:
7545 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7547 int streamNumber;
7548 TRACE("Cleaning up stream pointers\n");
7550 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7551 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7552 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7554 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7555 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7556 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7557 This->updateStateBlock->streamSource[streamNumber] = 0;
7558 /* Set changed flag? */
7561 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) */
7562 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7563 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7564 This->stateBlock->streamSource[streamNumber] = 0;
7567 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7568 else { /* This shouldn't happen */
7569 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7571 #endif
7575 break;
7576 case WINED3DRTYPE_INDEXBUFFER:
7577 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7578 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7579 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7580 This->updateStateBlock->pIndexData = NULL;
7583 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7584 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7585 This->stateBlock->pIndexData = NULL;
7589 break;
7590 default:
7591 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7592 break;
7596 /* Remove the resoruce from the resourceStore */
7597 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7599 TRACE("Resource released\n");
7603 /**********************************************************
7604 * IWineD3DDevice VTbl follows
7605 **********************************************************/
7607 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7609 /*** IUnknown methods ***/
7610 IWineD3DDeviceImpl_QueryInterface,
7611 IWineD3DDeviceImpl_AddRef,
7612 IWineD3DDeviceImpl_Release,
7613 /*** IWineD3DDevice methods ***/
7614 IWineD3DDeviceImpl_GetParent,
7615 /*** Creation methods**/
7616 IWineD3DDeviceImpl_CreateVertexBuffer,
7617 IWineD3DDeviceImpl_CreateIndexBuffer,
7618 IWineD3DDeviceImpl_CreateStateBlock,
7619 IWineD3DDeviceImpl_CreateSurface,
7620 IWineD3DDeviceImpl_CreateTexture,
7621 IWineD3DDeviceImpl_CreateVolumeTexture,
7622 IWineD3DDeviceImpl_CreateVolume,
7623 IWineD3DDeviceImpl_CreateCubeTexture,
7624 IWineD3DDeviceImpl_CreateQuery,
7625 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7626 IWineD3DDeviceImpl_CreateVertexDeclaration,
7627 IWineD3DDeviceImpl_CreateVertexShader,
7628 IWineD3DDeviceImpl_CreatePixelShader,
7629 IWineD3DDeviceImpl_CreatePalette,
7630 /*** Odd functions **/
7631 IWineD3DDeviceImpl_Init3D,
7632 IWineD3DDeviceImpl_Uninit3D,
7633 IWineD3DDeviceImpl_EnumDisplayModes,
7634 IWineD3DDeviceImpl_EvictManagedResources,
7635 IWineD3DDeviceImpl_GetAvailableTextureMem,
7636 IWineD3DDeviceImpl_GetBackBuffer,
7637 IWineD3DDeviceImpl_GetCreationParameters,
7638 IWineD3DDeviceImpl_GetDeviceCaps,
7639 IWineD3DDeviceImpl_GetDirect3D,
7640 IWineD3DDeviceImpl_GetDisplayMode,
7641 IWineD3DDeviceImpl_SetDisplayMode,
7642 IWineD3DDeviceImpl_GetHWND,
7643 IWineD3DDeviceImpl_SetHWND,
7644 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7645 IWineD3DDeviceImpl_GetRasterStatus,
7646 IWineD3DDeviceImpl_GetSwapChain,
7647 IWineD3DDeviceImpl_Reset,
7648 IWineD3DDeviceImpl_SetDialogBoxMode,
7649 IWineD3DDeviceImpl_SetCursorProperties,
7650 IWineD3DDeviceImpl_SetCursorPosition,
7651 IWineD3DDeviceImpl_ShowCursor,
7652 IWineD3DDeviceImpl_TestCooperativeLevel,
7653 IWineD3DDeviceImpl_EnumZBufferFormats,
7654 IWineD3DDeviceImpl_EnumTextureFormats,
7655 /*** Getters and setters **/
7656 IWineD3DDeviceImpl_SetClipPlane,
7657 IWineD3DDeviceImpl_GetClipPlane,
7658 IWineD3DDeviceImpl_SetClipStatus,
7659 IWineD3DDeviceImpl_GetClipStatus,
7660 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7661 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7662 IWineD3DDeviceImpl_SetDepthStencilSurface,
7663 IWineD3DDeviceImpl_GetDepthStencilSurface,
7664 IWineD3DDeviceImpl_SetFVF,
7665 IWineD3DDeviceImpl_GetFVF,
7666 IWineD3DDeviceImpl_SetGammaRamp,
7667 IWineD3DDeviceImpl_GetGammaRamp,
7668 IWineD3DDeviceImpl_SetIndices,
7669 IWineD3DDeviceImpl_GetIndices,
7670 IWineD3DDeviceImpl_SetLight,
7671 IWineD3DDeviceImpl_GetLight,
7672 IWineD3DDeviceImpl_SetLightEnable,
7673 IWineD3DDeviceImpl_GetLightEnable,
7674 IWineD3DDeviceImpl_SetMaterial,
7675 IWineD3DDeviceImpl_GetMaterial,
7676 IWineD3DDeviceImpl_SetNPatchMode,
7677 IWineD3DDeviceImpl_GetNPatchMode,
7678 IWineD3DDeviceImpl_SetPaletteEntries,
7679 IWineD3DDeviceImpl_GetPaletteEntries,
7680 IWineD3DDeviceImpl_SetPixelShader,
7681 IWineD3DDeviceImpl_GetPixelShader,
7682 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7683 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7684 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7685 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7686 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7687 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7688 IWineD3DDeviceImpl_SetRenderState,
7689 IWineD3DDeviceImpl_GetRenderState,
7690 IWineD3DDeviceImpl_SetRenderTarget,
7691 IWineD3DDeviceImpl_GetRenderTarget,
7692 IWineD3DDeviceImpl_SetFrontBackBuffers,
7693 IWineD3DDeviceImpl_SetSamplerState,
7694 IWineD3DDeviceImpl_GetSamplerState,
7695 IWineD3DDeviceImpl_SetScissorRect,
7696 IWineD3DDeviceImpl_GetScissorRect,
7697 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7698 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7699 IWineD3DDeviceImpl_SetStreamSource,
7700 IWineD3DDeviceImpl_GetStreamSource,
7701 IWineD3DDeviceImpl_SetStreamSourceFreq,
7702 IWineD3DDeviceImpl_GetStreamSourceFreq,
7703 IWineD3DDeviceImpl_SetTexture,
7704 IWineD3DDeviceImpl_GetTexture,
7705 IWineD3DDeviceImpl_SetTextureStageState,
7706 IWineD3DDeviceImpl_GetTextureStageState,
7707 IWineD3DDeviceImpl_SetTransform,
7708 IWineD3DDeviceImpl_GetTransform,
7709 IWineD3DDeviceImpl_SetVertexDeclaration,
7710 IWineD3DDeviceImpl_GetVertexDeclaration,
7711 IWineD3DDeviceImpl_SetVertexShader,
7712 IWineD3DDeviceImpl_GetVertexShader,
7713 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7714 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7715 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7716 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7717 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7718 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7719 IWineD3DDeviceImpl_SetViewport,
7720 IWineD3DDeviceImpl_GetViewport,
7721 IWineD3DDeviceImpl_MultiplyTransform,
7722 IWineD3DDeviceImpl_ValidateDevice,
7723 IWineD3DDeviceImpl_ProcessVertices,
7724 /*** State block ***/
7725 IWineD3DDeviceImpl_BeginStateBlock,
7726 IWineD3DDeviceImpl_EndStateBlock,
7727 /*** Scene management ***/
7728 IWineD3DDeviceImpl_BeginScene,
7729 IWineD3DDeviceImpl_EndScene,
7730 IWineD3DDeviceImpl_Present,
7731 IWineD3DDeviceImpl_Clear,
7732 /*** Drawing ***/
7733 IWineD3DDeviceImpl_DrawPrimitive,
7734 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7735 IWineD3DDeviceImpl_DrawPrimitiveUP,
7736 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7737 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7738 IWineD3DDeviceImpl_DrawRectPatch,
7739 IWineD3DDeviceImpl_DrawTriPatch,
7740 IWineD3DDeviceImpl_DeletePatch,
7741 IWineD3DDeviceImpl_ColorFill,
7742 IWineD3DDeviceImpl_UpdateTexture,
7743 IWineD3DDeviceImpl_UpdateSurface,
7744 IWineD3DDeviceImpl_CopyRects,
7745 IWineD3DDeviceImpl_StretchRect,
7746 IWineD3DDeviceImpl_GetRenderTargetData,
7747 IWineD3DDeviceImpl_GetFrontBufferData,
7748 /*** Internal use IWineD3DDevice methods ***/
7749 IWineD3DDeviceImpl_SetupTextureStates,
7750 /*** object tracking ***/
7751 IWineD3DDeviceImpl_ResourceReleased
7755 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7756 WINED3DRS_ALPHABLENDENABLE ,
7757 WINED3DRS_ALPHAFUNC ,
7758 WINED3DRS_ALPHAREF ,
7759 WINED3DRS_ALPHATESTENABLE ,
7760 WINED3DRS_BLENDOP ,
7761 WINED3DRS_COLORWRITEENABLE ,
7762 WINED3DRS_DESTBLEND ,
7763 WINED3DRS_DITHERENABLE ,
7764 WINED3DRS_FILLMODE ,
7765 WINED3DRS_FOGDENSITY ,
7766 WINED3DRS_FOGEND ,
7767 WINED3DRS_FOGSTART ,
7768 WINED3DRS_LASTPIXEL ,
7769 WINED3DRS_SHADEMODE ,
7770 WINED3DRS_SRCBLEND ,
7771 WINED3DRS_STENCILENABLE ,
7772 WINED3DRS_STENCILFAIL ,
7773 WINED3DRS_STENCILFUNC ,
7774 WINED3DRS_STENCILMASK ,
7775 WINED3DRS_STENCILPASS ,
7776 WINED3DRS_STENCILREF ,
7777 WINED3DRS_STENCILWRITEMASK ,
7778 WINED3DRS_STENCILZFAIL ,
7779 WINED3DRS_TEXTUREFACTOR ,
7780 WINED3DRS_WRAP0 ,
7781 WINED3DRS_WRAP1 ,
7782 WINED3DRS_WRAP2 ,
7783 WINED3DRS_WRAP3 ,
7784 WINED3DRS_WRAP4 ,
7785 WINED3DRS_WRAP5 ,
7786 WINED3DRS_WRAP6 ,
7787 WINED3DRS_WRAP7 ,
7788 WINED3DRS_ZENABLE ,
7789 WINED3DRS_ZFUNC ,
7790 WINED3DRS_ZWRITEENABLE
7793 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7794 WINED3DTSS_ADDRESSW ,
7795 WINED3DTSS_ALPHAARG0 ,
7796 WINED3DTSS_ALPHAARG1 ,
7797 WINED3DTSS_ALPHAARG2 ,
7798 WINED3DTSS_ALPHAOP ,
7799 WINED3DTSS_BUMPENVLOFFSET ,
7800 WINED3DTSS_BUMPENVLSCALE ,
7801 WINED3DTSS_BUMPENVMAT00 ,
7802 WINED3DTSS_BUMPENVMAT01 ,
7803 WINED3DTSS_BUMPENVMAT10 ,
7804 WINED3DTSS_BUMPENVMAT11 ,
7805 WINED3DTSS_COLORARG0 ,
7806 WINED3DTSS_COLORARG1 ,
7807 WINED3DTSS_COLORARG2 ,
7808 WINED3DTSS_COLOROP ,
7809 WINED3DTSS_RESULTARG ,
7810 WINED3DTSS_TEXCOORDINDEX ,
7811 WINED3DTSS_TEXTURETRANSFORMFLAGS
7814 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7815 WINED3DSAMP_ADDRESSU ,
7816 WINED3DSAMP_ADDRESSV ,
7817 WINED3DSAMP_ADDRESSW ,
7818 WINED3DSAMP_BORDERCOLOR ,
7819 WINED3DSAMP_MAGFILTER ,
7820 WINED3DSAMP_MINFILTER ,
7821 WINED3DSAMP_MIPFILTER ,
7822 WINED3DSAMP_MIPMAPLODBIAS ,
7823 WINED3DSAMP_MAXMIPLEVEL ,
7824 WINED3DSAMP_MAXANISOTROPY ,
7825 WINED3DSAMP_SRGBTEXTURE ,
7826 WINED3DSAMP_ELEMENTINDEX
7829 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7830 WINED3DRS_AMBIENT ,
7831 WINED3DRS_AMBIENTMATERIALSOURCE ,
7832 WINED3DRS_CLIPPING ,
7833 WINED3DRS_CLIPPLANEENABLE ,
7834 WINED3DRS_COLORVERTEX ,
7835 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7836 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7837 WINED3DRS_FOGDENSITY ,
7838 WINED3DRS_FOGEND ,
7839 WINED3DRS_FOGSTART ,
7840 WINED3DRS_FOGTABLEMODE ,
7841 WINED3DRS_FOGVERTEXMODE ,
7842 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7843 WINED3DRS_LIGHTING ,
7844 WINED3DRS_LOCALVIEWER ,
7845 WINED3DRS_MULTISAMPLEANTIALIAS ,
7846 WINED3DRS_MULTISAMPLEMASK ,
7847 WINED3DRS_NORMALIZENORMALS ,
7848 WINED3DRS_PATCHEDGESTYLE ,
7849 WINED3DRS_POINTSCALE_A ,
7850 WINED3DRS_POINTSCALE_B ,
7851 WINED3DRS_POINTSCALE_C ,
7852 WINED3DRS_POINTSCALEENABLE ,
7853 WINED3DRS_POINTSIZE ,
7854 WINED3DRS_POINTSIZE_MAX ,
7855 WINED3DRS_POINTSIZE_MIN ,
7856 WINED3DRS_POINTSPRITEENABLE ,
7857 WINED3DRS_RANGEFOGENABLE ,
7858 WINED3DRS_SPECULARMATERIALSOURCE ,
7859 WINED3DRS_TWEENFACTOR ,
7860 WINED3DRS_VERTEXBLEND
7863 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7864 WINED3DTSS_TEXCOORDINDEX ,
7865 WINED3DTSS_TEXTURETRANSFORMFLAGS
7868 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7869 WINED3DSAMP_DMAPOFFSET