wined3d: Move WINED3DRS_STIPPLEDALPHA to the state table.
[wine/multimedia.git] / dlls / wined3d / device.c
blobe6012f8415d636941e04af065ea9c7c19cc3800e
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
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
82 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
84 /* helper macros */
85 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
87 #define D3DCREATEOBJECTINSTANCE(object, type) { \
88 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
89 D3DMEMCHECK(object, pp##type); \
90 object->lpVtbl = &IWineD3D##type##_Vtbl; \
91 object->wineD3DDevice = This; \
92 object->parent = parent; \
93 object->ref = 1; \
94 *pp##type = (IWineD3D##type *) object; \
97 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
98 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
99 D3DMEMCHECK(object, pp##type); \
100 object->lpVtbl = &IWineD3D##type##_Vtbl; \
101 object->parent = parent; \
102 object->ref = 1; \
103 object->baseShader.device = (IWineD3DDevice*) This; \
104 *pp##type = (IWineD3D##type *) object; \
107 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
108 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
109 D3DMEMCHECK(object, pp##type); \
110 object->lpVtbl = &IWineD3D##type##_Vtbl; \
111 object->resource.wineD3DDevice = This; \
112 object->resource.parent = parent; \
113 object->resource.resourceType = d3dtype; \
114 object->resource.ref = 1; \
115 object->resource.pool = Pool; \
116 object->resource.format = Format; \
117 object->resource.usage = Usage; \
118 object->resource.size = _size; \
119 /* Check that we have enough video ram left */ \
120 if (Pool == WINED3DPOOL_DEFAULT) { \
121 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
122 WARN("Out of 'bogus' video memory\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 globalChangeGlRam(_size); \
129 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
130 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
131 FIXME("Out of memory!\n"); \
132 HeapFree(GetProcessHeap(), 0, object); \
133 *pp##type = NULL; \
134 return WINED3DERR_OUTOFVIDEOMEMORY; \
136 *pp##type = (IWineD3D##type *) object; \
137 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
138 TRACE("(%p) : Created resource %p\n", This, object); \
141 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
142 _basetexture.levels = Levels; \
143 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
144 _basetexture.LOD = 0; \
145 _basetexture.dirty = TRUE; \
148 /**********************************************************
149 * Global variable / Constants follow
150 **********************************************************/
151 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
153 /**********************************************************
154 * Utility functions follow
155 **********************************************************/
156 /* Convert the WINED3DLIGHT properties into equivalent gl lights */
157 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
159 float quad_att;
160 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
163 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
164 glMatrixMode(GL_MODELVIEW);
165 glPushMatrix();
166 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
168 /* Diffuse: */
169 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
170 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
171 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
172 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
173 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
174 checkGLcall("glLightfv");
176 /* Specular */
177 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
178 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
179 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
180 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
181 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
182 checkGLcall("glLightfv");
184 /* Ambient */
185 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
186 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
187 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
188 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
189 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
190 checkGLcall("glLightfv");
192 /* Attenuation - Are these right? guessing... */
193 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
194 checkGLcall("glLightf");
195 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
196 checkGLcall("glLightf");
198 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
199 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
200 } else {
201 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
204 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
205 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
206 checkGLcall("glLightf");
208 switch (lightInfo->OriginalParms.Type) {
209 case WINED3DLIGHT_POINT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
214 checkGLcall("glLightf");
215 /* FIXME: Range */
216 break;
218 case WINED3DLIGHT_SPOT:
219 /* Position */
220 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
221 checkGLcall("glLightfv");
222 /* Direction */
223 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
224 checkGLcall("glLightfv");
225 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
226 checkGLcall("glLightf");
227 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 /* FIXME: Range */
230 break;
232 case WINED3DLIGHT_DIRECTIONAL:
233 /* Direction */
234 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
235 checkGLcall("glLightfv");
236 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
237 checkGLcall("glLightf");
238 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
239 checkGLcall("glLightf");
240 break;
242 default:
243 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
246 /* Restore the modelview matrix */
247 glPopMatrix();
250 /**********************************************************
251 * GLSL helper functions follow
252 **********************************************************/
254 /** Attach a GLSL pixel or vertex shader object to the shader program */
255 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
258 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
259 if (This->stateBlock->glsl_program && shaderObj != 0) {
260 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
261 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
262 checkGLcall("glAttachObjectARB");
266 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
267 * It sets the programId on the current StateBlock (because it should be called
268 * inside of the DrawPrimitive() part of the render loop).
270 * If a program for the given combination does not exist, create one, and store
271 * the program in the list. If it creates a program, it will link the given
272 * objects, too.
274 * We keep the shader programs around on a list because linking
275 * shader objects together is an expensive operation. It's much
276 * faster to loop through a list of pre-compiled & linked programs
277 * each time that the application sets a new pixel or vertex shader
278 * than it is to re-link them together at that time.
280 * The list will be deleted in IWineD3DDevice::Release().
282 void set_glsl_shader_program(IWineD3DDevice *iface) {
284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
285 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
286 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
287 struct glsl_shader_prog_link *curLink = NULL;
288 struct glsl_shader_prog_link *newLink = NULL;
289 struct list *ptr = NULL;
290 GLhandleARB programId = 0;
291 int i;
292 char glsl_name[8];
294 ptr = list_head( &This->glsl_shader_progs );
295 while (ptr) {
296 /* At least one program exists - see if it matches our ps/vs combination */
297 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
298 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
299 /* Existing Program found, use it */
300 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
301 curLink->programId);
302 This->stateBlock->glsl_program = curLink;
303 return;
305 /* This isn't the entry we need - try the next one */
306 ptr = list_next( &This->glsl_shader_progs, ptr );
309 /* If we get to this point, then no matching program exists, so we create one */
310 programId = GL_EXTCALL(glCreateProgramObjectARB());
311 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
313 /* Allocate a new link for the list of programs */
314 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
315 newLink->programId = programId;
316 This->stateBlock->glsl_program = newLink;
318 /* Attach GLSL vshader */
319 if (NULL != vshader && This->vs_selected_mode == SHADER_GLSL) {
320 int i;
321 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
322 char tmp_name[10];
324 TRACE("Attaching vertex shader to GLSL program\n");
325 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
327 /* Bind vertex attributes to a corresponding index number to match
328 * the same index numbers as ARB_vertex_programs (makes loading
329 * vertex attributes simpler). With this method, we can use the
330 * exact same code to load the attributes later for both ARB and
331 * GLSL shaders.
333 * We have to do this here because we need to know the Program ID
334 * in order to make the bindings work, and it has to be done prior
335 * to linking the GLSL program. */
336 for (i = 0; i < max_attribs; ++i) {
337 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
338 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
340 checkGLcall("glBindAttribLocationARB");
341 newLink->vertexShader = vshader;
344 /* Attach GLSL pshader */
345 if (NULL != pshader && This->ps_selected_mode == SHADER_GLSL) {
346 TRACE("Attaching pixel shader to GLSL program\n");
347 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
348 newLink->pixelShader = pshader;
351 /* Link the program */
352 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
353 GL_EXTCALL(glLinkProgramARB(programId));
354 print_glsl_info_log(&GLINFO_LOCATION, programId);
355 list_add_head( &This->glsl_shader_progs, &newLink->entry);
357 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
358 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
359 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
360 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
362 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
363 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
364 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
365 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
368 return;
371 /** Detach the GLSL pixel or vertex shader object from the shader program */
372 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
376 if (shaderObj != 0 && programId != 0) {
377 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
378 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
379 checkGLcall("glDetachObjectARB");
383 /** Delete a GLSL shader program */
384 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
388 if (obj != 0) {
389 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
390 GL_EXTCALL(glDeleteObjectARB(obj));
391 checkGLcall("glDeleteObjectARB");
395 /** Delete the list of linked programs this shader is associated with.
396 * Also at this point, check to see if there are any objects left attached
397 * to each GLSL program. If not, delete the GLSL program object.
398 * This will be run when a device is released. */
399 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
401 struct list *ptr = NULL;
402 struct glsl_shader_prog_link *curLink = NULL;
403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
405 int numAttached = 0;
406 int i;
407 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
408 (one pixel shader and one vertex shader at most) */
410 ptr = list_head( &This->glsl_shader_progs );
411 while (ptr) {
412 /* First, get the current item,
413 * save the link to the next pointer,
414 * detach and delete shader objects,
415 * then de-allocate the list item's memory */
416 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
417 ptr = list_next( &This->glsl_shader_progs, ptr );
419 /* See if this object is still attached to the program - it may have been detached already */
420 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
421 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
422 for (i = 0; i < numAttached; i++) {
423 detach_glsl_shader(iface, objList[i], curLink->programId);
426 delete_glsl_shader_program(iface, curLink->programId);
428 /* Free the uniform locations */
429 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
430 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
432 /* Free the memory for this list item */
433 HeapFree(GetProcessHeap(), 0, curLink);
438 /* Apply the current values to the specified texture stage */
439 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 float col[4];
443 union {
444 float f;
445 DWORD d;
446 } tmpvalue;
448 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
449 clamping, MIPLOD, etc. This will work for up to 16 samplers.
452 if (Sampler >= GL_LIMITS(sampler_stages)) {
453 FIXME("Trying to set the state of more samplers %d than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
454 return;
456 VTRACE(("Activating appropriate texture state %d\n", Sampler));
457 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
458 ENTER_GL();
459 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
460 checkGLcall("glActiveTextureARB");
461 LEAVE_GL();
462 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
463 } else if (Sampler > 0) {
464 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
465 return;
468 /* TODO: change this to a lookup table
469 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
470 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
471 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
472 especially when there are a number of groups of states. */
474 TRACE("-----------------------> Updating the texture at Sampler %d to have new texture state information\n", Sampler);
476 /* 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 */
477 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
478 /* these are the only two supported states that need to be applied */
479 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
480 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
481 #if 0 /* not supported at the moment */
482 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
483 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
484 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
485 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
486 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
487 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
488 APPLY_STATE(WINED3DTSS_RESULTARG);
489 APPLY_STATE(WINED3DTSS_CONSTANT);
490 #endif
491 /* a quick sanity check in case someone forgot to update this function */
492 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
493 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
495 #undef APPLY_STATE
497 /* apply any sampler states that always need applying */
498 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
499 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
500 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
501 GL_TEXTURE_LOD_BIAS_EXT,
502 tmpvalue.f);
503 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
506 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
507 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
508 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
510 /* TODO: NV_POINT_SPRITE */
511 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
512 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
513 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
514 glDisable(GL_POINT_SMOOTH);
516 /* Centre the texture on the vertex */
517 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
518 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
520 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
521 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
522 checkGLcall("glTexEnvf(...)");
523 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
524 glEnable( GL_POINT_SPRITE_ARB );
525 checkGLcall("glEnable(...)");
526 } else {
527 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
528 glDisable( GL_POINT_SPRITE_ARB );
529 checkGLcall("glEnable(...)");
533 TRACE("-----------------------> Updated the texture at Sampler %d to have new texture state information\n", Sampler);
536 /**********************************************************
537 * IUnknown parts follows
538 **********************************************************/
540 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
544 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
545 if (IsEqualGUID(riid, &IID_IUnknown)
546 || IsEqualGUID(riid, &IID_IWineD3DBase)
547 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
548 IUnknown_AddRef(iface);
549 *ppobj = This;
550 return S_OK;
552 *ppobj = NULL;
553 return E_NOINTERFACE;
556 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
558 ULONG refCount = InterlockedIncrement(&This->ref);
560 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
561 return refCount;
564 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 ULONG refCount = InterlockedDecrement(&This->ref);
568 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
570 if (!refCount) {
571 if (This->fbo) {
572 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
575 /* TODO: Clean up all the surfaces and textures! */
576 /* NOTE: You must release the parent if the object was created via a callback
577 ** ***************************/
579 /* Delete any GLSL shader programs that may exist */
580 if (This->vs_selected_mode == SHADER_GLSL ||
581 This->ps_selected_mode == SHADER_GLSL)
582 delete_glsl_shader_list(iface);
584 /* Release the update stateblock */
585 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
586 if(This->updateStateBlock != This->stateBlock)
587 FIXME("(%p) Something's still holding the Update stateblock\n",This);
589 This->updateStateBlock = NULL;
590 { /* because were not doing proper internal refcounts releasing the primary state block
591 causes recursion with the extra checks in ResourceReleased, to avoid this we have
592 to set this->stateBlock = NULL; first */
593 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
594 This->stateBlock = NULL;
596 /* Release the stateblock */
597 if(IWineD3DStateBlock_Release(stateBlock) > 0){
598 FIXME("(%p) Something's still holding the Update stateblock\n",This);
602 if (This->resources != NULL ) {
603 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
604 dumpResources(This->resources);
608 IWineD3D_Release(This->wineD3D);
609 This->wineD3D = NULL;
610 HeapFree(GetProcessHeap(), 0, This);
611 TRACE("Freed device %p\n", This);
612 This = NULL;
614 return refCount;
617 /**********************************************************
618 * IWineD3DDevice implementation follows
619 **********************************************************/
620 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
622 *pParent = This->parent;
623 IUnknown_AddRef(This->parent);
624 return WINED3D_OK;
627 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
628 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
629 GLenum error, glUsage;
630 DWORD vboUsage = object->resource.usage;
631 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
632 WARN("Creating a vbo failed once, not trying again\n");
633 return;
636 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
638 ENTER_GL();
639 /* Make sure that the gl error is cleared. Do not use checkGLcall
640 * here because checkGLcall just prints a fixme and continues. However,
641 * if an error during VBO creation occurs we can fall back to non-vbo operation
642 * with full functionality(but performance loss)
644 while(glGetError() != GL_NO_ERROR);
646 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
647 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
648 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
649 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
650 * to check if the rhw and color values are in the correct format.
653 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
654 error = glGetError();
655 if(object->vbo == 0 || error != GL_NO_ERROR) {
656 WARN("Failed to create a VBO with error %d\n", error);
657 goto error;
660 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
661 error = glGetError();
662 if(error != GL_NO_ERROR) {
663 WARN("Failed to bind the VBO, error %d\n", error);
664 goto error;
667 /* Transformed vertices are horribly inflexible. If the app specifies an
668 * vertex buffer with transformed vertices in default pool without DYNAMIC
669 * usage assume DYNAMIC usage and print a warning. The app will have to update
670 * the vertices regularily for them to be useful
672 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
673 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
674 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
675 vboUsage |= WINED3DUSAGE_DYNAMIC;
678 /* Don't use static, because dx apps tend to update the buffer
679 * quite often even if they specify 0 usage
681 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
682 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
683 TRACE("Gl usage = GL_STREAM_DRAW\n");
684 glUsage = GL_STREAM_DRAW_ARB;
685 break;
686 case D3DUSAGE_WRITEONLY:
687 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
688 glUsage = GL_DYNAMIC_DRAW_ARB;
689 break;
690 case D3DUSAGE_DYNAMIC:
691 TRACE("Gl usage = GL_STREAM_COPY\n");
692 glUsage = GL_STREAM_COPY_ARB;
693 break;
694 default:
695 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
696 glUsage = GL_DYNAMIC_COPY_ARB;
697 break;
700 /* Reserve memory for the buffer. The amount of data won't change
701 * so we are safe with calling glBufferData once with a NULL ptr and
702 * calling glBufferSubData on updates
704 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
705 error = glGetError();
706 if(error != GL_NO_ERROR) {
707 WARN("glBufferDataARB failed with error %d\n", error);
708 goto error;
711 LEAVE_GL();
713 return;
714 error:
715 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
716 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
717 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
718 object->vbo = 0;
719 object->Flags |= VBFLAG_VBOCREATEFAIL;
720 LEAVE_GL();
721 return;
724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
725 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
726 IUnknown *parent) {
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVertexBufferImpl *object;
729 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
730 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
731 BOOL conv;
732 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
734 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
735 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
737 if(Size == 0) return WINED3DERR_INVALIDCALL;
739 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
740 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
742 object->fvf = FVF;
744 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
745 * drawStridedFast (half-life 2).
747 * Basically converting the vertices in the buffer is quite expensive, and observations
748 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
749 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
751 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
752 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
753 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
754 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
755 * dx7 apps.
756 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
757 * more. In this call we can convert dx7 buffers too.
759 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
760 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
761 (dxVersion > 7 || !conv) ) {
762 CreateVBO(object);
764 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
765 if(dxVersion == 7 && object->vbo) {
766 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
767 object->resource.allocatedMemory = NULL;
771 return WINED3D_OK;
774 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
775 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
776 HANDLE *sharedHandle, IUnknown *parent) {
777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
778 IWineD3DIndexBufferImpl *object;
779 TRACE("(%p) Creating index buffer\n", This);
781 /* Allocate the storage for the device */
782 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
784 /*TODO: use VBO's */
785 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
786 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
789 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
790 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
791 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
793 return WINED3D_OK;
796 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
799 IWineD3DStateBlockImpl *object;
800 int i, j;
801 HRESULT temp_result;
803 D3DCREATEOBJECTINSTANCE(object, StateBlock)
804 object->blockType = Type;
806 /* Special case - Used during initialization to produce a placeholder stateblock
807 so other functions called can update a state block */
808 if (Type == WINED3DSBT_INIT) {
809 /* Don't bother increasing the reference count otherwise a device will never
810 be freed due to circular dependencies */
811 return WINED3D_OK;
814 temp_result = allocate_shader_constants(object);
815 if (WINED3D_OK != temp_result)
816 return temp_result;
818 /* Otherwise, might as well set the whole state block to the appropriate values */
819 if (This->stateBlock != NULL)
820 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
821 else
822 memset(object->streamFreq, 1, sizeof(object->streamFreq));
824 /* Reset the ref and type after kludging it */
825 object->wineD3DDevice = This;
826 object->ref = 1;
827 object->blockType = Type;
829 TRACE("Updating changed flags appropriate for type %d\n", Type);
831 if (Type == WINED3DSBT_ALL) {
833 TRACE("ALL => Pretend everything has changed\n");
834 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
836 } else if (Type == WINED3DSBT_PIXELSTATE) {
838 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
839 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
841 object->changed.pixelShader = TRUE;
843 /* Pixel Shader Constants */
844 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
845 object->changed.pixelShaderConstantsF[i] = TRUE;
846 for (i = 0; i < MAX_CONST_B; ++i)
847 object->changed.pixelShaderConstantsB[i] = TRUE;
848 for (i = 0; i < MAX_CONST_I; ++i)
849 object->changed.pixelShaderConstantsI[i] = TRUE;
851 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
852 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
854 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
855 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
856 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
859 for (j = 0 ; j < 16; j++) {
860 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
862 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
866 } else if (Type == WINED3DSBT_VERTEXSTATE) {
868 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
869 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
871 object->changed.vertexShader = TRUE;
873 /* Vertex Shader Constants */
874 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
875 object->changed.vertexShaderConstantsF[i] = TRUE;
876 for (i = 0; i < MAX_CONST_B; ++i)
877 object->changed.vertexShaderConstantsB[i] = TRUE;
878 for (i = 0; i < MAX_CONST_I; ++i)
879 object->changed.vertexShaderConstantsI[i] = TRUE;
881 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
882 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
884 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
885 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
886 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
889 for (j = 0 ; j < 16; j++){
890 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
891 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
895 /* Duplicate light chain */
897 PLIGHTINFOEL *src = NULL;
898 PLIGHTINFOEL *dst = NULL;
899 PLIGHTINFOEL *newEl = NULL;
900 src = This->stateBlock->lights;
901 object->lights = NULL;
904 while (src) {
905 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
906 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
907 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
908 newEl->prev = dst;
909 newEl->changed = TRUE;
910 newEl->enabledChanged = TRUE;
911 if (dst == NULL) {
912 object->lights = newEl;
913 } else {
914 dst->next = newEl;
916 dst = newEl;
917 src = src->next;
922 } else {
923 FIXME("Unrecognized state block type %d\n", Type);
926 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
927 return WINED3D_OK;
931 /* ************************************
932 MSDN:
933 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
935 Discard
936 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
938 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.
940 ******************************** */
942 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) {
943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
944 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
945 unsigned int pow2Width, pow2Height;
946 unsigned int Size = 1;
947 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
948 TRACE("(%p) Create surface\n",This);
950 /** FIXME: Check ranges on the inputs are valid
951 * MSDN
952 * MultisampleQuality
953 * [in] Quality level. The valid range is between zero and one less than the level
954 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
955 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
956 * values of paired render targets, depth stencil surfaces, and the MultiSample type
957 * must all match.
958 *******************************/
962 * TODO: Discard MSDN
963 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
965 * If this flag is set, the contents of the depth stencil buffer will be
966 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
967 * with a different depth surface.
969 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
970 ***************************/
972 if(MultisampleQuality < 0) {
973 FIXME("Invalid multisample level %d\n", MultisampleQuality);
974 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
977 if(MultisampleQuality > 0) {
978 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
979 MultisampleQuality=0;
982 /** FIXME: Check that the format is supported
983 * by the device.
984 *******************************/
986 /* Non-power2 support */
987 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
988 pow2Width = Width;
989 pow2Height = Height;
990 } else {
991 /* Find the nearest pow2 match */
992 pow2Width = pow2Height = 1;
993 while (pow2Width < Width) pow2Width <<= 1;
994 while (pow2Height < Height) pow2Height <<= 1;
997 if (pow2Width > Width || pow2Height > Height) {
998 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
999 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
1000 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1001 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1002 This, Width, Height);
1003 return WINED3DERR_NOTAVAILABLE;
1007 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1008 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1009 * space!
1010 *********************************/
1011 if (WINED3DFMT_UNKNOWN == Format) {
1012 Size = 0;
1013 } else if (Format == WINED3DFMT_DXT1) {
1014 /* DXT1 is half byte per pixel */
1015 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1017 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1018 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1019 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1020 } else {
1021 /* The pitch is a multiple of 4 bytes */
1022 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1023 Size *= pow2Height;
1026 /** Create and initialise the surface resource **/
1027 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1028 /* "Standalone" surface */
1029 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1031 object->currentDesc.Width = Width;
1032 object->currentDesc.Height = Height;
1033 object->currentDesc.MultiSampleType = MultiSample;
1034 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1036 /* Setup some glformat defaults */
1037 object->glDescription.glFormat = tableEntry->glFormat;
1038 object->glDescription.glFormatInternal = tableEntry->glInternal;
1039 object->glDescription.glType = tableEntry->glType;
1041 object->glDescription.textureName = 0;
1042 object->glDescription.level = Level;
1043 object->glDescription.target = GL_TEXTURE_2D;
1045 /* Internal data */
1046 object->pow2Width = pow2Width;
1047 object->pow2Height = pow2Height;
1049 /* Flags */
1050 object->Flags = 0; /* We start without flags set */
1051 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1052 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1053 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1054 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1057 if (WINED3DFMT_UNKNOWN != Format) {
1058 object->bytesPerPixel = tableEntry->bpp;
1059 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1060 object->pow2Size *= pow2Height;
1061 } else {
1062 object->bytesPerPixel = 0;
1063 object->pow2Size = 0;
1066 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1068 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1070 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1071 * this function is too deep to need to care about things like this.
1072 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1073 * ****************************************/
1074 switch(Pool) {
1075 case WINED3DPOOL_SCRATCH:
1076 if(!Lockable)
1077 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1078 which are mutually exclusive, setting lockable to true\n");
1079 Lockable = TRUE;
1080 break;
1081 case WINED3DPOOL_SYSTEMMEM:
1082 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1083 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1084 case WINED3DPOOL_MANAGED:
1085 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1086 Usage of DYNAMIC which are mutually exclusive, not doing \
1087 anything just telling you.\n");
1088 break;
1089 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1090 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1091 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1092 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1093 break;
1094 default:
1095 FIXME("(%p) Unknown pool %d\n", This, Pool);
1096 break;
1099 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1100 FIXME("Trying to create a render target that isn't in the default pool\n");
1103 /* mark the texture as dirty so that it gets loaded first time around*/
1104 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1105 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1106 This, Width, Height, Format, debug_d3dformat(Format),
1107 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1109 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1110 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1111 This->ddraw_primary = (IWineD3DSurface *) object;
1113 /* Look at the implementation and set the correct Vtable */
1114 switch(Impl) {
1115 case SURFACE_OPENGL:
1116 /* Nothing to do, it's set already */
1117 break;
1119 case SURFACE_GDI:
1120 object->lpVtbl = &IWineGDISurface_Vtbl;
1121 break;
1123 default:
1124 /* To be sure to catch this */
1125 ERR("Unknown requested surface implementation %d!\n", Impl);
1126 IWineD3DSurface_Release((IWineD3DSurface *) object);
1127 return WINED3DERR_INVALIDCALL;
1130 /* Call the private setup routine */
1131 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1136 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1137 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1138 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141 IWineD3DTextureImpl *object;
1142 unsigned int i;
1143 UINT tmpW;
1144 UINT tmpH;
1145 HRESULT hr;
1146 unsigned int pow2Width;
1147 unsigned int pow2Height;
1150 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1151 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1152 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1154 /* TODO: It should only be possible to create textures for formats
1155 that are reported as supported */
1156 if (WINED3DFMT_UNKNOWN >= Format) {
1157 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1158 return WINED3DERR_INVALIDCALL;
1161 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1162 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1163 object->width = Width;
1164 object->height = Height;
1166 /** Non-power2 support **/
1167 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1168 pow2Width = Width;
1169 pow2Height = Height;
1170 } else {
1171 /* Find the nearest pow2 match */
1172 pow2Width = pow2Height = 1;
1173 while (pow2Width < Width) pow2Width <<= 1;
1174 while (pow2Height < Height) pow2Height <<= 1;
1177 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1178 /* Precalculated scaling for 'faked' non power of two texture coords */
1179 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1180 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1181 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1183 /* Calculate levels for mip mapping */
1184 if (Levels == 0) {
1185 TRACE("calculating levels %d\n", object->baseTexture.levels);
1186 object->baseTexture.levels++;
1187 tmpW = Width;
1188 tmpH = Height;
1189 while (tmpW > 1 || tmpH > 1) {
1190 tmpW = max(1, tmpW >> 1);
1191 tmpH = max(1, tmpH >> 1);
1192 object->baseTexture.levels++;
1194 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1197 /* Generate all the surfaces */
1198 tmpW = Width;
1199 tmpH = Height;
1200 for (i = 0; i < object->baseTexture.levels; i++)
1202 /* use the callback to create the texture surface */
1203 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1204 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1205 FIXME("Failed to create surface %p\n", object);
1206 /* clean up */
1207 object->surfaces[i] = NULL;
1208 IWineD3DTexture_Release((IWineD3DTexture *)object);
1210 *ppTexture = NULL;
1211 return hr;
1214 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1215 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1216 /* calculate the next mipmap level */
1217 tmpW = max(1, tmpW >> 1);
1218 tmpH = max(1, tmpH >> 1);
1221 TRACE("(%p) : Created texture %p\n", This, object);
1222 return WINED3D_OK;
1225 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1226 UINT Width, UINT Height, UINT Depth,
1227 UINT Levels, DWORD Usage,
1228 WINED3DFORMAT Format, WINED3DPOOL Pool,
1229 IWineD3DVolumeTexture **ppVolumeTexture,
1230 HANDLE *pSharedHandle, IUnknown *parent,
1231 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 IWineD3DVolumeTextureImpl *object;
1235 unsigned int i;
1236 UINT tmpW;
1237 UINT tmpH;
1238 UINT tmpD;
1240 /* TODO: It should only be possible to create textures for formats
1241 that are reported as supported */
1242 if (WINED3DFMT_UNKNOWN >= Format) {
1243 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1244 return WINED3DERR_INVALIDCALL;
1247 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1248 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1250 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1251 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1253 object->width = Width;
1254 object->height = Height;
1255 object->depth = Depth;
1257 /* Calculate levels for mip mapping */
1258 if (Levels == 0) {
1259 object->baseTexture.levels++;
1260 tmpW = Width;
1261 tmpH = Height;
1262 tmpD = Depth;
1263 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1264 tmpW = max(1, tmpW >> 1);
1265 tmpH = max(1, tmpH >> 1);
1266 tmpD = max(1, tmpD >> 1);
1267 object->baseTexture.levels++;
1269 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1272 /* Generate all the surfaces */
1273 tmpW = Width;
1274 tmpH = Height;
1275 tmpD = Depth;
1277 for (i = 0; i < object->baseTexture.levels; i++)
1279 /* Create the volume */
1280 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1281 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1283 /* Set its container to this object */
1284 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1286 /* calcualte the next mipmap level */
1287 tmpW = max(1, tmpW >> 1);
1288 tmpH = max(1, tmpH >> 1);
1289 tmpD = max(1, tmpD >> 1);
1292 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1293 TRACE("(%p) : Created volume texture %p\n", This, object);
1294 return WINED3D_OK;
1297 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1298 UINT Width, UINT Height, UINT Depth,
1299 DWORD Usage,
1300 WINED3DFORMAT Format, WINED3DPOOL Pool,
1301 IWineD3DVolume** ppVolume,
1302 HANDLE* pSharedHandle, IUnknown *parent) {
1304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1306 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1308 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1310 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1311 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1313 object->currentDesc.Width = Width;
1314 object->currentDesc.Height = Height;
1315 object->currentDesc.Depth = Depth;
1316 object->bytesPerPixel = formatDesc->bpp;
1318 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1319 object->lockable = TRUE;
1320 object->locked = FALSE;
1321 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1322 object->dirty = TRUE;
1324 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1328 UINT Levels, DWORD Usage,
1329 WINED3DFORMAT Format, WINED3DPOOL Pool,
1330 IWineD3DCubeTexture **ppCubeTexture,
1331 HANDLE *pSharedHandle, IUnknown *parent,
1332 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1335 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1336 unsigned int i, j;
1337 UINT tmpW;
1338 HRESULT hr;
1339 unsigned int pow2EdgeLength = EdgeLength;
1341 /* TODO: It should only be possible to create textures for formats
1342 that are reported as supported */
1343 if (WINED3DFMT_UNKNOWN >= Format) {
1344 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1345 return WINED3DERR_INVALIDCALL;
1348 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1349 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1351 TRACE("(%p) Create Cube Texture\n", This);
1353 /** Non-power2 support **/
1355 /* Find the nearest pow2 match */
1356 pow2EdgeLength = 1;
1357 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1359 object->edgeLength = EdgeLength;
1360 /* TODO: support for native non-power 2 */
1361 /* Precalculated scaling for 'faked' non power of two texture coords */
1362 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1364 /* Calculate levels for mip mapping */
1365 if (Levels == 0) {
1366 object->baseTexture.levels++;
1367 tmpW = EdgeLength;
1368 while (tmpW > 1) {
1369 tmpW = max(1, tmpW >> 1);
1370 object->baseTexture.levels++;
1372 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1375 /* Generate all the surfaces */
1376 tmpW = EdgeLength;
1377 for (i = 0; i < object->baseTexture.levels; i++) {
1379 /* Create the 6 faces */
1380 for (j = 0; j < 6; j++) {
1382 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1383 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1385 if(hr!= WINED3D_OK) {
1386 /* clean up */
1387 int k;
1388 int l;
1389 for (l = 0; l < j; l++) {
1390 IWineD3DSurface_Release(object->surfaces[j][i]);
1392 for (k = 0; k < i; k++) {
1393 for (l = 0; l < 6; l++) {
1394 IWineD3DSurface_Release(object->surfaces[l][j]);
1398 FIXME("(%p) Failed to create surface\n",object);
1399 HeapFree(GetProcessHeap(),0,object);
1400 *ppCubeTexture = NULL;
1401 return hr;
1403 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1404 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1406 tmpW = max(1, tmpW >> 1);
1409 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1410 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1411 return WINED3D_OK;
1414 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1416 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1418 if (NULL == ppQuery) {
1419 /* Just a check to see if we support this type of query */
1420 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1421 switch(Type) {
1422 case WINED3DQUERYTYPE_OCCLUSION:
1423 TRACE("(%p) occlusion query\n", This);
1424 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1425 hr = WINED3D_OK;
1426 else
1427 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1428 break;
1429 case WINED3DQUERYTYPE_VCACHE:
1430 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1431 case WINED3DQUERYTYPE_VERTEXSTATS:
1432 case WINED3DQUERYTYPE_EVENT:
1433 case WINED3DQUERYTYPE_TIMESTAMP:
1434 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1435 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1436 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1437 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1438 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1439 case WINED3DQUERYTYPE_PIXELTIMINGS:
1440 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1441 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1442 default:
1443 FIXME("(%p) Unhandled query type %d\n", This, Type);
1445 return hr;
1448 D3DCREATEOBJECTINSTANCE(object, Query)
1449 object->type = Type;
1450 /* allocated the 'extended' data based on the type of query requested */
1451 switch(Type){
1452 case WINED3DQUERYTYPE_OCCLUSION:
1453 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1454 TRACE("(%p) Allocating data for an occlusion query\n", This);
1455 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1457 break;
1459 case WINED3DQUERYTYPE_VCACHE:
1460 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1461 case WINED3DQUERYTYPE_VERTEXSTATS:
1462 case WINED3DQUERYTYPE_EVENT:
1463 case WINED3DQUERYTYPE_TIMESTAMP:
1464 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1465 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1466 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1467 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1468 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1469 case WINED3DQUERYTYPE_PIXELTIMINGS:
1470 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1471 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1472 default:
1473 object->extendedData = 0;
1474 FIXME("(%p) Unhandled query type %d\n",This , Type);
1476 TRACE("(%p) : Created Query %p\n", This, object);
1477 return WINED3D_OK;
1480 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1482 IUnknown* parent,
1483 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1484 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1487 HDC hDc;
1488 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1489 int num;
1490 XVisualInfo template;
1491 GLXContext oldContext;
1492 Drawable oldDrawable;
1493 HRESULT hr = WINED3D_OK;
1495 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1497 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1498 * does a device hold a reference to a swap chain giving them a lifetime of the device
1499 * or does the swap chain notify the device of its destruction.
1500 *******************************/
1502 /* Check the params */
1503 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1504 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1505 return WINED3DERR_INVALIDCALL;
1506 } else if (*pPresentationParameters->BackBufferCount > 1) {
1507 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");
1510 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1512 /*********************
1513 * Lookup the window Handle and the relating X window handle
1514 ********************/
1516 /* Setup hwnd we are using, plus which display this equates to */
1517 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1518 if (!object->win_handle) {
1519 object->win_handle = This->createParms.hFocusWindow;
1522 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1523 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1524 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1525 return WINED3DERR_NOTAVAILABLE;
1527 hDc = GetDC(object->win_handle);
1528 object->display = get_display(hDc);
1529 ReleaseDC(object->win_handle, hDc);
1530 TRACE("Using a display of %p %p\n", object->display, hDc);
1532 if (NULL == object->display || NULL == hDc) {
1533 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1534 return WINED3DERR_NOTAVAILABLE;
1537 if (object->win == 0) {
1538 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1539 return WINED3DERR_NOTAVAILABLE;
1542 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1543 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1546 * Create an opengl context for the display visual
1547 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1548 * use different properties after that point in time. FIXME: How to handle when requested format
1549 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1550 * it chooses is identical to the one already being used!
1551 **********************************/
1553 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1554 ENTER_GL();
1556 /* Create a new context for this swapchain */
1557 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1558 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1559 (or the best possible if none is requested) */
1560 TRACE("Found x visual ID : %ld\n", template.visualid);
1562 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1563 if (NULL == object->visInfo) {
1564 ERR("cannot really get XVisual\n");
1565 LEAVE_GL();
1566 return WINED3DERR_NOTAVAILABLE;
1567 } else {
1568 int n, value;
1569 /* Write out some debug info about the visual/s */
1570 TRACE("Using x visual ID : %ld\n", template.visualid);
1571 TRACE(" visual info: %p\n", object->visInfo);
1572 TRACE(" num items : %d\n", num);
1573 for (n = 0;n < num; n++) {
1574 TRACE("=====item=====: %d\n", n + 1);
1575 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1576 TRACE(" screen : %d\n", object->visInfo[n].screen);
1577 TRACE(" depth : %u\n", object->visInfo[n].depth);
1578 TRACE(" class : %d\n", object->visInfo[n].class);
1579 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1580 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1581 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1582 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1583 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1584 /* log some extra glx info */
1585 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1586 TRACE(" gl_aux_buffers : %d\n", value);
1587 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1588 TRACE(" gl_buffer_size : %d\n", value);
1589 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1590 TRACE(" gl_red_size : %d\n", value);
1591 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1592 TRACE(" gl_green_size : %d\n", value);
1593 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1594 TRACE(" gl_blue_size : %d\n", value);
1595 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1596 TRACE(" gl_alpha_size : %d\n", value);
1597 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1598 TRACE(" gl_depth_size : %d\n", value);
1599 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1600 TRACE(" gl_stencil_size : %d\n", value);
1602 /* Now choose a similar visual ID*/
1604 #ifdef USE_CONTEXT_MANAGER
1606 /** TODO: use a context mamager **/
1607 #endif
1610 IWineD3DSwapChain *implSwapChain;
1611 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1612 /* The first time around we create the context that is shared with all other swapchains and render targets */
1613 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1614 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1615 } else {
1617 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1618 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1619 /* and create a new context with the implicit swapchains context as the shared context */
1620 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1621 IWineD3DSwapChain_Release(implSwapChain);
1625 /* Cleanup */
1626 XFree(object->visInfo);
1627 object->visInfo = NULL;
1629 LEAVE_GL();
1631 if (!object->glCtx) {
1632 ERR("Failed to create GLX context\n");
1633 return WINED3DERR_NOTAVAILABLE;
1634 } else {
1635 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1636 object->win_handle, object->glCtx, object->win, object->visInfo);
1639 /*********************
1640 * Windowed / Fullscreen
1641 *******************/
1644 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1645 * so we should really check to see if there is a fullscreen swapchain already
1646 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1647 **************************************/
1649 if (!*(pPresentationParameters->Windowed)) {
1651 DEVMODEW devmode;
1652 HDC hdc;
1653 int bpp = 0;
1655 /* Get info on the current display setup */
1656 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1657 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1658 DeleteDC(hdc);
1660 /* Change the display settings */
1661 memset(&devmode, 0, sizeof(DEVMODEW));
1662 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1663 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1664 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1665 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1666 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1667 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1669 /* Make popup window */
1670 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1671 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1672 *(pPresentationParameters->BackBufferWidth),
1673 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1675 /* For GetDisplayMode */
1676 This->ddraw_width = devmode.dmPelsWidth;
1677 This->ddraw_height = devmode.dmPelsHeight;
1678 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1682 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1683 * then the corresponding dimension of the client area of the hDeviceWindow
1684 * (or the focus window, if hDeviceWindow is NULL) is taken.
1685 **********************/
1687 if (*(pPresentationParameters->Windowed) &&
1688 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1689 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1691 RECT Rect;
1692 GetClientRect(object->win_handle, &Rect);
1694 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1695 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1696 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1698 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1699 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1700 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1704 /*********************
1705 * finish off parameter initialization
1706 *******************/
1708 /* Put the correct figures in the presentation parameters */
1709 TRACE("Copying across presentation parameters\n");
1710 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1711 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1712 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1713 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1714 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1715 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1716 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1717 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1718 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1719 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1720 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1721 object->presentParms.Flags = *(pPresentationParameters->Flags);
1722 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1723 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1726 /*********************
1727 * Create the back, front and stencil buffers
1728 *******************/
1730 TRACE("calling rendertarget CB\n");
1731 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1732 parent,
1733 object->presentParms.BackBufferWidth,
1734 object->presentParms.BackBufferHeight,
1735 object->presentParms.BackBufferFormat,
1736 object->presentParms.MultiSampleType,
1737 object->presentParms.MultiSampleQuality,
1738 TRUE /* Lockable */,
1739 &object->frontBuffer,
1740 NULL /* pShared (always null)*/);
1741 if (object->frontBuffer != NULL)
1742 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1744 if(object->presentParms.BackBufferCount > 0) {
1745 int i;
1747 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1748 if(!object->backBuffer) {
1749 ERR("Out of memory\n");
1751 if (object->frontBuffer) {
1752 IUnknown *bufferParent;
1753 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1754 IUnknown_Release(bufferParent); /* once for the get parent */
1755 if (IUnknown_Release(bufferParent) > 0) {
1756 FIXME("(%p) Something's still holding the front buffer\n",This);
1759 HeapFree(GetProcessHeap(), 0, object);
1760 return E_OUTOFMEMORY;
1763 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1764 TRACE("calling rendertarget CB\n");
1765 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1766 parent,
1767 object->presentParms.BackBufferWidth,
1768 object->presentParms.BackBufferHeight,
1769 object->presentParms.BackBufferFormat,
1770 object->presentParms.MultiSampleType,
1771 object->presentParms.MultiSampleQuality,
1772 TRUE /* Lockable */,
1773 &object->backBuffer[i],
1774 NULL /* pShared (always null)*/);
1775 if(hr == WINED3D_OK && object->backBuffer[i]) {
1776 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1777 } else {
1778 break;
1781 } else {
1782 object->backBuffer = NULL;
1785 if (object->backBuffer != NULL) {
1786 ENTER_GL();
1787 glDrawBuffer(GL_BACK);
1788 checkGLcall("glDrawBuffer(GL_BACK)");
1789 LEAVE_GL();
1790 } else {
1791 /* Single buffering - draw to front buffer */
1792 ENTER_GL();
1793 glDrawBuffer(GL_FRONT);
1794 checkGLcall("glDrawBuffer(GL_FRONT)");
1795 LEAVE_GL();
1798 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1799 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1800 TRACE("Creating depth stencil buffer\n");
1801 if (This->depthStencilBuffer == NULL ) {
1802 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1803 parent,
1804 object->presentParms.BackBufferWidth,
1805 object->presentParms.BackBufferHeight,
1806 object->presentParms.AutoDepthStencilFormat,
1807 object->presentParms.MultiSampleType,
1808 object->presentParms.MultiSampleQuality,
1809 FALSE /* FIXME: Discard */,
1810 &This->depthStencilBuffer,
1811 NULL /* pShared (always null)*/ );
1812 if (This->depthStencilBuffer != NULL)
1813 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1816 /** TODO: A check on width, height and multisample types
1817 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1818 ****************************/
1819 object->wantsDepthStencilBuffer = TRUE;
1820 } else {
1821 object->wantsDepthStencilBuffer = FALSE;
1824 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1827 /*********************
1828 * init the default renderTarget management
1829 *******************/
1830 object->drawable = object->win;
1831 object->render_ctx = object->glCtx;
1833 if (hr == WINED3D_OK) {
1834 /*********************
1835 * Setup some defaults and clear down the buffers
1836 *******************/
1837 ENTER_GL();
1838 /** save current context and drawable **/
1839 oldContext = glXGetCurrentContext();
1840 oldDrawable = glXGetCurrentDrawable();
1842 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1843 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1844 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1846 checkGLcall("glXMakeCurrent");
1848 TRACE("Setting up the screen\n");
1849 /* Clear the screen */
1850 glClearColor(1.0, 0.0, 0.0, 0.0);
1851 checkGLcall("glClearColor");
1852 glClearIndex(0);
1853 glClearDepth(1);
1854 glClearStencil(0xffff);
1856 checkGLcall("glClear");
1858 glColor3f(1.0, 1.0, 1.0);
1859 checkGLcall("glColor3f");
1861 glEnable(GL_LIGHTING);
1862 checkGLcall("glEnable");
1864 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1865 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1867 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1868 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1870 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1871 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1873 /* switch back to the original context (if there was one)*/
1874 if (This->swapchains) {
1875 /** TODO: restore the context and drawable **/
1876 glXMakeCurrent(object->display, oldDrawable, oldContext);
1879 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1880 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1881 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1882 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1883 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1885 LEAVE_GL();
1887 TRACE("Set swapchain to %p\n", object);
1888 } else { /* something went wrong so clean up */
1889 IUnknown* bufferParent;
1890 if (object->frontBuffer) {
1892 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1893 IUnknown_Release(bufferParent); /* once for the get parent */
1894 if (IUnknown_Release(bufferParent) > 0) {
1895 FIXME("(%p) Something's still holding the front buffer\n",This);
1898 if (object->backBuffer) {
1899 int i;
1900 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1901 if(object->backBuffer[i]) {
1902 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1903 IUnknown_Release(bufferParent); /* once for the get parent */
1904 if (IUnknown_Release(bufferParent) > 0) {
1905 FIXME("(%p) Something's still holding the back buffer\n",This);
1909 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1910 object->backBuffer = NULL;
1912 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1913 /* Clean up the context */
1914 /* check that we are the current context first (we shouldn't be though!) */
1915 if (object->glCtx != 0) {
1916 if(glXGetCurrentContext() == object->glCtx) {
1917 glXMakeCurrent(object->display, None, NULL);
1919 glXDestroyContext(object->display, object->glCtx);
1921 HeapFree(GetProcessHeap(), 0, object);
1925 return hr;
1928 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1929 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1931 TRACE("(%p)\n", This);
1933 return This->NumberOfSwapChains;
1936 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1938 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1940 if(iSwapChain < This->NumberOfSwapChains) {
1941 *pSwapChain = This->swapchains[iSwapChain];
1942 IWineD3DSwapChain_AddRef(*pSwapChain);
1943 TRACE("(%p) returning %p\n", This, *pSwapChain);
1944 return WINED3D_OK;
1945 } else {
1946 TRACE("Swapchain out of range\n");
1947 *pSwapChain = NULL;
1948 return WINED3DERR_INVALIDCALL;
1952 /*****
1953 * Vertex Declaration
1954 *****/
1955 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1957 IWineD3DVertexDeclarationImpl *object = NULL;
1958 HRESULT hr = WINED3D_OK;
1959 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1960 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1961 object->allFVF = 0;
1963 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1965 return hr;
1968 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1969 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1971 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1972 HRESULT hr = WINED3D_OK;
1973 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1974 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1976 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1978 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1979 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1980 if (pDeclaration != NULL) {
1981 IWineD3DVertexDeclaration *vertexDeclaration;
1982 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1983 if (WINED3D_OK == hr) {
1984 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1985 object->vertexDeclaration = vertexDeclaration;
1986 } else {
1987 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1988 IWineD3DVertexShader_Release(*ppVertexShader);
1989 return WINED3DERR_INVALIDCALL;
1993 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1995 if (WINED3D_OK != hr) {
1996 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1997 IWineD3DVertexShader_Release(*ppVertexShader);
1998 return WINED3DERR_INVALIDCALL;
2001 #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. */
2002 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
2003 /* Foo */
2004 } else {
2005 /* Bar */
2008 #endif
2010 return WINED3D_OK;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2016 HRESULT hr = WINED3D_OK;
2018 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2019 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2020 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2021 if (WINED3D_OK == hr) {
2022 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2023 } else {
2024 WARN("(%p) : Failed to create pixel shader\n", This);
2027 return hr;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2032 IWineD3DPaletteImpl *object;
2033 HRESULT hr;
2034 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2036 /* Create the new object */
2037 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2038 if(!object) {
2039 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2040 return E_OUTOFMEMORY;
2043 object->lpVtbl = &IWineD3DPalette_Vtbl;
2044 object->ref = 1;
2045 object->Flags = Flags;
2046 object->parent = Parent;
2047 object->wineD3DDevice = This;
2048 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2050 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2052 if(!object->hpal) {
2053 HeapFree( GetProcessHeap(), 0, object);
2054 return E_OUTOFMEMORY;
2057 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2058 if(FAILED(hr)) {
2059 IWineD3DPalette_Release((IWineD3DPalette *) object);
2060 return hr;
2063 *Palette = (IWineD3DPalette *) object;
2065 return WINED3D_OK;
2068 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2070 IWineD3DSwapChainImpl *swapchain;
2072 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2073 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2075 /* TODO: Test if OpenGL is compiled in and loaded */
2077 /* Setup the implicit swapchain */
2078 TRACE("Creating implicit swapchain\n");
2079 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2080 WARN("Failed to create implicit swapchain\n");
2081 return WINED3DERR_INVALIDCALL;
2084 This->NumberOfSwapChains = 1;
2085 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2086 if(!This->swapchains) {
2087 ERR("Out of memory!\n");
2088 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2089 return E_OUTOFMEMORY;
2091 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2093 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2094 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2095 This->renderTarget = swapchain->backBuffer[0];
2097 else {
2098 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2099 This->renderTarget = swapchain->frontBuffer;
2101 IWineD3DSurface_AddRef(This->renderTarget);
2102 /* Depth Stencil support */
2103 This->stencilBufferTarget = This->depthStencilBuffer;
2104 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2105 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
2107 if (NULL != This->stencilBufferTarget) {
2108 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2111 /* Set up some starting GL setup */
2112 ENTER_GL();
2114 * Initialize openGL extension related variables
2115 * with Default values
2118 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2119 /* Setup all the devices defaults */
2120 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2121 #if 0
2122 IWineD3DImpl_CheckGraphicsMemory();
2123 #endif
2124 LEAVE_GL();
2126 /* Initialize our list of GLSL programs */
2127 list_init(&This->glsl_shader_progs);
2129 { /* Set a default viewport */
2130 WINED3DVIEWPORT vp;
2131 vp.X = 0;
2132 vp.Y = 0;
2133 vp.Width = *(pPresentationParameters->BackBufferWidth);
2134 vp.Height = *(pPresentationParameters->BackBufferHeight);
2135 vp.MinZ = 0.0f;
2136 vp.MaxZ = 1.0f;
2137 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2140 /* Initialize the current view state */
2141 This->modelview_valid = 1;
2142 This->proj_valid = 0;
2143 This->view_ident = 1;
2144 This->last_was_rhw = 0;
2145 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2146 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2148 /* Clear the screen */
2149 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2151 This->d3d_initialized = TRUE;
2152 return WINED3D_OK;
2155 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface) {
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2157 int sampler;
2158 IUnknown* swapChainParent;
2159 uint i;
2160 TRACE("(%p)\n", This);
2162 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2164 /* Delete the mouse cursor texture */
2165 if(This->cursorTexture) {
2166 ENTER_GL();
2167 glDeleteTextures(1, &This->cursorTexture);
2168 LEAVE_GL();
2169 This->cursorTexture = 0;
2172 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2173 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2176 /* Release the buffers (with sanity checks)*/
2177 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2178 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2179 if(This->depthStencilBuffer != This->stencilBufferTarget)
2180 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2182 This->stencilBufferTarget = NULL;
2184 TRACE("Releasing the render target at %p\n", This->renderTarget);
2185 if(IWineD3DSurface_Release(This->renderTarget) >0){
2186 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2188 TRACE("Setting rendertarget to NULL\n");
2189 This->renderTarget = NULL;
2191 if (This->depthStencilBuffer) {
2192 if(D3DCB_DestroyDepthStencilSurface > 0) {
2193 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2195 This->depthStencilBuffer = NULL;
2198 for(i=0; i < This->NumberOfSwapChains; i++) {
2199 TRACE("Releasing the implicit swapchain %d\n", i);
2200 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2201 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2202 IUnknown_Release(swapChainParent); /* once for the get parent */
2203 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2204 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2208 HeapFree(GetProcessHeap(), 0, This->swapchains);
2209 This->swapchains = NULL;
2210 This->NumberOfSwapChains = 0;
2212 This->d3d_initialized = FALSE;
2213 return WINED3D_OK;
2216 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2218 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2220 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2221 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2222 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2223 * separately.
2225 This->ddraw_fullscreen = fullscreen;
2228 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2231 DEVMODEW DevModeW;
2232 int i;
2233 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2235 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2237 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2238 /* Ignore some modes if a description was passed */
2239 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2240 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2241 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2243 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2245 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2246 return D3D_OK;
2249 return D3D_OK;
2252 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2253 DEVMODEW devmode;
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 LONG ret;
2256 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2258 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2260 /* Resize the screen even without a window:
2261 * The app could have unset it with SetCooperativeLevel, but not called
2262 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2263 * but we don't have any hwnd
2266 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2267 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2268 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2269 devmode.dmPelsWidth = pMode->Width;
2270 devmode.dmPelsHeight = pMode->Height;
2272 devmode.dmDisplayFrequency = pMode->RefreshRate;
2273 if (pMode->RefreshRate != 0) {
2274 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2277 /* Only change the mode if necessary */
2278 if( (This->ddraw_width == pMode->Width) &&
2279 (This->ddraw_height == pMode->Height) &&
2280 (This->ddraw_format == pMode->Format) &&
2281 (pMode->RefreshRate == 0) ) {
2282 return D3D_OK;
2285 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2286 if (ret != DISP_CHANGE_SUCCESSFUL) {
2287 if(devmode.dmDisplayFrequency != 0) {
2288 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2289 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2290 devmode.dmDisplayFrequency = 0;
2291 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2293 if(ret != DISP_CHANGE_SUCCESSFUL) {
2294 return DDERR_INVALIDMODE;
2298 /* Store the new values */
2299 This->ddraw_width = pMode->Width;
2300 This->ddraw_height = pMode->Height;
2301 This->ddraw_format = pMode->Format;
2303 /* Only do this with a window of course */
2304 if(This->ddraw_window)
2305 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2307 return WINED3D_OK;
2310 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2312 *ppD3D= This->wineD3D;
2313 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2314 IWineD3D_AddRef(*ppD3D);
2315 return WINED3D_OK;
2318 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2319 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2320 * into the video ram as possible and seeing how many fit
2321 * you can also get the correct initial value from nvidia and ATI's driver via X
2322 * texture memory is video memory + AGP memory
2323 *******************/
2324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2325 static BOOL showfixmes = TRUE;
2326 if (showfixmes) {
2327 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2328 (wined3d_settings.emulated_textureram/(1024*1024)),
2329 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2330 showfixmes = FALSE;
2332 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2333 (wined3d_settings.emulated_textureram/(1024*1024)),
2334 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2335 /* return simulated texture memory left */
2336 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2341 /*****
2342 * Get / Set FVF
2343 *****/
2344 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 HRESULT hr = WINED3D_OK;
2348 /* Update the current state block */
2349 This->updateStateBlock->fvf = fvf;
2350 This->updateStateBlock->changed.fvf = TRUE;
2351 This->updateStateBlock->set.fvf = TRUE;
2353 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2354 return hr;
2358 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2361 *pfvf = This->stateBlock->fvf;
2362 return WINED3D_OK;
2365 /*****
2366 * Get / Set Stream Source
2367 *****/
2368 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2370 IWineD3DVertexBuffer *oldSrc;
2372 /**TODO: instance and index data, see
2373 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2375 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2376 **************/
2378 /* D3d9 only, but shouldn't hurt d3d8 */
2379 UINT streamFlags;
2381 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2382 if (streamFlags) {
2383 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2384 FIXME("stream index data not supported\n");
2386 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2387 FIXME("stream instance data not supported\n");
2391 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2393 if (StreamNumber >= MAX_STREAMS) {
2394 WARN("Stream out of range %d\n", StreamNumber);
2395 return WINED3DERR_INVALIDCALL;
2398 oldSrc = This->stateBlock->streamSource[StreamNumber];
2399 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2401 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2402 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2403 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2404 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2405 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2406 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2408 /* Handle recording of state blocks */
2409 if (This->isRecordingState) {
2410 TRACE("Recording... not performing anything\n");
2411 return WINED3D_OK;
2414 /* Same stream object: no action */
2415 if (oldSrc == pStreamData)
2416 return WINED3D_OK;
2418 /* Need to do a getParent and pass the reffs up */
2419 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2420 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2421 so for now, just count internally */
2422 if (pStreamData != NULL) {
2423 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2424 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2425 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2427 vbImpl->stream = StreamNumber;
2428 vbImpl->Flags |= VBFLAG_STREAM;
2429 IWineD3DVertexBuffer_AddRef(pStreamData);
2431 if (oldSrc != NULL) {
2432 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2433 IWineD3DVertexBuffer_Release(oldSrc);
2436 return WINED3D_OK;
2439 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2441 UINT streamFlags;
2443 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2444 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2447 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2448 if (streamFlags) {
2449 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2450 FIXME("stream index data not supported\n");
2452 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2453 FIXME("stream instance data not supported\n");
2457 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2459 if (StreamNumber >= MAX_STREAMS) {
2460 WARN("Stream out of range %d\n", StreamNumber);
2461 return WINED3DERR_INVALIDCALL;
2463 *pStream = This->stateBlock->streamSource[StreamNumber];
2464 *pStride = This->stateBlock->streamStride[StreamNumber];
2465 if (pOffset) {
2466 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2469 if (*pStream == NULL) {
2470 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2471 return WINED3DERR_INVALIDCALL;
2474 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2475 return WINED3D_OK;
2478 /*Should be quite easy, just an extension of vertexdata
2479 ref...
2480 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2482 The divider is a bit odd though
2484 VertexOffset = StartVertex / Divider * StreamStride +
2485 VertexIndex / Divider * StreamStride + StreamOffset
2488 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2491 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2492 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2494 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2495 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2496 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2498 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2499 FIXME("Stream indexing not fully supported\n");
2502 return WINED3D_OK;
2505 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2509 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2511 TRACE("(%p) : returning %d\n", This, *Divider);
2513 return WINED3D_OK;
2516 /*****
2517 * Get / Set & Multiply Transform
2518 *****/
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 /* Most of this routine, comments included copied from ddraw tree initially: */
2523 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2525 /* Handle recording of state blocks */
2526 if (This->isRecordingState) {
2527 TRACE("Recording... not performing anything\n");
2528 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2529 This->updateStateBlock->set.transform[d3dts] = TRUE;
2530 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2531 return WINED3D_OK;
2535 * If the new matrix is the same as the current one,
2536 * we cut off any further processing. this seems to be a reasonable
2537 * optimization because as was noticed, some apps (warcraft3 for example)
2538 * tend towards setting the same matrix repeatedly for some reason.
2540 * From here on we assume that the new matrix is different, wherever it matters.
2542 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2543 TRACE("The app is setting the same matrix over again\n");
2544 return WINED3D_OK;
2545 } else {
2546 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2550 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2551 where ViewMat = Camera space, WorldMat = world space.
2553 In OpenGL, camera and world space is combined into GL_MODELVIEW
2554 matrix. The Projection matrix stay projection matrix.
2557 /* Capture the times we can just ignore the change for now */
2558 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2559 This->modelview_valid = FALSE;
2560 return WINED3D_OK;
2562 } else if (d3dts == WINED3DTS_PROJECTION) {
2563 This->proj_valid = FALSE;
2564 return WINED3D_OK;
2566 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2567 /* Indexed Vertex Blending Matrices 256 -> 511 */
2568 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2569 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2570 return WINED3D_OK;
2573 /* Now we really are going to have to change a matrix */
2574 ENTER_GL();
2576 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2577 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2578 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2579 unsigned int k;
2581 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2582 * NOTE: We have to reset the positions even if the light/plane is not currently
2583 * enabled, since the call to enable it will not reset the position.
2584 * NOTE2: Apparently texture transforms do NOT need reapplying
2587 PLIGHTINFOEL *lightChain = NULL;
2588 This->modelview_valid = FALSE;
2589 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2591 glMatrixMode(GL_MODELVIEW);
2592 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2593 glPushMatrix();
2594 glLoadMatrixf((const float *)lpmatrix);
2595 checkGLcall("glLoadMatrixf(...)");
2597 /* Reset lights */
2598 lightChain = This->stateBlock->lights;
2599 while (lightChain && lightChain->glIndex != -1) {
2600 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2601 checkGLcall("glLightfv posn");
2602 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2603 checkGLcall("glLightfv dirn");
2604 lightChain = lightChain->next;
2607 /* Reset Clipping Planes if clipping is enabled */
2608 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2609 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2610 checkGLcall("glClipPlane");
2612 glPopMatrix();
2614 } else { /* What was requested!?? */
2615 WARN("invalid matrix specified: %i\n", d3dts);
2618 /* Release lock, all done */
2619 LEAVE_GL();
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2626 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2627 return WINED3D_OK;
2630 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2631 WINED3DMATRIX *mat = NULL;
2632 WINED3DMATRIX temp;
2634 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2635 * below means it will be recorded in a state block change, but it
2636 * works regardless where it is recorded.
2637 * If this is found to be wrong, change to StateBlock.
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2642 if (State < HIGHEST_TRANSFORMSTATE)
2644 mat = &This->updateStateBlock->transforms[State];
2645 } else {
2646 FIXME("Unhandled transform state!!\n");
2649 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2651 /* Apply change via set transform - will reapply to eg. lights this way */
2652 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2655 /*****
2656 * Get / Set Light
2657 *****/
2658 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2659 you can reference any indexes you want as long as that number max are enabled at any
2660 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2661 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2662 but when recording, just build a chain pretty much of commands to be replayed. */
2664 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2665 float rho;
2666 PLIGHTINFOEL *object, *temp;
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2671 /* If recording state block, just add to end of lights chain */
2672 if (This->isRecordingState) {
2673 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2674 if (NULL == object) {
2675 return WINED3DERR_OUTOFVIDEOMEMORY;
2677 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2678 object->OriginalIndex = Index;
2679 object->glIndex = -1;
2680 object->changed = TRUE;
2682 /* Add to the END of the chain of lights changes to be replayed */
2683 if (This->updateStateBlock->lights == NULL) {
2684 This->updateStateBlock->lights = object;
2685 } else {
2686 temp = This->updateStateBlock->lights;
2687 while (temp->next != NULL) temp=temp->next;
2688 temp->next = object;
2690 TRACE("Recording... not performing anything more\n");
2691 return WINED3D_OK;
2694 /* Ok, not recording any longer so do real work */
2695 object = This->stateBlock->lights;
2696 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2698 /* If we didn't find it in the list of lights, time to add it */
2699 if (object == NULL) {
2700 PLIGHTINFOEL *insertAt,*prevPos;
2702 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2703 if (NULL == object) {
2704 return WINED3DERR_OUTOFVIDEOMEMORY;
2706 object->OriginalIndex = Index;
2707 object->glIndex = -1;
2709 /* Add it to the front of list with the idea that lights will be changed as needed
2710 BUT after any lights currently assigned GL indexes */
2711 insertAt = This->stateBlock->lights;
2712 prevPos = NULL;
2713 while (insertAt != NULL && insertAt->glIndex != -1) {
2714 prevPos = insertAt;
2715 insertAt = insertAt->next;
2718 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2719 This->stateBlock->lights = object;
2720 } else if (insertAt == NULL) { /* End of list */
2721 prevPos->next = object;
2722 object->prev = prevPos;
2723 } else { /* Middle of chain */
2724 if (prevPos == NULL) {
2725 This->stateBlock->lights = object;
2726 } else {
2727 prevPos->next = object;
2729 object->prev = prevPos;
2730 object->next = insertAt;
2731 insertAt->prev = object;
2735 /* Initialize the object */
2736 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2737 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2738 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2739 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2740 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2741 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2742 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2744 /* Save away the information */
2745 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2747 switch (pLight->Type) {
2748 case WINED3DLIGHT_POINT:
2749 /* Position */
2750 object->lightPosn[0] = pLight->Position.x;
2751 object->lightPosn[1] = pLight->Position.y;
2752 object->lightPosn[2] = pLight->Position.z;
2753 object->lightPosn[3] = 1.0f;
2754 object->cutoff = 180.0f;
2755 /* FIXME: Range */
2756 break;
2758 case WINED3DLIGHT_DIRECTIONAL:
2759 /* Direction */
2760 object->lightPosn[0] = -pLight->Direction.x;
2761 object->lightPosn[1] = -pLight->Direction.y;
2762 object->lightPosn[2] = -pLight->Direction.z;
2763 object->lightPosn[3] = 0.0;
2764 object->exponent = 0.0f;
2765 object->cutoff = 180.0f;
2766 break;
2768 case WINED3DLIGHT_SPOT:
2769 /* Position */
2770 object->lightPosn[0] = pLight->Position.x;
2771 object->lightPosn[1] = pLight->Position.y;
2772 object->lightPosn[2] = pLight->Position.z;
2773 object->lightPosn[3] = 1.0;
2775 /* Direction */
2776 object->lightDirn[0] = pLight->Direction.x;
2777 object->lightDirn[1] = pLight->Direction.y;
2778 object->lightDirn[2] = pLight->Direction.z;
2779 object->lightDirn[3] = 1.0;
2782 * opengl-ish and d3d-ish spot lights use too different models for the
2783 * light "intensity" as a function of the angle towards the main light direction,
2784 * so we only can approximate very roughly.
2785 * however spot lights are rather rarely used in games (if ever used at all).
2786 * furthermore if still used, probably nobody pays attention to such details.
2788 if (pLight->Falloff == 0) {
2789 rho = 6.28f;
2790 } else {
2791 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2793 if (rho < 0.0001) rho = 0.0001f;
2794 object->exponent = -0.3/log(cos(rho/2));
2795 if (object->exponent > 128.0) {
2796 object->exponent = 128.0;
2798 object->cutoff = pLight->Phi*90/M_PI;
2800 /* FIXME: Range */
2801 break;
2803 default:
2804 FIXME("Unrecognized light type %d\n", pLight->Type);
2807 /* Update the live definitions if the light is currently assigned a glIndex */
2808 if (object->glIndex != -1) {
2809 setup_light(iface, object->glIndex, object);
2811 return WINED3D_OK;
2814 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2815 PLIGHTINFOEL *lightInfo = NULL;
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2819 /* Locate the light in the live lights */
2820 lightInfo = This->stateBlock->lights;
2821 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2823 if (lightInfo == NULL) {
2824 TRACE("Light information requested but light not defined\n");
2825 return WINED3DERR_INVALIDCALL;
2828 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2829 return WINED3D_OK;
2832 /*****
2833 * Get / Set Light Enable
2834 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2835 *****/
2836 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2837 PLIGHTINFOEL *lightInfo = NULL;
2838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2839 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2841 /* Tests show true = 128...not clear why */
2843 Enable = Enable? 128: 0;
2845 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2846 if (This->isRecordingState) {
2847 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2848 if (NULL == lightInfo) {
2849 return WINED3DERR_OUTOFVIDEOMEMORY;
2851 lightInfo->OriginalIndex = Index;
2852 lightInfo->glIndex = -1;
2853 lightInfo->enabledChanged = TRUE;
2854 lightInfo->lightEnabled = Enable;
2856 /* Add to the END of the chain of lights changes to be replayed */
2857 if (This->updateStateBlock->lights == NULL) {
2858 This->updateStateBlock->lights = lightInfo;
2859 } else {
2860 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2861 while (temp->next != NULL) temp=temp->next;
2862 temp->next = lightInfo;
2864 TRACE("Recording... not performing anything more\n");
2865 return WINED3D_OK;
2868 /* Not recording... So, locate the light in the live lights */
2869 lightInfo = This->stateBlock->lights;
2870 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2872 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2873 if (lightInfo == NULL) {
2875 TRACE("Light enabled requested but light not defined, so defining one!\n");
2876 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2878 /* Search for it again! Should be fairly quick as near head of list */
2879 lightInfo = This->stateBlock->lights;
2880 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2881 if (lightInfo == NULL) {
2882 FIXME("Adding default lights has failed dismally\n");
2883 return WINED3DERR_INVALIDCALL;
2887 /* OK, we now have a light... */
2888 if (!Enable) {
2890 /* If we are disabling it, check it was enabled, and
2891 still only do something if it has assigned a glIndex (which it should have!) */
2892 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2893 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2894 ENTER_GL();
2895 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2896 checkGLcall("glDisable GL_LIGHT0+Index");
2897 LEAVE_GL();
2898 } else {
2899 TRACE("Nothing to do as light was not enabled\n");
2901 lightInfo->lightEnabled = Enable;
2902 } else {
2904 /* We are enabling it. If it is enabled, it's really simple */
2905 if (lightInfo->lightEnabled) {
2906 /* nop */
2907 TRACE("Nothing to do as light was enabled\n");
2909 /* If it already has a glIndex, it's still simple */
2910 } else if (lightInfo->glIndex != -1) {
2911 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2912 lightInfo->lightEnabled = Enable;
2913 ENTER_GL();
2914 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2915 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2916 LEAVE_GL();
2918 /* Otherwise got to find space - lights are ordered gl indexes first */
2919 } else {
2920 PLIGHTINFOEL *bsf = NULL;
2921 PLIGHTINFOEL *pos = This->stateBlock->lights;
2922 PLIGHTINFOEL *prev = NULL;
2923 int Index= 0;
2924 int glIndex = -1;
2926 /* Try to minimize changes as much as possible */
2927 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2929 /* Try to remember which index can be replaced if necessary */
2930 if (bsf==NULL && !pos->lightEnabled) {
2931 /* Found a light we can replace, save as best replacement */
2932 bsf = pos;
2935 /* Step to next space */
2936 prev = pos;
2937 pos = pos->next;
2938 Index ++;
2941 /* If we have too many active lights, fail the call */
2942 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2943 FIXME("Program requests too many concurrent lights\n");
2944 return WINED3DERR_INVALIDCALL;
2946 /* If we have allocated all lights, but not all are enabled,
2947 reuse one which is not enabled */
2948 } else if (Index == This->maxConcurrentLights) {
2949 /* use bsf - Simply swap the new light and the BSF one */
2950 PLIGHTINFOEL *bsfNext = bsf->next;
2951 PLIGHTINFOEL *bsfPrev = bsf->prev;
2953 /* Sort out ends */
2954 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2955 if (bsf->prev != NULL) {
2956 bsf->prev->next = lightInfo;
2957 } else {
2958 This->stateBlock->lights = lightInfo;
2961 /* If not side by side, lots of chains to update */
2962 if (bsf->next != lightInfo) {
2963 lightInfo->prev->next = bsf;
2964 bsf->next->prev = lightInfo;
2965 bsf->next = lightInfo->next;
2966 bsf->prev = lightInfo->prev;
2967 lightInfo->next = bsfNext;
2968 lightInfo->prev = bsfPrev;
2970 } else {
2971 /* Simple swaps */
2972 bsf->prev = lightInfo;
2973 bsf->next = lightInfo->next;
2974 lightInfo->next = bsf;
2975 lightInfo->prev = bsfPrev;
2979 /* Update states */
2980 glIndex = bsf->glIndex;
2981 bsf->glIndex = -1;
2982 lightInfo->glIndex = glIndex;
2983 lightInfo->lightEnabled = Enable;
2985 /* Finally set up the light in gl itself */
2986 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2987 ENTER_GL();
2988 setup_light(iface, glIndex, lightInfo);
2989 glEnable(GL_LIGHT0 + glIndex);
2990 checkGLcall("glEnable GL_LIGHT0 new setup");
2991 LEAVE_GL();
2993 /* If we reached the end of the allocated lights, with space in the
2994 gl lights, setup a new light */
2995 } else if (pos->glIndex == -1) {
2997 /* We reached the end of the allocated gl lights, so already
2998 know the index of the next one! */
2999 glIndex = Index;
3000 lightInfo->glIndex = glIndex;
3001 lightInfo->lightEnabled = Enable;
3003 /* In an ideal world, it's already in the right place */
3004 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
3005 /* No need to move it */
3006 } else {
3007 /* Remove this light from the list */
3008 lightInfo->prev->next = lightInfo->next;
3009 if (lightInfo->next != NULL) {
3010 lightInfo->next->prev = lightInfo->prev;
3013 /* Add in at appropriate place (inbetween prev and pos) */
3014 lightInfo->prev = prev;
3015 lightInfo->next = pos;
3016 if (prev == NULL) {
3017 This->stateBlock->lights = lightInfo;
3018 } else {
3019 prev->next = lightInfo;
3021 if (pos != NULL) {
3022 pos->prev = lightInfo;
3026 /* Finally set up the light in gl itself */
3027 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3028 ENTER_GL();
3029 setup_light(iface, glIndex, lightInfo);
3030 glEnable(GL_LIGHT0 + glIndex);
3031 checkGLcall("glEnable GL_LIGHT0 new setup");
3032 LEAVE_GL();
3037 return WINED3D_OK;
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3042 PLIGHTINFOEL *lightInfo = NULL;
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 TRACE("(%p) : for idx(%d)\n", This, Index);
3046 /* Locate the light in the live lights */
3047 lightInfo = This->stateBlock->lights;
3048 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3050 if (lightInfo == NULL) {
3051 TRACE("Light enabled state requested but light not defined\n");
3052 return WINED3DERR_INVALIDCALL;
3054 *pEnable = lightInfo->lightEnabled;
3055 return WINED3D_OK;
3058 /*****
3059 * Get / Set Clip Planes
3060 *****/
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3065 /* Validate Index */
3066 if (Index >= GL_LIMITS(clipplanes)) {
3067 TRACE("Application has requested clipplane this device doesn't support\n");
3068 return WINED3DERR_INVALIDCALL;
3071 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3072 This->updateStateBlock->set.clipplane[Index] = TRUE;
3073 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3074 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3075 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3076 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3078 /* Handle recording of state blocks */
3079 if (This->isRecordingState) {
3080 TRACE("Recording... not performing anything\n");
3081 return WINED3D_OK;
3084 /* Apply it */
3086 ENTER_GL();
3088 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3089 glMatrixMode(GL_MODELVIEW);
3090 glPushMatrix();
3091 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3093 TRACE("Clipplane [%f,%f,%f,%f]\n",
3094 This->updateStateBlock->clipplane[Index][0],
3095 This->updateStateBlock->clipplane[Index][1],
3096 This->updateStateBlock->clipplane[Index][2],
3097 This->updateStateBlock->clipplane[Index][3]);
3098 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3099 checkGLcall("glClipPlane");
3101 glPopMatrix();
3102 LEAVE_GL();
3104 return WINED3D_OK;
3107 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 TRACE("(%p) : for idx %d\n", This, Index);
3111 /* Validate Index */
3112 if (Index >= GL_LIMITS(clipplanes)) {
3113 TRACE("Application has requested clipplane this device doesn't support\n");
3114 return WINED3DERR_INVALIDCALL;
3117 pPlane[0] = This->stateBlock->clipplane[Index][0];
3118 pPlane[1] = This->stateBlock->clipplane[Index][1];
3119 pPlane[2] = This->stateBlock->clipplane[Index][2];
3120 pPlane[3] = This->stateBlock->clipplane[Index][3];
3121 return WINED3D_OK;
3124 /*****
3125 * Get / Set Clip Plane Status
3126 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3127 *****/
3128 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 FIXME("(%p) : stub\n", This);
3131 if (NULL == pClipStatus) {
3132 return WINED3DERR_INVALIDCALL;
3134 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3135 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 FIXME("(%p) : stub\n", This);
3142 if (NULL == pClipStatus) {
3143 return WINED3DERR_INVALIDCALL;
3145 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3146 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3147 return WINED3D_OK;
3150 /*****
3151 * Get / Set Material
3152 *****/
3153 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 This->updateStateBlock->changed.material = TRUE;
3157 This->updateStateBlock->set.material = TRUE;
3158 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3160 /* Handle recording of state blocks */
3161 if (This->isRecordingState) {
3162 TRACE("Recording... not performing anything\n");
3163 return WINED3D_OK;
3166 ENTER_GL();
3167 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3168 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3169 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3170 pMaterial->Ambient.b, pMaterial->Ambient.a);
3171 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3172 pMaterial->Specular.b, pMaterial->Specular.a);
3173 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3174 pMaterial->Emissive.b, pMaterial->Emissive.a);
3175 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3177 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3178 checkGLcall("glMaterialfv(GL_AMBIENT)");
3179 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3180 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3182 /* Only change material color if specular is enabled, otherwise it is set to black */
3183 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3184 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3185 checkGLcall("glMaterialfv(GL_SPECULAR");
3186 } else {
3187 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3188 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3189 checkGLcall("glMaterialfv(GL_SPECULAR");
3191 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3192 checkGLcall("glMaterialfv(GL_EMISSION)");
3193 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3194 checkGLcall("glMaterialf(GL_SHININESS");
3196 LEAVE_GL();
3197 return WINED3D_OK;
3200 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3203 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3204 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3205 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3206 pMaterial->Ambient.b, pMaterial->Ambient.a);
3207 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3208 pMaterial->Specular.b, pMaterial->Specular.a);
3209 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3210 pMaterial->Emissive.b, pMaterial->Emissive.a);
3211 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3213 return WINED3D_OK;
3216 /*****
3217 * Get / Set Indices
3218 *****/
3219 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3220 UINT BaseVertexIndex) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 IWineD3DIndexBuffer *oldIdxs;
3224 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3225 oldIdxs = This->updateStateBlock->pIndexData;
3227 This->updateStateBlock->changed.indices = TRUE;
3228 This->updateStateBlock->set.indices = TRUE;
3229 This->updateStateBlock->pIndexData = pIndexData;
3230 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3232 /* Handle recording of state blocks */
3233 if (This->isRecordingState) {
3234 TRACE("Recording... not performing anything\n");
3235 return WINED3D_OK;
3238 if (NULL != pIndexData) {
3239 IWineD3DIndexBuffer_AddRef(pIndexData);
3241 if (NULL != oldIdxs) {
3242 IWineD3DIndexBuffer_Release(oldIdxs);
3244 return WINED3D_OK;
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 *ppIndexData = This->stateBlock->pIndexData;
3252 /* up ref count on ppindexdata */
3253 if (*ppIndexData) {
3254 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3255 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3256 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3257 }else{
3258 TRACE("(%p) No index data set\n", This);
3260 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3262 return WINED3D_OK;
3265 /*****
3266 * Get / Set Viewports
3267 *****/
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3271 TRACE("(%p)\n", This);
3272 This->updateStateBlock->changed.viewport = TRUE;
3273 This->updateStateBlock->set.viewport = TRUE;
3274 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3276 /* Handle recording of state blocks */
3277 if (This->isRecordingState) {
3278 TRACE("Recording... not performing anything\n");
3279 return WINED3D_OK;
3281 This->viewport_changed = TRUE;
3283 ENTER_GL();
3285 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3286 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3288 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3289 checkGLcall("glDepthRange");
3290 /* Note: GL requires lower left, DirectX supplies upper left */
3291 /* TODO: replace usage of renderTarget with context management */
3292 glViewport(pViewport->X,
3293 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3294 pViewport->Width, pViewport->Height);
3296 checkGLcall("glViewport");
3298 LEAVE_GL();
3300 return WINED3D_OK;
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 TRACE("(%p)\n", This);
3307 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3308 return WINED3D_OK;
3311 /*****
3312 * Get / Set Render States
3313 * TODO: Verify against dx9 definitions
3314 *****/
3315 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 /* Simple way of referring to either a DWORD or a 4 byte float */
3320 union {
3321 DWORD d;
3322 float f;
3323 } tmpvalue;
3325 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3326 This->updateStateBlock->changed.renderState[State] = TRUE;
3327 This->updateStateBlock->set.renderState[State] = TRUE;
3328 This->updateStateBlock->renderState[State] = Value;
3330 /* Handle recording of state blocks */
3331 if (This->isRecordingState) {
3332 TRACE("Recording... not performing anything\n");
3333 return WINED3D_OK;
3336 ENTER_GL();
3338 switch (State) {
3339 case WINED3DRS_FILLMODE :
3340 case WINED3DRS_LIGHTING :
3341 case WINED3DRS_ZENABLE :
3342 case WINED3DRS_CULLMODE :
3343 case WINED3DRS_SHADEMODE :
3344 case WINED3DRS_DITHERENABLE :
3345 case WINED3DRS_ZWRITEENABLE :
3346 case WINED3DRS_ZFUNC :
3347 case WINED3DRS_AMBIENT :
3348 case WINED3DRS_ALPHABLENDENABLE :
3349 case WINED3DRS_SRCBLEND :
3350 case WINED3DRS_DESTBLEND :
3351 case WINED3DRS_ANTIALIASEDLINEENABLE :
3352 case WINED3DRS_BLENDFACTOR :
3353 case WINED3DRS_ALPHATESTENABLE :
3354 case WINED3DRS_ALPHAFUNC :
3355 case WINED3DRS_ALPHAREF :
3356 case WINED3DRS_COLORKEYENABLE :
3357 case WINED3DRS_CLIPPLANEENABLE :
3358 case WINED3DRS_CLIPPING :
3359 case WINED3DRS_BLENDOP :
3360 case WINED3DRS_TEXTUREFACTOR :
3361 case WINED3DRS_SPECULARENABLE :
3362 case WINED3DRS_STENCILENABLE :
3363 case WINED3DRS_TWOSIDEDSTENCILMODE :
3364 case WINED3DRS_STENCILFUNC :
3365 case WINED3DRS_CCW_STENCILFUNC :
3366 case WINED3DRS_STENCILREF :
3367 case WINED3DRS_STENCILMASK :
3368 case WINED3DRS_STENCILFAIL :
3369 case WINED3DRS_STENCILZFAIL :
3370 case WINED3DRS_STENCILPASS :
3371 case WINED3DRS_CCW_STENCILFAIL :
3372 case WINED3DRS_CCW_STENCILZFAIL :
3373 case WINED3DRS_CCW_STENCILPASS :
3374 case WINED3DRS_EDGEANTIALIAS :
3375 case WINED3DRS_STENCILWRITEMASK :
3376 case WINED3DRS_FOGENABLE :
3377 case WINED3DRS_FOGTABLEMODE :
3378 case WINED3DRS_FOGVERTEXMODE :
3379 case WINED3DRS_FOGSTART :
3380 case WINED3DRS_FOGEND :
3381 case WINED3DRS_RANGEFOGENABLE :
3382 case WINED3DRS_FOGCOLOR :
3383 case WINED3DRS_FOGDENSITY :
3384 case WINED3DRS_VERTEXBLEND :
3385 case WINED3DRS_TWEENFACTOR :
3386 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
3387 case WINED3DRS_COLORVERTEX :
3388 case WINED3DRS_DIFFUSEMATERIALSOURCE :
3389 case WINED3DRS_SPECULARMATERIALSOURCE :
3390 case WINED3DRS_AMBIENTMATERIALSOURCE :
3391 case WINED3DRS_EMISSIVEMATERIALSOURCE :
3392 case WINED3DRS_LINEPATTERN :
3393 case WINED3DRS_ZBIAS : /* D3D8 only */
3394 case WINED3DRS_NORMALIZENORMALS :
3395 case WINED3DRS_POINTSIZE :
3396 case WINED3DRS_POINTSIZE_MIN :
3397 case WINED3DRS_POINTSIZE_MAX :
3398 case WINED3DRS_POINTSCALE_A :
3399 case WINED3DRS_POINTSCALE_B :
3400 case WINED3DRS_POINTSCALE_C :
3401 case WINED3DRS_POINTSCALEENABLE :
3402 case WINED3DRS_COLORWRITEENABLE :
3403 case WINED3DRS_COLORWRITEENABLE1 :
3404 case WINED3DRS_COLORWRITEENABLE2 :
3405 case WINED3DRS_COLORWRITEENABLE3 :
3406 case WINED3DRS_LOCALVIEWER :
3407 case WINED3DRS_LASTPIXEL :
3408 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
3409 case WINED3DRS_POINTSPRITEENABLE :
3410 case WINED3DRS_WRAP0 :
3411 case WINED3DRS_WRAP1 :
3412 case WINED3DRS_WRAP2 :
3413 case WINED3DRS_WRAP3 :
3414 case WINED3DRS_WRAP4 :
3415 case WINED3DRS_WRAP5 :
3416 case WINED3DRS_WRAP6 :
3417 case WINED3DRS_WRAP7 :
3418 case WINED3DRS_WRAP8 :
3419 case WINED3DRS_WRAP9 :
3420 case WINED3DRS_WRAP10 :
3421 case WINED3DRS_WRAP11 :
3422 case WINED3DRS_WRAP12 :
3423 case WINED3DRS_WRAP13 :
3424 case WINED3DRS_WRAP14 :
3425 case WINED3DRS_WRAP15 :
3426 case WINED3DRS_MULTISAMPLEANTIALIAS :
3427 case WINED3DRS_SCISSORTESTENABLE :
3428 case WINED3DRS_SLOPESCALEDEPTHBIAS :
3429 case WINED3DRS_DEPTHBIAS :
3430 case WINED3DRS_TEXTUREPERSPECTIVE :
3431 case WINED3DRS_STIPPLEDALPHA :
3432 StateTable[STATE_RENDER(State)].apply(STATE_RENDER(State), This->stateBlock);
3433 break;
3435 /** not supported */
3436 case WINED3DRS_ZVISIBLE :
3438 LEAVE_GL();
3439 return WINED3DERR_INVALIDCALL;
3442 case WINED3DRS_ANTIALIAS :
3444 if (Value)
3445 ERR(" Antialias not supported yet.\n");
3446 break;
3449 case WINED3DRS_MULTISAMPLEMASK :
3451 if(0xFFFFFFFF != Value)
3452 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3453 break;
3456 case WINED3DRS_PATCHEDGESTYLE :
3458 if(WINED3DPATCHEDGE_DISCRETE != Value)
3459 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3460 break;
3463 case WINED3DRS_PATCHSEGMENTS :
3465 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
3466 tmpvalue.f = 1.0f;
3467 if(tmpvalue.d != Value)
3468 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3469 break;
3472 case WINED3DRS_DEBUGMONITORTOKEN :
3474 /* Only useful for "debug builds". */
3475 if(0xbaadcafe != Value) {
3476 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
3477 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
3478 * but our tests disagree.
3479 * We do not claim to implement a debugging lib, so do not write an ERR
3481 WARN("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3483 break;
3486 case WINED3DRS_POSITIONDEGREE :
3488 if(WINED3DDEGREE_CUBIC != Value)
3489 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3490 break;
3493 case WINED3DRS_NORMALDEGREE :
3495 if(WINED3DDEGREE_LINEAR != Value)
3496 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3497 break;
3500 case WINED3DRS_MINTESSELLATIONLEVEL :
3501 case WINED3DRS_MAXTESSELLATIONLEVEL :
3502 case WINED3DRS_ADAPTIVETESS_X :
3503 case WINED3DRS_ADAPTIVETESS_Y :
3504 case WINED3DRS_ADAPTIVETESS_Z :
3505 case WINED3DRS_ADAPTIVETESS_W :
3507 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
3508 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3509 else
3510 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
3511 break;
3514 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
3516 if(Value)
3517 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3518 break;
3521 case WINED3DRS_SRGBWRITEENABLE :
3523 if(Value)
3524 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3525 break;
3528 case WINED3DRS_SEPARATEALPHABLENDENABLE :
3530 if(Value)
3531 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
3532 break;
3535 case WINED3DRS_SRCBLENDALPHA :
3536 case WINED3DRS_DESTBLENDALPHA :
3537 case WINED3DRS_BLENDOPALPHA :
3539 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
3540 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
3541 else
3542 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
3543 break;
3546 default:
3547 FIXME("(%p)->(%s,%d) unknown state\n", This, debug_d3drenderstate(State), Value);
3550 LEAVE_GL();
3552 return WINED3D_OK;
3555 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3557 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3558 *pValue = This->stateBlock->renderState[State];
3559 return WINED3D_OK;
3562 /*****
3563 * Get / Set Sampler States
3564 * TODO: Verify against dx9 definitions
3565 *****/
3567 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3570 * SetSampler is designed to allow for more than the standard up to 8 textures
3571 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3572 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3574 * http://developer.nvidia.com/object/General_FAQ.html#t6
3576 * There are two new settings for GForce
3577 * the sampler one:
3578 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3579 * and the texture one:
3580 * GL_MAX_TEXTURE_COORDS_ARB.
3581 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3582 ******************/
3583 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3584 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3585 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3586 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3587 return WINED3DERR_INVALIDCALL;
3590 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3591 debug_d3dsamplerstate(Type), Type, Value);
3592 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3593 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3594 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3596 /* Handle recording of state blocks */
3597 if (This->isRecordingState) {
3598 TRACE("Recording... not performing anything\n");
3599 return WINED3D_OK;
3602 return WINED3D_OK;
3605 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3607 /** TODO: check that sampler is in range **/
3608 *Value = This->stateBlock->samplerState[Sampler][Type];
3609 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3611 return WINED3D_OK;
3614 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3616 RECT windowRect;
3617 UINT winHeight;
3619 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3620 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3621 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3623 winHeight = windowRect.bottom - windowRect.top;
3624 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3625 pRect->right - pRect->left, pRect->bottom - pRect->top);
3626 ENTER_GL();
3627 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3628 checkGLcall("glScissor");
3629 LEAVE_GL();
3631 return WINED3D_OK;
3634 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 GLint scissorBox[4];
3638 ENTER_GL();
3639 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3640 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3641 pRect->left = scissorBox[0];
3642 pRect->top = scissorBox[1];
3643 pRect->right = scissorBox[0] + scissorBox[2];
3644 pRect->bottom = scissorBox[1] + scissorBox[3];
3645 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3646 LEAVE_GL();
3647 return WINED3D_OK;
3650 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3652 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3654 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3656 This->updateStateBlock->vertexDecl = pDecl;
3657 This->updateStateBlock->changed.vertexDecl = TRUE;
3658 This->updateStateBlock->set.vertexDecl = TRUE;
3660 if (This->isRecordingState) {
3661 TRACE("Recording... not performing anything\n");
3664 if (NULL != pDecl) {
3665 IWineD3DVertexDeclaration_AddRef(pDecl);
3667 if (NULL != oldDecl) {
3668 IWineD3DVertexDeclaration_Release(oldDecl);
3670 return WINED3D_OK;
3673 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3678 *ppDecl = This->stateBlock->vertexDecl;
3679 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3680 return WINED3D_OK;
3683 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3685 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3687 This->updateStateBlock->vertexShader = pShader;
3688 This->updateStateBlock->changed.vertexShader = TRUE;
3689 This->updateStateBlock->set.vertexShader = TRUE;
3691 if (This->isRecordingState) {
3692 TRACE("Recording... not performing anything\n");
3695 if (NULL != pShader) {
3696 IWineD3DVertexShader_AddRef(pShader);
3698 if (NULL != oldShader) {
3699 IWineD3DVertexShader_Release(oldShader);
3702 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3704 * TODO: merge HAL shaders context switching from prototype
3706 return WINED3D_OK;
3709 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3712 if (NULL == ppShader) {
3713 return WINED3DERR_INVALIDCALL;
3715 *ppShader = This->stateBlock->vertexShader;
3716 if( NULL != *ppShader)
3717 IWineD3DVertexShader_AddRef(*ppShader);
3719 TRACE("(%p) : returning %p\n", This, *ppShader);
3720 return WINED3D_OK;
3723 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3724 IWineD3DDevice *iface,
3725 UINT start,
3726 CONST BOOL *srcData,
3727 UINT count) {
3729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3730 int i, cnt = min(count, MAX_CONST_B - start);
3732 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3733 iface, srcData, start, count);
3735 if (srcData == NULL || cnt < 0)
3736 return WINED3DERR_INVALIDCALL;
3738 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3739 for (i = 0; i < cnt; i++)
3740 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3742 for (i = start; i < cnt + start; ++i) {
3743 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3744 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3747 return WINED3D_OK;
3750 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3751 IWineD3DDevice *iface,
3752 UINT start,
3753 BOOL *dstData,
3754 UINT count) {
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 int cnt = min(count, MAX_CONST_B - start);
3759 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3760 iface, dstData, start, count);
3762 if (dstData == NULL || cnt < 0)
3763 return WINED3DERR_INVALIDCALL;
3765 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3766 return WINED3D_OK;
3769 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3770 IWineD3DDevice *iface,
3771 UINT start,
3772 CONST int *srcData,
3773 UINT count) {
3775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3776 int i, cnt = min(count, MAX_CONST_I - start);
3778 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3779 iface, srcData, start, count);
3781 if (srcData == NULL || cnt < 0)
3782 return WINED3DERR_INVALIDCALL;
3784 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3785 for (i = 0; i < cnt; i++)
3786 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3787 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3789 for (i = start; i < cnt + start; ++i) {
3790 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3791 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3794 return WINED3D_OK;
3797 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3798 IWineD3DDevice *iface,
3799 UINT start,
3800 int *dstData,
3801 UINT count) {
3803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3804 int cnt = min(count, MAX_CONST_I - start);
3806 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3807 iface, dstData, start, count);
3809 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3810 return WINED3DERR_INVALIDCALL;
3812 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3813 return WINED3D_OK;
3816 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3817 IWineD3DDevice *iface,
3818 UINT start,
3819 CONST float *srcData,
3820 UINT count) {
3822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3823 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3825 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3826 iface, srcData, start, count);
3828 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3829 return WINED3DERR_INVALIDCALL;
3831 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3832 for (i = 0; i < cnt; i++)
3833 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3834 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3836 for (i = start; i < cnt + start; ++i) {
3837 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3838 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3839 ptr->idx = i;
3840 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3841 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3843 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3846 return WINED3D_OK;
3849 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3850 IWineD3DDevice *iface,
3851 UINT start,
3852 float *dstData,
3853 UINT count) {
3855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3856 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3858 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3859 iface, dstData, start, count);
3861 if (dstData == NULL || cnt < 0)
3862 return WINED3DERR_INVALIDCALL;
3864 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3865 return WINED3D_OK;
3868 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3870 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3871 This->updateStateBlock->pixelShader = pShader;
3872 This->updateStateBlock->changed.pixelShader = TRUE;
3873 This->updateStateBlock->set.pixelShader = TRUE;
3875 /* Handle recording of state blocks */
3876 if (This->isRecordingState) {
3877 TRACE("Recording... not performing anything\n");
3880 if (NULL != pShader) {
3881 IWineD3DPixelShader_AddRef(pShader);
3883 if (NULL != oldShader) {
3884 IWineD3DPixelShader_Release(oldShader);
3887 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3889 * TODO: merge HAL shaders context switching from prototype
3891 return WINED3D_OK;
3894 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 if (NULL == ppShader) {
3898 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3899 return WINED3DERR_INVALIDCALL;
3902 *ppShader = This->stateBlock->pixelShader;
3903 if (NULL != *ppShader) {
3904 IWineD3DPixelShader_AddRef(*ppShader);
3906 TRACE("(%p) : returning %p\n", This, *ppShader);
3907 return WINED3D_OK;
3910 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3911 IWineD3DDevice *iface,
3912 UINT start,
3913 CONST BOOL *srcData,
3914 UINT count) {
3916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3917 int i, cnt = min(count, MAX_CONST_B - start);
3919 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3920 iface, srcData, start, count);
3922 if (srcData == NULL || cnt < 0)
3923 return WINED3DERR_INVALIDCALL;
3925 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3926 for (i = 0; i < cnt; i++)
3927 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3929 for (i = start; i < cnt + start; ++i) {
3930 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3931 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3934 return WINED3D_OK;
3937 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3938 IWineD3DDevice *iface,
3939 UINT start,
3940 BOOL *dstData,
3941 UINT count) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 int cnt = min(count, MAX_CONST_B - start);
3946 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3947 iface, dstData, start, count);
3949 if (dstData == NULL || cnt < 0)
3950 return WINED3DERR_INVALIDCALL;
3952 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3953 return WINED3D_OK;
3956 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3957 IWineD3DDevice *iface,
3958 UINT start,
3959 CONST int *srcData,
3960 UINT count) {
3962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3963 int i, cnt = min(count, MAX_CONST_I - start);
3965 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3966 iface, srcData, start, count);
3968 if (srcData == NULL || cnt < 0)
3969 return WINED3DERR_INVALIDCALL;
3971 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3972 for (i = 0; i < cnt; i++)
3973 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3974 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3976 for (i = start; i < cnt + start; ++i) {
3977 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3978 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3981 return WINED3D_OK;
3984 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3985 IWineD3DDevice *iface,
3986 UINT start,
3987 int *dstData,
3988 UINT count) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 int cnt = min(count, MAX_CONST_I - start);
3993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3994 iface, dstData, start, count);
3996 if (dstData == NULL || cnt < 0)
3997 return WINED3DERR_INVALIDCALL;
3999 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4004 IWineD3DDevice *iface,
4005 UINT start,
4006 CONST float *srcData,
4007 UINT count) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4012 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4013 iface, srcData, start, count);
4015 if (srcData == NULL || cnt < 0)
4016 return WINED3DERR_INVALIDCALL;
4018 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4019 for (i = 0; i < cnt; i++)
4020 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4021 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4023 for (i = start; i < cnt + start; ++i) {
4024 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
4025 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4026 ptr->idx = i;
4027 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4028 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
4030 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4033 return WINED3D_OK;
4036 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4037 IWineD3DDevice *iface,
4038 UINT start,
4039 float *dstData,
4040 UINT count) {
4042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4043 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4045 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4046 iface, dstData, start, count);
4048 if (dstData == NULL || cnt < 0)
4049 return WINED3DERR_INVALIDCALL;
4051 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4052 return WINED3D_OK;
4055 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4056 static HRESULT
4057 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4058 char *dest_ptr, *dest_conv = NULL;
4059 unsigned int i;
4060 DWORD DestFVF = dest->fvf;
4061 WINED3DVIEWPORT vp;
4062 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4063 BOOL doClip;
4064 int numTextures;
4066 if (SrcFVF & WINED3DFVF_NORMAL) {
4067 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4070 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
4071 ERR("Source has no position mask\n");
4072 return WINED3DERR_INVALIDCALL;
4075 /* We might access VBOs from this code, so hold the lock */
4076 ENTER_GL();
4078 if (dest->resource.allocatedMemory == NULL) {
4079 /* This may happen if we do direct locking into a vbo. Unlikely,
4080 * but theoretically possible(ddraw processvertices test)
4082 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4083 if(!dest->resource.allocatedMemory) {
4084 LEAVE_GL();
4085 ERR("Out of memory\n");
4086 return E_OUTOFMEMORY;
4088 if(dest->vbo) {
4089 void *src;
4090 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4091 checkGLcall("glBindBufferARB");
4092 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4093 if(src) {
4094 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4096 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4097 checkGLcall("glUnmapBufferARB");
4101 /* Get a pointer into the destination vbo(create one if none exists) and
4102 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4104 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4105 CreateVBO(dest);
4108 if(dest->vbo) {
4109 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4110 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
4111 if(!dest_conv) {
4112 ERR("glMapBuffer failed\n");
4113 /* Continue without storing converted vertices */
4117 /* Should I clip?
4118 * a) WINED3DRS_CLIPPING is enabled
4119 * b) WINED3DVOP_CLIP is passed
4121 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4122 static BOOL warned = FALSE;
4124 * The clipping code is not quite correct. Some things need
4125 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4126 * so disable clipping for now.
4127 * (The graphics in Half-Life are broken, and my processvertices
4128 * test crashes with IDirect3DDevice3)
4129 doClip = TRUE;
4131 doClip = FALSE;
4132 if(!warned) {
4133 warned = TRUE;
4134 FIXME("Clipping is broken and disabled for now\n");
4136 } else doClip = FALSE;
4137 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4138 if(dest_conv) {
4139 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4142 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4143 WINED3DTS_VIEW,
4144 &view_mat);
4145 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4146 WINED3DTS_PROJECTION,
4147 &proj_mat);
4148 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4149 WINED3DTS_WORLDMATRIX(0),
4150 &world_mat);
4152 TRACE("View mat:\n");
4153 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); \
4154 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); \
4155 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); \
4156 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); \
4158 TRACE("Proj mat:\n");
4159 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); \
4160 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); \
4161 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); \
4162 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); \
4164 TRACE("World mat:\n");
4165 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); \
4166 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); \
4167 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); \
4168 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); \
4170 /* Get the viewport */
4171 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4172 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4173 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4175 multiply_matrix(&mat,&view_mat,&world_mat);
4176 multiply_matrix(&mat,&proj_mat,&mat);
4178 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4180 for (i = 0; i < dwCount; i+= 1) {
4181 unsigned int tex_index;
4183 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4184 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4185 /* The position first */
4186 float *p =
4187 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4188 float x, y, z, rhw;
4189 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4191 /* Multiplication with world, view and projection matrix */
4192 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);
4193 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);
4194 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);
4195 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);
4197 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4199 /* WARNING: The following things are taken from d3d7 and were not yet checked
4200 * against d3d8 or d3d9!
4203 /* Clipping conditions: From
4204 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4206 * A vertex is clipped if it does not match the following requirements
4207 * -rhw < x <= rhw
4208 * -rhw < y <= rhw
4209 * 0 < z <= rhw
4210 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4212 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4213 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4217 if( !doClip ||
4218 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4219 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4220 ( rhw > eps ) ) ) {
4222 /* "Normal" viewport transformation (not clipped)
4223 * 1) The values are divided by rhw
4224 * 2) The y axis is negative, so multiply it with -1
4225 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4226 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4227 * 4) Multiply x with Width/2 and add Width/2
4228 * 5) The same for the height
4229 * 6) Add the viewpoint X and Y to the 2D coordinates and
4230 * The minimum Z value to z
4231 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4233 * Well, basically it's simply a linear transformation into viewport
4234 * coordinates
4237 x /= rhw;
4238 y /= rhw;
4239 z /= rhw;
4241 y *= -1;
4243 x *= vp.Width / 2;
4244 y *= vp.Height / 2;
4245 z *= vp.MaxZ - vp.MinZ;
4247 x += vp.Width / 2 + vp.X;
4248 y += vp.Height / 2 + vp.Y;
4249 z += vp.MinZ;
4251 rhw = 1 / rhw;
4252 } else {
4253 /* That vertex got clipped
4254 * Contrary to OpenGL it is not dropped completely, it just
4255 * undergoes a different calculation.
4257 TRACE("Vertex got clipped\n");
4258 x += rhw;
4259 y += rhw;
4261 x /= 2;
4262 y /= 2;
4264 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4265 * outside of the main vertex buffer memory. That needs some more
4266 * investigation...
4270 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4273 ( (float *) dest_ptr)[0] = x;
4274 ( (float *) dest_ptr)[1] = y;
4275 ( (float *) dest_ptr)[2] = z;
4276 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4278 dest_ptr += 3 * sizeof(float);
4280 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4281 dest_ptr += sizeof(float);
4284 if(dest_conv) {
4285 float w = 1 / rhw;
4286 ( (float *) dest_conv)[0] = x * w;
4287 ( (float *) dest_conv)[1] = y * w;
4288 ( (float *) dest_conv)[2] = z * w;
4289 ( (float *) dest_conv)[3] = w;
4291 dest_conv += 3 * sizeof(float);
4293 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4294 dest_conv += sizeof(float);
4298 if (DestFVF & WINED3DFVF_PSIZE) {
4299 dest_ptr += sizeof(DWORD);
4300 if(dest_conv) dest_conv += sizeof(DWORD);
4302 if (DestFVF & WINED3DFVF_NORMAL) {
4303 float *normal =
4304 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4305 /* AFAIK this should go into the lighting information */
4306 FIXME("Didn't expect the destination to have a normal\n");
4307 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4308 if(dest_conv) {
4309 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4313 if (DestFVF & WINED3DFVF_DIFFUSE) {
4314 DWORD *color_d =
4315 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4316 if(!color_d) {
4317 static BOOL warned = FALSE;
4319 if(!warned) {
4320 ERR("No diffuse color in source, but destination has one\n");
4321 warned = TRUE;
4324 *( (DWORD *) dest_ptr) = 0xffffffff;
4325 dest_ptr += sizeof(DWORD);
4327 if(dest_conv) {
4328 *( (DWORD *) dest_conv) = 0xffffffff;
4329 dest_conv += sizeof(DWORD);
4332 else {
4333 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4334 if(dest_conv) {
4335 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4336 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4337 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4338 dest_conv += sizeof(DWORD);
4343 if (DestFVF & WINED3DFVF_SPECULAR) {
4344 /* What's the color value in the feedback buffer? */
4345 DWORD *color_s =
4346 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4347 if(!color_s) {
4348 static BOOL warned = FALSE;
4350 if(!warned) {
4351 ERR("No specular color in source, but destination has one\n");
4352 warned = TRUE;
4355 *( (DWORD *) dest_ptr) = 0xFF000000;
4356 dest_ptr += sizeof(DWORD);
4358 if(dest_conv) {
4359 *( (DWORD *) dest_conv) = 0xFF000000;
4360 dest_conv += sizeof(DWORD);
4363 else {
4364 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4365 if(dest_conv) {
4366 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4367 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4368 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4369 dest_conv += sizeof(DWORD);
4374 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4375 float *tex_coord =
4376 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4377 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4378 if(!tex_coord) {
4379 ERR("No source texture, but destination requests one\n");
4380 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4381 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4383 else {
4384 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4385 if(dest_conv) {
4386 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4392 if(dest_conv) {
4393 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4394 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4397 LEAVE_GL();
4399 return WINED3D_OK;
4401 #undef copy_and_next
4403 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4406 WineDirect3DVertexStridedData strided;
4407 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4409 if (!SrcImpl) {
4410 WARN("NULL source vertex buffer\n");
4411 return WINED3DERR_INVALIDCALL;
4413 /* We don't need the source vbo because this buffer is only used as
4414 * a source for ProcessVertices. Avoid wasting resources by converting the
4415 * buffer and loading the VBO
4417 if(SrcImpl->vbo) {
4418 TRACE("Releasing the source vbo, it won't be needed\n");
4420 if(!SrcImpl->resource.allocatedMemory) {
4421 /* Rescue the data from the buffer */
4422 void *src;
4423 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4424 if(!SrcImpl->resource.allocatedMemory) {
4425 ERR("Out of memory\n");
4426 return E_OUTOFMEMORY;
4429 ENTER_GL();
4430 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4431 checkGLcall("glBindBufferARB");
4433 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4434 if(src) {
4435 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4438 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4439 checkGLcall("glUnmapBufferARB");
4440 } else {
4441 ENTER_GL();
4444 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4445 checkGLcall("glBindBufferARB");
4446 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4447 checkGLcall("glDeleteBuffersARB");
4448 LEAVE_GL();
4450 SrcImpl->vbo = 0;
4453 memset(&strided, 0, sizeof(strided));
4454 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4456 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4459 /*****
4460 * Apply / Get / Set Texture Stage States
4461 * TODO: Verify against dx9 definitions
4462 *****/
4464 /* 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 */
4465 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4467 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4468 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4470 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4472 /* Check that the stage is within limits */
4473 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
4474 TRACE("Attempt to access invalid texture rejected\n");
4475 return;
4478 ENTER_GL();
4480 switch (Type) {
4481 case WINED3DTSS_ALPHAOP :
4482 case WINED3DTSS_COLOROP :
4483 /* nothing to do as moved to drawprim for now */
4484 break;
4485 case WINED3DTSS_ADDRESSW :
4486 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
4487 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4488 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
4490 } else {
4491 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
4492 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
4493 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
4494 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
4496 #endif
4497 case WINED3DTSS_TEXCOORDINDEX :
4499 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
4501 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
4502 one flag, you can still specify an index value, which the system uses to
4503 determine the texture wrapping mode.
4504 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
4505 means use the vertex position (camera-space) as the input texture coordinates
4506 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
4507 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
4508 to the TEXCOORDINDEX value */
4511 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
4513 switch (Value & 0xFFFF0000) {
4514 case WINED3DTSS_TCI_PASSTHRU:
4515 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
4516 glDisable(GL_TEXTURE_GEN_S);
4517 glDisable(GL_TEXTURE_GEN_T);
4518 glDisable(GL_TEXTURE_GEN_R);
4519 glDisable(GL_TEXTURE_GEN_Q);
4520 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
4521 break;
4523 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
4524 /* CameraSpacePosition means use the vertex position, transformed to camera space,
4525 as the input texture coordinates for this stage's texture transformation. This
4526 equates roughly to EYE_LINEAR */
4528 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4529 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4530 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4531 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4532 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
4534 glMatrixMode(GL_MODELVIEW);
4535 glPushMatrix();
4536 glLoadIdentity();
4537 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4538 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4539 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4540 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4541 glPopMatrix();
4543 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
4544 glEnable(GL_TEXTURE_GEN_S);
4545 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4546 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4547 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4548 glEnable(GL_TEXTURE_GEN_T);
4549 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4550 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4551 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4552 glEnable(GL_TEXTURE_GEN_R);
4553 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4554 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4555 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4557 break;
4559 case WINED3DTSS_TCI_CAMERASPACENORMAL:
4561 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4562 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4563 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4564 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4565 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4566 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
4568 glMatrixMode(GL_MODELVIEW);
4569 glPushMatrix();
4570 glLoadIdentity();
4571 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4572 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4573 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4574 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4575 glPopMatrix();
4577 glEnable(GL_TEXTURE_GEN_S);
4578 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4579 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4580 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4581 glEnable(GL_TEXTURE_GEN_T);
4582 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4583 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4584 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4585 glEnable(GL_TEXTURE_GEN_R);
4586 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4587 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4588 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4591 break;
4593 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
4595 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4596 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4597 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4598 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4599 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4600 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
4602 glMatrixMode(GL_MODELVIEW);
4603 glPushMatrix();
4604 glLoadIdentity();
4605 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4606 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4607 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4608 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4609 glPopMatrix();
4611 glEnable(GL_TEXTURE_GEN_S);
4612 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4613 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4614 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4615 glEnable(GL_TEXTURE_GEN_T);
4616 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4617 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4618 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4619 glEnable(GL_TEXTURE_GEN_R);
4620 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4621 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4622 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4625 break;
4627 /* Unhandled types: */
4628 default:
4629 /* Todo: */
4630 /* ? disable GL_TEXTURE_GEN_n ? */
4631 glDisable(GL_TEXTURE_GEN_S);
4632 glDisable(GL_TEXTURE_GEN_T);
4633 glDisable(GL_TEXTURE_GEN_R);
4634 glDisable(GL_TEXTURE_GEN_Q);
4635 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
4636 break;
4639 break;
4641 /* Unhandled */
4642 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4643 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU);
4644 break;
4646 case WINED3DTSS_BUMPENVMAT00 :
4647 case WINED3DTSS_BUMPENVMAT01 :
4648 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4649 break;
4650 case WINED3DTSS_BUMPENVMAT10 :
4651 case WINED3DTSS_BUMPENVMAT11 :
4652 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4653 break;
4655 case WINED3DTSS_BUMPENVLSCALE :
4656 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4657 break;
4659 case WINED3DTSS_BUMPENVLOFFSET :
4660 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4661 break;
4663 case WINED3DTSS_RESULTARG :
4664 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4665 break;
4667 default:
4668 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
4669 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4672 LEAVE_GL();
4674 return;
4677 /*****
4678 * Get / Set Texture Stage States
4679 * TODO: Verify against dx9 definitions
4680 *****/
4681 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4684 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4686 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4688 /* Reject invalid texture units */
4689 if (Stage >= GL_LIMITS(texture_stages)) {
4690 TRACE("Attempt to access invalid texture rejected\n");
4691 return WINED3DERR_INVALIDCALL;
4694 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4695 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4696 This->updateStateBlock->textureState[Stage][Type] = Value;
4698 return WINED3D_OK;
4701 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4704 *pValue = This->updateStateBlock->textureState[Stage][Type];
4705 return WINED3D_OK;
4708 /*****
4709 * Get / Set Texture
4710 *****/
4711 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 IWineD3DBaseTexture *oldTexture;
4716 oldTexture = This->updateStateBlock->textures[Stage];
4717 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4719 #if 0 /* TODO: check so vertex textures */
4720 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4721 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4722 return WINED3D_OK;
4724 #endif
4726 /* Reject invalid texture units */
4727 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4728 WARN("Attempt to access invalid texture rejected\n");
4729 return WINED3DERR_INVALIDCALL;
4732 if(pTexture != NULL) {
4733 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4735 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4736 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4737 return WINED3DERR_INVALIDCALL;
4741 oldTexture = This->updateStateBlock->textures[Stage];
4742 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4743 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4745 This->updateStateBlock->set.textures[Stage] = TRUE;
4746 This->updateStateBlock->changed.textures[Stage] = TRUE;
4747 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4748 This->updateStateBlock->textures[Stage] = pTexture;
4750 /* Handle recording of state blocks */
4751 if (This->isRecordingState) {
4752 TRACE("Recording... not performing anything\n");
4753 return WINED3D_OK;
4756 /** NOTE: MSDN says that setTexture increases the reference count,
4757 * and the the application nust set the texture back to null (or have a leaky application),
4758 * This means we should pass the refcount up to the parent
4759 *******************************/
4760 if (NULL != This->updateStateBlock->textures[Stage]) {
4761 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4764 if (NULL != oldTexture) {
4765 IWineD3DBaseTexture_Release(oldTexture);
4768 /* Reset color keying */
4769 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
4770 BOOL enable_ckey = FALSE;
4772 if(pTexture) {
4773 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
4774 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
4777 if(enable_ckey) {
4778 glAlphaFunc(GL_NOTEQUAL, 0.0);
4779 checkGLcall("glAlphaFunc");
4783 return WINED3D_OK;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4790 /* Reject invalid texture units */
4791 if (Stage >= GL_LIMITS(sampler_stages)) {
4792 TRACE("Attempt to access invalid texture rejected\n");
4793 return WINED3DERR_INVALIDCALL;
4795 *ppTexture=This->stateBlock->textures[Stage];
4796 if (*ppTexture)
4797 IWineD3DBaseTexture_AddRef(*ppTexture);
4799 return WINED3D_OK;
4802 /*****
4803 * Get Back Buffer
4804 *****/
4805 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4806 IWineD3DSurface **ppBackBuffer) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 IWineD3DSwapChain *swapChain;
4809 HRESULT hr;
4811 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4813 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4814 if (hr == WINED3D_OK) {
4815 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4816 IWineD3DSwapChain_Release(swapChain);
4817 } else {
4818 *ppBackBuffer = NULL;
4820 return hr;
4823 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 WARN("(%p) : stub, calling idirect3d for now\n", This);
4826 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4829 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4831 IWineD3DSwapChain *swapChain;
4832 HRESULT hr;
4834 if(iSwapChain > 0) {
4835 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4836 if (hr == WINED3D_OK) {
4837 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4838 IWineD3DSwapChain_Release(swapChain);
4839 } else {
4840 FIXME("(%p) Error getting display mode\n", This);
4842 } else {
4843 /* Don't read the real display mode,
4844 but return the stored mode instead. X11 can't change the color
4845 depth, and some apps are pretty angry if they SetDisplayMode from
4846 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4848 Also don't relay to the swapchain because with ddraw it's possible
4849 that there isn't a swapchain at all */
4850 pMode->Width = This->ddraw_width;
4851 pMode->Height = This->ddraw_height;
4852 pMode->Format = This->ddraw_format;
4853 pMode->RefreshRate = 0;
4854 hr = WINED3D_OK;
4857 return hr;
4860 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p)->(%p)\n", This, hWnd);
4864 This->ddraw_window = hWnd;
4865 return WINED3D_OK;
4868 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4870 TRACE("(%p)->(%p)\n", This, hWnd);
4872 *hWnd = This->ddraw_window;
4873 return WINED3D_OK;
4876 /*****
4877 * Stateblock related functions
4878 *****/
4880 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 IWineD3DStateBlockImpl *object;
4883 HRESULT temp_result;
4885 TRACE("(%p)\n", This);
4887 if (This->isRecordingState) {
4888 return WINED3DERR_INVALIDCALL;
4891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4892 if (NULL == object ) {
4893 FIXME("(%p)Error allocating memory for stateblock\n", This);
4894 return E_OUTOFMEMORY;
4896 TRACE("(%p) created object %p\n", This, object);
4897 object->wineD3DDevice= This;
4898 /** FIXME: object->parent = parent; **/
4899 object->parent = NULL;
4900 object->blockType = WINED3DSBT_ALL;
4901 object->ref = 1;
4902 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4904 temp_result = allocate_shader_constants(object);
4905 if (WINED3D_OK != temp_result)
4906 return temp_result;
4908 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4909 This->updateStateBlock = object;
4910 This->isRecordingState = TRUE;
4912 TRACE("(%p) recording stateblock %p\n",This , object);
4913 return WINED3D_OK;
4916 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 if (!This->isRecordingState) {
4920 FIXME("(%p) not recording! returning error\n", This);
4921 *ppStateBlock = NULL;
4922 return WINED3DERR_INVALIDCALL;
4925 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4926 This->isRecordingState = FALSE;
4927 This->updateStateBlock = This->stateBlock;
4928 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4929 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4930 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4931 return WINED3D_OK;
4934 /*****
4935 * Scene related functions
4936 *****/
4937 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4938 /* At the moment we have no need for any functionality at the beginning
4939 of a scene */
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 TRACE("(%p) : stub\n", This);
4942 return WINED3D_OK;
4945 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 TRACE("(%p)\n", This);
4948 ENTER_GL();
4949 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4950 glFlush();
4951 checkGLcall("glFlush");
4953 TRACE("End Scene\n");
4954 /* If we're using FBOs this isn't needed */
4955 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
4957 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4958 IUnknown *targetContainer = NULL;
4959 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4960 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
4961 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
4962 /** always dirtify for now. we must find a better way to see that surface have been modified
4963 (Modifications should will only occur via draw-primitive, but we do need better locking
4964 switching to render-to-texture should remove the overhead though.
4966 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
4967 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
4968 IWineD3DSurface_PreLoad(This->renderTarget);
4969 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
4970 IUnknown_Release(targetContainer);
4973 This->sceneEnded = TRUE;
4974 LEAVE_GL();
4975 return WINED3D_OK;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4979 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4980 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 IWineD3DSwapChain *swapChain = NULL;
4983 int i;
4984 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4986 TRACE("(%p) Presenting the frame\n", This);
4988 for(i = 0 ; i < swapchains ; i ++) {
4990 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4991 TRACE("presentinng chain %d, %p\n", i, swapChain);
4992 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4993 IWineD3DSwapChain_Release(swapChain);
4996 return WINED3D_OK;
4999 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5000 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5003 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
5004 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
5005 when the depth-buffer format does not contain stencil buffer information, this method fails. */
5006 GLbitfield glMask = 0;
5007 GLboolean old_ztest;
5008 GLfloat old_z_clear_value;
5009 GLint old_stencil_clear_value;
5010 GLfloat old_color_clear_value[4];
5011 unsigned int i;
5012 CONST WINED3DRECT* curRect;
5014 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
5015 Count, pRects, Flags, Z, Stencil);
5017 ENTER_GL();
5019 glEnable(GL_SCISSOR_TEST);
5020 checkGLcall("glEnable GL_SCISSOR_TEST");
5022 if (Count > 0 && pRects) {
5023 curRect = pRects;
5024 } else {
5025 curRect = NULL;
5028 /* Only set the values up once, as they are not changing */
5029 if (Flags & WINED3DCLEAR_STENCIL) {
5030 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
5031 glClearStencil(Stencil);
5032 checkGLcall("glClearStencil");
5033 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5034 glStencilMask(0xFFFFFFFF);
5037 if (Flags & WINED3DCLEAR_ZBUFFER) {
5038 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
5039 glDepthMask(GL_TRUE);
5040 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
5041 glClearDepth(Z);
5042 checkGLcall("glClearDepth");
5043 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5046 if (Flags & WINED3DCLEAR_TARGET) {
5047 TRACE("Clearing screen with glClear to color %x\n", Color);
5048 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
5049 glClearColor(D3DCOLOR_R(Color),
5050 D3DCOLOR_G(Color),
5051 D3DCOLOR_B(Color),
5052 D3DCOLOR_A(Color));
5053 checkGLcall("glClearColor");
5055 /* Clear ALL colors! */
5056 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5057 glMask = glMask | GL_COLOR_BUFFER_BIT;
5060 /* Now process each rect in turn */
5061 for (i = 0; i < Count || i == 0; i++) {
5063 if (curRect) {
5064 /* Note gl uses lower left, width/height */
5065 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
5066 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
5067 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5068 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5069 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
5070 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
5071 checkGLcall("glScissor");
5072 } else {
5073 glScissor(This->stateBlock->viewport.X,
5074 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
5075 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
5076 This->stateBlock->viewport.Width,
5077 This->stateBlock->viewport.Height);
5078 checkGLcall("glScissor");
5081 /* Clear the selected rectangle (or full screen) */
5082 glClear(glMask);
5083 checkGLcall("glClear");
5085 /* Step to the next rectangle */
5086 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
5089 /* Restore the old values (why..?) */
5090 if (Flags & WINED3DCLEAR_STENCIL) {
5091 glClearStencil(old_stencil_clear_value);
5092 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5094 if (Flags & WINED3DCLEAR_ZBUFFER) {
5095 glDepthMask(old_ztest);
5096 glClearDepth(old_z_clear_value);
5098 if (Flags & WINED3DCLEAR_TARGET) {
5099 glClearColor(old_color_clear_value[0],
5100 old_color_clear_value[1],
5101 old_color_clear_value[2],
5102 old_color_clear_value[3]);
5103 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5104 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5105 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5106 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5109 glDisable(GL_SCISSOR_TEST);
5110 checkGLcall("glDisable");
5111 LEAVE_GL();
5113 return WINED3D_OK;
5116 /*****
5117 * Drawing functions
5118 *****/
5119 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5120 UINT PrimitiveCount) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5123 This->stateBlock->streamIsUP = FALSE;
5125 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5126 debug_d3dprimitivetype(PrimitiveType),
5127 StartVertex, PrimitiveCount);
5128 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5129 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
5132 return WINED3D_OK;
5135 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5136 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5137 WINED3DPRIMITIVETYPE PrimitiveType,
5138 INT baseVIndex, UINT minIndex,
5139 UINT NumVertices, UINT startIndex, UINT primCount) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 UINT idxStride = 2;
5143 IWineD3DIndexBuffer *pIB;
5144 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5146 pIB = This->stateBlock->pIndexData;
5147 This->stateBlock->streamIsUP = FALSE;
5149 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
5150 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5151 minIndex, NumVertices, startIndex, baseVIndex, primCount);
5153 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5154 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5155 idxStride = 2;
5156 } else {
5157 idxStride = 4;
5160 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
5161 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
5163 return WINED3D_OK;
5166 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5167 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5168 UINT VertexStreamZeroStride) {
5169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5171 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5172 debug_d3dprimitivetype(PrimitiveType),
5173 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5175 /* release the stream source */
5176 if (This->stateBlock->streamSource[0] != NULL) {
5177 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5180 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5181 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5182 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5183 This->stateBlock->streamIsUP = TRUE;
5185 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5186 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
5188 /* MSDN specifies stream zero settings must be set to NULL */
5189 This->stateBlock->streamStride[0] = 0;
5190 This->stateBlock->streamSource[0] = NULL;
5192 /*stream zero settings set to null at end, as per the msdn */
5193 return WINED3D_OK;
5196 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5197 UINT MinVertexIndex, UINT NumVertices,
5198 UINT PrimitiveCount, CONST void* pIndexData,
5199 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5200 UINT VertexStreamZeroStride) {
5201 int idxStride;
5202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5204 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5205 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5206 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5207 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5209 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5210 idxStride = 2;
5211 } else {
5212 idxStride = 4;
5215 /* release the stream and index data */
5216 if (This->stateBlock->streamSource[0] != NULL) {
5217 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5219 if (This->stateBlock->pIndexData) {
5220 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
5223 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5224 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5225 This->stateBlock->streamIsUP = TRUE;
5226 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5228 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
5230 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5231 This->stateBlock->streamSource[0] = NULL;
5232 This->stateBlock->streamStride[0] = 0;
5233 This->stateBlock->pIndexData = NULL;
5235 return WINED3D_OK;
5238 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5240 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
5241 return WINED3D_OK;
5243 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5244 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246 HRESULT hr = WINED3D_OK;
5247 WINED3DRESOURCETYPE sourceType;
5248 WINED3DRESOURCETYPE destinationType;
5249 int i ,levels;
5251 /* TODO: think about moving the code into IWineD3DBaseTexture */
5253 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5255 /* verify that the source and destination textures aren't NULL */
5256 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5257 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5258 This, pSourceTexture, pDestinationTexture);
5259 hr = WINED3DERR_INVALIDCALL;
5262 if (pSourceTexture == pDestinationTexture) {
5263 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5264 This, pSourceTexture, pDestinationTexture);
5265 hr = WINED3DERR_INVALIDCALL;
5267 /* Verify that the source and destination textures are the same type */
5268 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5269 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5271 if (sourceType != destinationType) {
5272 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5273 This);
5274 hr = WINED3DERR_INVALIDCALL;
5277 /* check that both textures have the identical numbers of levels */
5278 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5279 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5280 hr = WINED3DERR_INVALIDCALL;
5283 if (WINED3D_OK == hr) {
5285 /* Make sure that the destination texture is loaded */
5286 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5288 /* Update every surface level of the texture */
5289 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5291 switch (sourceType) {
5292 case WINED3DRTYPE_TEXTURE:
5294 IWineD3DSurface *srcSurface;
5295 IWineD3DSurface *destSurface;
5297 for (i = 0 ; i < levels ; ++i) {
5298 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5299 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5300 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5301 IWineD3DSurface_Release(srcSurface);
5302 IWineD3DSurface_Release(destSurface);
5303 if (WINED3D_OK != hr) {
5304 WARN("(%p) : Call to update surface failed\n", This);
5305 return hr;
5309 break;
5310 case WINED3DRTYPE_CUBETEXTURE:
5312 IWineD3DSurface *srcSurface;
5313 IWineD3DSurface *destSurface;
5314 WINED3DCUBEMAP_FACES faceType;
5316 for (i = 0 ; i < levels ; ++i) {
5317 /* Update each cube face */
5318 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5319 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5320 if (WINED3D_OK != hr) {
5321 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5322 } else {
5323 TRACE("Got srcSurface %p\n", srcSurface);
5325 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5326 if (WINED3D_OK != hr) {
5327 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5328 } else {
5329 TRACE("Got desrSurface %p\n", destSurface);
5331 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5332 IWineD3DSurface_Release(srcSurface);
5333 IWineD3DSurface_Release(destSurface);
5334 if (WINED3D_OK != hr) {
5335 WARN("(%p) : Call to update surface failed\n", This);
5336 return hr;
5341 break;
5342 #if 0 /* TODO: Add support for volume textures */
5343 case WINED3DRTYPE_VOLUMETEXTURE:
5345 IWineD3DVolume srcVolume = NULL;
5346 IWineD3DSurface destVolume = NULL;
5348 for (i = 0 ; i < levels ; ++i) {
5349 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5350 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5351 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5352 IWineD3DVolume_Release(srcSurface);
5353 IWineD3DVolume_Release(destSurface);
5354 if (WINED3D_OK != hr) {
5355 WARN("(%p) : Call to update volume failed\n", This);
5356 return hr;
5360 break;
5361 #endif
5362 default:
5363 FIXME("(%p) : Unsupported source and destination type\n", This);
5364 hr = WINED3DERR_INVALIDCALL;
5368 return hr;
5371 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5372 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5373 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 TRACE("(%p) : stub\n", This);
5377 return WINED3D_OK;
5379 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5382 * NOTE It may be best to move the code into surface to occomplish this
5383 ****************************************/
5385 WINED3DSURFACE_DESC surfaceDesc;
5386 unsigned int surfaceWidth, surfaceHeight;
5387 glDescriptor *targetGlDescription = NULL;
5388 glDescriptor *surfaceGlDescription = NULL;
5389 IWineD3DSwapChainImpl *container = NULL;
5391 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5392 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5393 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5395 surfaceDesc.Width = &surfaceWidth;
5396 surfaceDesc.Height = &surfaceHeight;
5397 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5398 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5400 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5401 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5402 ENTER_GL();
5403 /* TODO: opengl Context switching for swapchains etc... */
5404 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
5405 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
5406 glReadBuffer(GL_BACK);
5407 vcheckGLcall("glReadBuffer(GL_BACK)");
5408 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
5409 glReadBuffer(GL_FRONT);
5410 vcheckGLcall("glReadBuffer(GL_FRONT)");
5411 } else if (pRenderTarget == This->depthStencilBuffer) {
5412 FIXME("Reading of depthstencil not yet supported\n");
5415 glReadPixels(0,
5417 surfaceWidth,
5418 surfaceHeight,
5419 surfaceGlDescription->glFormat,
5420 surfaceGlDescription->glType,
5421 (void *)IWineD3DSurface_GetData(pSurface));
5422 vcheckGLcall("glReadPixels(...)");
5423 if(NULL != container ){
5424 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5426 } else {
5427 IWineD3DBaseTexture *container;
5428 GLenum textureDimensions = GL_TEXTURE_2D;
5430 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5431 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5432 IWineD3DBaseTexture_Release(container);
5434 /* TODO: 2D -> Cube surface coppies etc.. */
5435 if (surfaceGlDescription->target != textureDimensions) {
5436 FIXME("(%p) : Texture dimension mismatch\n", This);
5438 glEnable(textureDimensions);
5439 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5440 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5441 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5442 vcheckGLcall("glBindTexture");
5443 glGetTexImage(surfaceGlDescription->target,
5444 surfaceGlDescription->level,
5445 surfaceGlDescription->glFormat,
5446 surfaceGlDescription->glType,
5447 (void *)IWineD3DSurface_GetData(pSurface));
5448 glDisable(textureDimensions);
5449 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5452 LEAVE_GL();
5453 return WINED3D_OK;
5456 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5457 IWineD3DSwapChain *swapChain;
5458 HRESULT hr;
5459 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5460 if(hr == WINED3D_OK) {
5461 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5462 IWineD3DSwapChain_Release(swapChain);
5464 return hr;
5467 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5469 /* return a sensible default */
5470 *pNumPasses = 1;
5471 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5472 FIXME("(%p) : stub\n", This);
5473 return WINED3D_OK;
5476 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5478 int j;
5479 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5480 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5481 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5482 return WINED3DERR_INVALIDCALL;
5484 for (j = 0; j < 256; ++j) {
5485 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5486 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5487 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5488 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5490 TRACE("(%p) : returning\n", This);
5491 return WINED3D_OK;
5494 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5496 int j;
5497 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5498 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5499 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5500 return WINED3DERR_INVALIDCALL;
5502 for (j = 0; j < 256; ++j) {
5503 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5504 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5505 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5506 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5508 TRACE("(%p) : returning\n", This);
5509 return WINED3D_OK;
5512 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5514 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5515 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5516 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5517 return WINED3DERR_INVALIDCALL;
5519 /*TODO: stateblocks */
5520 This->currentPalette = PaletteNumber;
5521 TRACE("(%p) : returning\n", This);
5522 return WINED3D_OK;
5525 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5527 if (PaletteNumber == NULL) {
5528 WARN("(%p) : returning Invalid Call\n", This);
5529 return WINED3DERR_INVALIDCALL;
5531 /*TODO: stateblocks */
5532 *PaletteNumber = This->currentPalette;
5533 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5534 return WINED3D_OK;
5537 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5539 static BOOL showFixmes = TRUE;
5540 if (showFixmes) {
5541 FIXME("(%p) : stub\n", This);
5542 showFixmes = FALSE;
5545 This->softwareVertexProcessing = bSoftware;
5546 return WINED3D_OK;
5550 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5552 static BOOL showFixmes = TRUE;
5553 if (showFixmes) {
5554 FIXME("(%p) : stub\n", This);
5555 showFixmes = FALSE;
5557 return This->softwareVertexProcessing;
5561 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 IWineD3DSwapChain *swapChain;
5564 HRESULT hr;
5566 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5568 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5569 if(hr == WINED3D_OK){
5570 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5571 IWineD3DSwapChain_Release(swapChain);
5572 }else{
5573 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5575 return hr;
5579 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5581 static BOOL showfixmes = TRUE;
5582 if(nSegments != 0.0f) {
5583 if( showfixmes) {
5584 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5585 showfixmes = FALSE;
5588 return WINED3D_OK;
5591 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 static BOOL showfixmes = TRUE;
5594 if( showfixmes) {
5595 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5596 showfixmes = FALSE;
5598 return 0.0f;
5601 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5603 /** TODO: remove casts to IWineD3DSurfaceImpl
5604 * NOTE: move code to surface to accomplish this
5605 ****************************************/
5606 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5607 int srcWidth, srcHeight;
5608 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5609 WINED3DFORMAT destFormat, srcFormat;
5610 UINT destSize;
5611 int destLeft, destTop;
5612 WINED3DPOOL srcPool, destPool;
5613 int offset = 0;
5614 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5615 glDescriptor *glDescription = NULL;
5616 GLenum textureDimensions = GL_TEXTURE_2D;
5617 IWineD3DBaseTexture *baseTexture;
5619 WINED3DSURFACE_DESC winedesc;
5621 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5622 memset(&winedesc, 0, sizeof(winedesc));
5623 winedesc.Width = &srcSurfaceWidth;
5624 winedesc.Height = &srcSurfaceHeight;
5625 winedesc.Pool = &srcPool;
5626 winedesc.Format = &srcFormat;
5628 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5630 winedesc.Width = &destSurfaceWidth;
5631 winedesc.Height = &destSurfaceHeight;
5632 winedesc.Pool = &destPool;
5633 winedesc.Format = &destFormat;
5634 winedesc.Size = &destSize;
5636 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5638 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5639 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5640 return WINED3DERR_INVALIDCALL;
5643 if (destFormat == WINED3DFMT_UNKNOWN) {
5644 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5645 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5647 /* Get the update surface description */
5648 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5651 /* Make sure the surface is loaded and up to date */
5652 IWineD3DSurface_PreLoad(pDestinationSurface);
5654 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5656 ENTER_GL();
5658 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5659 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5660 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5661 destLeft = pDestPoint ? pDestPoint->x : 0;
5662 destTop = pDestPoint ? pDestPoint->y : 0;
5665 /* This function doesn't support compressed textures
5666 the pitch is just bytesPerPixel * width */
5667 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5668 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5669 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5670 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5672 /* TODO DXT formats */
5674 if(pSourceRect != NULL && pSourceRect->top != 0){
5675 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5677 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5678 ,This
5679 ,glDescription->level
5680 ,destLeft
5681 ,destTop
5682 ,srcWidth
5683 ,srcHeight
5684 ,glDescription->glFormat
5685 ,glDescription->glType
5686 ,IWineD3DSurface_GetData(pSourceSurface)
5689 /* Sanity check */
5690 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5692 /* need to lock the surface to get the data */
5693 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5696 /* TODO: Cube and volume support */
5697 if(rowoffset != 0){
5698 /* not a whole row so we have to do it a line at a time */
5699 int j;
5701 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5702 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5704 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5706 glTexSubImage2D(glDescription->target
5707 ,glDescription->level
5708 ,destLeft
5710 ,srcWidth
5712 ,glDescription->glFormat
5713 ,glDescription->glType
5714 ,data /* could be quicker using */
5716 data += rowoffset;
5719 } else { /* Full width, so just write out the whole texture */
5721 if (WINED3DFMT_DXT1 == destFormat ||
5722 WINED3DFMT_DXT2 == destFormat ||
5723 WINED3DFMT_DXT3 == destFormat ||
5724 WINED3DFMT_DXT4 == destFormat ||
5725 WINED3DFMT_DXT5 == destFormat) {
5726 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5727 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5728 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5729 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5730 } if (destFormat != srcFormat) {
5731 FIXME("Updating mixed format compressed texture is not curretly support\n");
5732 } else {
5733 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5734 glDescription->level,
5735 glDescription->glFormatInternal,
5736 srcWidth,
5737 srcHeight,
5739 destSize,
5740 IWineD3DSurface_GetData(pSourceSurface));
5742 } else {
5743 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5747 } else {
5748 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5750 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5751 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5752 data returned by GetData non-power2 width/height with hardware non-power2
5753 pow2Width/height are set to surface width height, repacking isn't needed so it
5754 doesn't matter which function gets called. */
5755 glTexSubImage2D(glDescription->target
5756 ,glDescription->level
5757 ,destLeft
5758 ,destTop
5759 ,srcWidth
5760 ,srcHeight
5761 ,glDescription->glFormat
5762 ,glDescription->glType
5763 ,IWineD3DSurface_GetData(pSourceSurface)
5765 } else {
5767 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5768 glTexSubImage2D(glDescription->target
5769 ,glDescription->level
5770 ,destLeft
5771 ,destTop
5772 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5773 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5774 ,glDescription->glFormat
5775 ,glDescription->glType
5776 ,IWineD3DSurface_GetData(pSourceSurface)
5782 checkGLcall("glTexSubImage2D");
5783 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5785 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5786 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5787 * surface bigger than it needs to be hmm.. */
5788 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5789 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5790 IWineD3DBaseTexture_Release(baseTexture);
5793 glDisable(textureDimensions); /* This needs to be managed better.... */
5794 LEAVE_GL();
5796 return WINED3D_OK;
5799 /* Implementation details at http://developer.nvidia.com/attach/6494
5801 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5802 hmm.. no longer supported use
5803 OpenGL evaluators or tessellate surfaces within your application.
5806 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5807 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5809 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5810 FIXME("(%p) : Stub\n", This);
5811 return WINED3D_OK;
5815 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5816 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5818 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5819 FIXME("(%p) : Stub\n", This);
5820 return WINED3D_OK;
5823 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5825 TRACE("(%p) Handle(%d)\n", This, Handle);
5826 FIXME("(%p) : Stub\n", This);
5827 return WINED3D_OK;
5830 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5832 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5833 DDBLTFX BltFx;
5834 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5836 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5837 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5838 return WINED3DERR_INVALIDCALL;
5841 /* Just forward this to the DirectDraw blitting engine */
5842 memset(&BltFx, 0, sizeof(BltFx));
5843 BltFx.dwSize = sizeof(BltFx);
5844 BltFx.u5.dwFillColor = color;
5845 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5848 /* rendertarget and deptth stencil functions */
5849 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5852 /* FIXME: Implelent RenderTargetIndex >0 */
5853 if(RenderTargetIndex > 0)
5854 FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
5856 *ppRenderTarget = This->renderTarget;
5857 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5858 /* Note inc ref on returned surface */
5859 if(*ppRenderTarget != NULL)
5860 IWineD3DSurface_AddRef(*ppRenderTarget);
5861 return WINED3D_OK;
5864 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5866 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5867 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5868 IWineD3DSwapChainImpl *Swapchain;
5869 HRESULT hr;
5871 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5873 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5874 if(hr != WINED3D_OK) {
5875 ERR("Can't get the swapchain\n");
5876 return hr;
5879 /* Make sure to release the swapchain */
5880 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5882 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5883 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5884 return WINED3DERR_INVALIDCALL;
5886 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5887 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5888 return WINED3DERR_INVALIDCALL;
5891 if(Swapchain->frontBuffer != Front) {
5892 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5894 if(Swapchain->frontBuffer)
5895 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5896 Swapchain->frontBuffer = Front;
5898 if(Swapchain->frontBuffer) {
5899 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5903 if(Back && !Swapchain->backBuffer) {
5904 /* We need memory for the back buffer array - only one back buffer this way */
5905 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5906 if(!Swapchain->backBuffer) {
5907 ERR("Out of memory\n");
5908 return E_OUTOFMEMORY;
5912 if(Swapchain->backBuffer[0] != Back) {
5913 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5914 ENTER_GL();
5915 if(!Swapchain->backBuffer[0]) {
5916 /* GL was told to draw to the front buffer at creation,
5917 * undo that
5919 glDrawBuffer(GL_BACK);
5920 checkGLcall("glDrawBuffer(GL_BACK)");
5921 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5922 Swapchain->presentParms.BackBufferCount = 1;
5923 } else if (!Back) {
5924 /* That makes problems - disable for now */
5925 /* glDrawBuffer(GL_FRONT); */
5926 checkGLcall("glDrawBuffer(GL_FRONT)");
5927 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5928 Swapchain->presentParms.BackBufferCount = 0;
5930 LEAVE_GL();
5932 if(Swapchain->backBuffer[0])
5933 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5934 Swapchain->backBuffer[0] = Back;
5936 if(Swapchain->backBuffer[0]) {
5937 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5938 } else {
5939 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5944 return WINED3D_OK;
5947 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5949 *ppZStencilSurface = This->depthStencilBuffer;
5950 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5952 if(*ppZStencilSurface != NULL) {
5953 /* Note inc ref on returned surface */
5954 IWineD3DSurface_AddRef(*ppZStencilSurface);
5956 return WINED3D_OK;
5959 static void bind_fbo(IWineD3DDevice *iface) {
5960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5962 if (!This->fbo) {
5963 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5964 checkGLcall("glGenFramebuffersEXT()");
5966 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5967 checkGLcall("glBindFramebuffer()");
5970 /* TODO: Handle stencil attachments */
5971 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5973 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5975 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5977 bind_fbo(iface);
5979 if (depth_stencil_impl) {
5980 GLenum texttarget, target;
5982 IWineD3DSurface_PreLoad(depth_stencil);
5983 texttarget = depth_stencil_impl->glDescription.target;
5984 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5986 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5987 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5988 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5989 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5990 glBindTexture(target, 0);
5992 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5993 checkGLcall("glFramebufferTexture2DEXT()");
5994 } else {
5995 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5996 checkGLcall("glFramebufferTexture2DEXT()");
5999 if (!This->render_offscreen) {
6000 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6001 checkGLcall("glBindFramebuffer()");
6005 static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
6006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6007 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6009 if (This->render_offscreen) {
6010 GLenum texttarget, target;
6012 bind_fbo(iface);
6014 IWineD3DSurface_PreLoad(render_target);
6015 texttarget = rtimpl->glDescription.target;
6016 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6018 glBindTexture(target, rtimpl->glDescription.textureName);
6019 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
6020 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
6021 glBindTexture(target, 0);
6023 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texttarget, rtimpl->glDescription.textureName, 0));
6024 checkGLcall("glFramebufferTexture2DEXT()");
6025 } else {
6026 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6027 checkGLcall("glBindFramebuffer()");
6031 /* internal static helper functions */
6032 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6033 IWineD3DSurface *RenderSurface);
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 HRESULT hr = WINED3D_OK;
6038 WINED3DVIEWPORT viewport;
6040 TRACE("(%p) Swapping rendertarget\n",This);
6041 if (RenderTargetIndex > 0) {
6042 FIXME("(%p) Render targets other than the first are not supported\n",This);
6043 RenderTargetIndex = 0;
6046 /* MSDN says that null disables the render target
6047 but a device must always be associated with a render target
6048 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6050 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6051 for more details
6053 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6054 FIXME("Trying to set render target 0 to NULL\n");
6055 return WINED3DERR_INVALIDCALL;
6057 /* TODO: replace Impl* usage with interface usage */
6058 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6059 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);
6060 return WINED3DERR_INVALIDCALL;
6062 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
6063 * builds, but I think wine counts as a 'debug' build for now.
6064 ******************************/
6065 /* If we are trying to set what we already have, don't bother */
6066 if (pRenderTarget == This->renderTarget) {
6067 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6068 } else {
6069 /* Otherwise, set the render target up */
6071 if (!This->sceneEnded) {
6072 IWineD3DDevice_EndScene(iface);
6074 TRACE("clearing renderer\n");
6075 /* IWineD3DDeviceImpl_CleanRender(iface); */
6076 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6077 depending on the renter target implementation being used.
6078 A shared context implementation will share all buffers between all rendertargets (including swapchains),
6079 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6080 stencil buffer and incure an extra memory overhead */
6081 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
6082 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6083 set_render_target_fbo(iface, pRenderTarget);
6087 if (SUCCEEDED(hr)) {
6088 /* Finally, reset the viewport as the MSDN states. */
6089 /* TODO: Replace impl usage */
6090 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
6091 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
6092 viewport.X = 0;
6093 viewport.Y = 0;
6094 viewport.MaxZ = 1.0f;
6095 viewport.MinZ = 0.0f;
6096 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6097 } else {
6098 FIXME("Unknown error setting the render target\n");
6100 This->sceneEnded = FALSE;
6101 return hr;
6104 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6106 HRESULT hr = WINED3D_OK;
6107 IWineD3DSurface *tmp;
6109 TRACE("(%p) Swapping z-buffer\n",This);
6111 if (pNewZStencil == This->stencilBufferTarget) {
6112 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6113 } else {
6114 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6115 * depending on the renter target implementation being used.
6116 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6117 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6118 * stencil buffer and incure an extra memory overhead
6119 ******************************************************/
6122 tmp = This->stencilBufferTarget;
6123 This->stencilBufferTarget = pNewZStencil;
6124 /* should we be calling the parent or the wined3d surface? */
6125 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6126 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6127 hr = WINED3D_OK;
6128 /** TODO: glEnable/glDisable on depth/stencil depending on
6129 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
6130 **********************************************************/
6131 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6132 set_depth_stencil_fbo(iface, pNewZStencil);
6136 return hr;
6140 #ifdef GL_VERSION_1_3
6141 /* Internal functions not in DirectX */
6142 /** TODO: move this off to the opengl context manager
6143 *(the swapchain doesn't need to know anything about offscreen rendering!)
6144 ****************************************************/
6146 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
6148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6150 TRACE("(%p), %p\n", This, swapchain);
6152 if (swapchain->win != swapchain->drawable) {
6153 /* Set everything back the way it ws */
6154 swapchain->render_ctx = swapchain->glCtx;
6155 swapchain->drawable = swapchain->win;
6157 return WINED3D_OK;
6160 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
6161 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
6162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6163 int i;
6164 unsigned int width;
6165 unsigned int height;
6166 WINED3DFORMAT format;
6167 WINED3DSURFACE_DESC surfaceDesc;
6168 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6169 surfaceDesc.Width = &width;
6170 surfaceDesc.Height = &height;
6171 surfaceDesc.Format = &format;
6172 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6173 *context = NULL;
6174 /* I need a get width/height function (and should do something with the format) */
6175 for (i = 0; i < CONTEXT_CACHE; ++i) {
6176 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
6177 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
6178 the pSurface can be set to 0 allowing it to be reused from cache **/
6179 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
6180 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
6181 *context = &This->contextCache[i];
6182 break;
6184 if (This->contextCache[i].Width == 0) {
6185 This->contextCache[i].pSurface = pSurface;
6186 This->contextCache[i].Width = width;
6187 This->contextCache[i].Height = height;
6188 *context = &This->contextCache[i];
6189 break;
6192 if (i == CONTEXT_CACHE) {
6193 int minUsage = 0x7FFFFFFF; /* MAX_INT */
6194 glContext *dropContext = 0;
6195 for (i = 0; i < CONTEXT_CACHE; i++) {
6196 if (This->contextCache[i].usedcount < minUsage) {
6197 dropContext = &This->contextCache[i];
6198 minUsage = This->contextCache[i].usedcount;
6201 /* clean up the context (this doesn't work for ATI at the moment */
6202 #if 0
6203 glXDestroyContext(swapchain->display, dropContext->context);
6204 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
6205 #endif
6206 FIXME("Leak\n");
6207 dropContext->Width = 0;
6208 dropContext->pSurface = pSurface;
6209 *context = dropContext;
6210 } else {
6211 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
6212 for (i = 0; i < CONTEXT_CACHE; i++) {
6213 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
6217 if (*context != NULL)
6218 return WINED3D_OK;
6219 else
6220 return E_OUTOFMEMORY;
6222 #endif
6224 /* Reapply the device stateblock */
6225 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
6227 BOOL oldRecording;
6228 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6230 /* Disable recording */
6231 oldUpdateStateBlock = This->updateStateBlock;
6232 oldRecording= This->isRecordingState;
6233 This->isRecordingState = FALSE;
6234 This->updateStateBlock = This->stateBlock;
6236 /* Reapply the state block */
6237 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
6239 /* Restore recording */
6240 This->isRecordingState = oldRecording;
6241 This->updateStateBlock = oldUpdateStateBlock;
6244 /* Set offscreen rendering. When rendering offscreen the surface will be
6245 * rendered upside down to compensate for the fact that D3D texture coordinates
6246 * are flipped compared to GL texture coordinates. The cullmode is affected by
6247 * this, so it must be updated. To update the cullmode stateblock recording has
6248 * to be temporarily disabled. The new state management code will hopefully
6249 * make this unnecessary */
6250 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
6252 DWORD cullMode;
6253 BOOL oldRecording;
6254 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6256 /* Nothing to update, return. */
6257 if (This->render_offscreen == isTexture) return;
6259 /* Disable recording */
6260 oldUpdateStateBlock = This->updateStateBlock;
6261 oldRecording= This->isRecordingState;
6262 This->isRecordingState = FALSE;
6263 This->updateStateBlock = This->stateBlock;
6265 This->render_offscreen = isTexture;
6266 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
6267 This->depth_copy_state = WINED3D_DCS_COPY;
6269 This->last_was_rhw = FALSE;
6270 This->proj_valid = FALSE;
6271 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
6272 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
6274 /* Restore recording */
6275 This->isRecordingState = oldRecording;
6276 This->updateStateBlock = oldUpdateStateBlock;
6279 /* Returns an array of compatible FBconfig(s).
6280 * The array must be freed with XFree. Requires ENTER_GL() */
6282 static GLXFBConfig* device_find_fbconfigs(
6283 IWineD3DDeviceImpl* This,
6284 IWineD3DSwapChainImpl* implicitSwapchainImpl,
6285 IWineD3DSurface* RenderSurface) {
6287 GLXFBConfig* cfgs = NULL;
6288 int nCfgs = 0;
6289 int attribs[256];
6290 int nAttribs = 0;
6292 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
6293 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
6294 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
6296 /**TODO:
6297 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
6298 it StencilSurface != NULL && zBufferTarget == NULL switch it on
6301 #define PUSH1(att) attribs[nAttribs++] = (att);
6302 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
6304 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
6306 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
6307 PUSH2(GLX_X_RENDERABLE, TRUE);
6308 PUSH2(GLX_DOUBLEBUFFER, TRUE);
6309 TRACE("calling makeglcfg\n");
6310 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
6311 PUSH1(None);
6312 TRACE("calling chooseFGConfig\n");
6313 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6314 DefaultScreen(implicitSwapchainImpl->display),
6315 attribs, &nCfgs);
6316 if (cfgs == NULL) {
6317 /* OK we didn't find the exact config, so use any reasonable match */
6318 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
6319 why we failed. */
6320 static BOOL show_message = TRUE;
6321 if (show_message) {
6322 ERR("Failed to find exact match, finding alternative but you may "
6323 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
6324 show_message = FALSE;
6326 nAttribs = 0;
6327 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6328 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
6329 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6330 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6331 TRACE("calling makeglcfg\n");
6332 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6333 PUSH1(None);
6334 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6335 DefaultScreen(implicitSwapchainImpl->display),
6336 attribs, &nCfgs);
6339 if (cfgs == NULL) {
6340 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6341 BackBufferFormat, debug_d3dformat(BackBufferFormat),
6342 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6343 } else {
6344 #ifdef EXTRA_TRACES
6345 int i;
6346 for (i = 0; i < nCfgs; ++i) {
6347 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6348 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6349 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6351 if (NULL != This->renderTarget) {
6352 glFlush();
6353 vcheckGLcall("glFlush");
6354 /** This is only useful if the old render target was a swapchain,
6355 * we need to supercede this with a function that displays
6356 * the current buffer on the screen. This is easy to do in glx1.3 but
6357 * we need to do copy-write pixels in glx 1.2.
6358 ************************************************/
6359 glXSwapBuffers(implicitSwapChainImpl->display,
6360 implicitSwapChainImpl->drawable);
6361 printf("Hit Enter to get next frame ...\n");
6362 getchar();
6364 #endif
6366 #undef PUSH1
6367 #undef PUSH2
6369 return cfgs;
6372 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6373 * the functionality needs splitting up so that we don't do more than we should do.
6374 * this only seems to impact performance a little.
6375 ******************************/
6376 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6377 IWineD3DSurface *RenderSurface) {
6380 * Currently only active for GLX >= 1.3
6381 * for others versions we'll have to use GLXPixmaps
6383 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6384 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6385 * so only check OpenGL version
6386 * ..........................
6387 * I don't believe that it is a problem with NVidia headers,
6388 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6389 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6390 * ATI Note:
6391 * Your application will report GLX version 1.2 on glXQueryVersion.
6392 * However, it is safe to call the GLX 1.3 functions as described below.
6394 #if defined(GL_VERSION_1_3)
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6397 GLXFBConfig* cfgs = NULL;
6398 IWineD3DSwapChain *currentSwapchain;
6399 IWineD3DSwapChainImpl *currentSwapchainImpl;
6400 IWineD3DSwapChain *implicitSwapchain;
6401 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6402 IWineD3DSwapChain *renderSurfaceSwapchain;
6403 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6405 /* Obtain a reference to the device implicit swapchain,
6406 * the swapchain of the current render target,
6407 * and the swapchain of the new render target.
6408 * Fallback to device implicit swapchain if the current render target doesn't have one */
6409 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6410 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6411 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
6412 if (currentSwapchain == NULL)
6413 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
6415 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6416 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6417 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6419 ENTER_GL();
6422 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6423 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6424 **********************************************************************/
6425 if (renderSurfaceSwapchain != NULL) {
6427 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6428 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6429 TRACE("making swapchain active\n");
6430 if (RenderSurface != This->renderTarget) {
6431 BOOL backbuf = FALSE;
6432 int i;
6434 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6435 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6436 backbuf = TRUE;
6437 break;
6441 if (backbuf) {
6442 } else {
6443 /* This could be flagged so that some operations work directly with the front buffer */
6444 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6446 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6447 renderSurfaceSwapchainImpl->win,
6448 renderSurfaceSwapchainImpl->glCtx) == False) {
6450 TRACE("Error in setting current context: context %p drawable %ld !\n",
6451 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6453 checkGLcall("glXMakeContextCurrent");
6455 /* Clean up the old context */
6456 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6458 /* Reapply the stateblock, and set the device not to render to texture */
6459 device_reapply_stateblock(This);
6460 device_render_to_texture(This, FALSE);
6463 /* Offscreen rendering: PBuffers (currently disabled).
6464 * Also note that this path is never reached if FBOs are supported */
6465 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6466 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6468 /** ********************************************************************
6469 * This is a quickly hacked out implementation of offscreen textures.
6470 * It will work in most cases but there may be problems if the client
6471 * modifies the texture directly, or expects the contents of the rendertarget
6472 * to be persistent.
6474 * There are some real speed vs compatibility issues here:
6475 * we should really use a new context for every texture, but that eats ram.
6476 * we should also be restoring the texture to the pbuffer but that eats CPU
6477 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6478 * but if this means reusing the display backbuffer then we need to make sure that
6479 * states are correctly preserved.
6480 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6481 * and gain a good performance increase at the cost of compatibility.
6482 * I would suggest that, when this is the case, a user configurable flag be made
6483 * available, allowing the user to choose the best emulated experience for them.
6484 *********************************************************************/
6486 XVisualInfo *visinfo;
6487 glContext *newContext;
6489 /* Here were using a shared context model */
6490 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6491 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6494 /* If the context doesn't exist then create a new one */
6495 /* TODO: This should really be part of findGlContext */
6496 if (NULL == newContext->context) {
6498 int attribs[256];
6499 int nAttribs = 0;
6501 TRACE("making new buffer\n");
6502 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6503 attribs[nAttribs++] = newContext->Width;
6504 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6505 attribs[nAttribs++] = newContext->Height;
6506 attribs[nAttribs++] = None;
6508 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6510 /** ****************************************
6511 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6512 *they note:
6513 * In future releases, we may provide the calls glXCreateNewContext,
6514 * glXQueryDrawable and glXMakeContextCurrent.
6515 * so until then we have to use glXGetVisualFromFBConfig &co..
6516 ********************************************/
6518 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6519 if (!visinfo) {
6520 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6521 } else {
6522 newContext->context = glXCreateContext(
6523 implicitSwapchainImpl->display, visinfo,
6524 implicitSwapchainImpl->glCtx, GL_TRUE);
6526 XFree(visinfo);
6529 if (NULL == newContext || NULL == newContext->context) {
6530 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6531 } else {
6532 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6533 if (glXMakeCurrent(implicitSwapchainImpl->display,
6534 newContext->drawable, newContext->context) == False) {
6536 TRACE("Error in setting current context: context %p drawable %ld\n",
6537 newContext->context, newContext->drawable);
6539 checkGLcall("glXMakeContextCurrent");
6541 /* Clean up the old context */
6542 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6544 /* Reapply stateblock, and set device to render to a texture */
6545 device_reapply_stateblock(This);
6546 device_render_to_texture(This, TRUE);
6548 /* Set the current context of the swapchain to the new context */
6549 implicitSwapchainImpl->drawable = newContext->drawable;
6550 implicitSwapchainImpl->render_ctx = newContext->context;
6552 } else {
6553 /* Same context, but update render_offscreen and cull mode */
6554 device_render_to_texture(This, TRUE);
6557 /* Replace the render target */
6558 if (This->renderTarget != RenderSurface) {
6559 IWineD3DSurface_Release(This->renderTarget);
6560 This->renderTarget = RenderSurface;
6561 IWineD3DSurface_AddRef(RenderSurface);
6564 if (cfgs != NULL) XFree(cfgs);
6565 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6566 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6567 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6568 LEAVE_GL();
6569 #endif
6570 return WINED3D_OK;
6573 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6574 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6576 /* TODO: the use of Impl is deprecated. */
6577 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6579 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6581 /* some basic validation checks */
6582 if(This->cursorTexture) {
6583 ENTER_GL();
6584 glDeleteTextures(1, &This->cursorTexture);
6585 LEAVE_GL();
6586 This->cursorTexture = 0;
6589 if(pCursorBitmap) {
6590 /* MSDN: Cursor must be A8R8G8B8 */
6591 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6592 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6593 return WINED3DERR_INVALIDCALL;
6596 /* MSDN: Cursor must be smaller than the display mode */
6597 if(pSur->currentDesc.Width > This->ddraw_width ||
6598 pSur->currentDesc.Height > This->ddraw_height) {
6599 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
6600 return WINED3DERR_INVALIDCALL;
6603 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6604 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6605 * Texture and Blitting code to draw the cursor
6607 pSur->Flags |= SFLAG_FORCELOAD;
6608 IWineD3DSurface_PreLoad(pCursorBitmap);
6609 pSur->Flags &= ~SFLAG_FORCELOAD;
6610 /* Do not store the surface's pointer because the application may release
6611 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6612 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6614 This->cursorTexture = pSur->glDescription.textureName;
6615 This->cursorWidth = pSur->currentDesc.Width;
6616 This->cursorHeight = pSur->currentDesc.Height;
6617 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6620 This->xHotSpot = XHotSpot;
6621 This->yHotSpot = YHotSpot;
6622 return WINED3D_OK;
6625 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6627 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6629 This->xScreenSpace = XScreenSpace;
6630 This->yScreenSpace = YScreenSpace;
6632 return;
6636 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6638 BOOL oldVisible = This->bCursorVisible;
6639 TRACE("(%p) : visible(%d)\n", This, bShow);
6641 if(This->cursorTexture)
6642 This->bCursorVisible = bShow;
6644 return oldVisible;
6647 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6649 TRACE("(%p) : state (%u)\n", This, This->state);
6650 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6651 switch (This->state) {
6652 case WINED3D_OK:
6653 return WINED3D_OK;
6654 case WINED3DERR_DEVICELOST:
6656 ResourceList *resourceList = This->resources;
6657 while (NULL != resourceList) {
6658 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6659 return WINED3DERR_DEVICENOTRESET;
6660 resourceList = resourceList->next;
6662 return WINED3DERR_DEVICELOST;
6664 case WINED3DERR_DRIVERINTERNALERROR:
6665 return WINED3DERR_DRIVERINTERNALERROR;
6668 /* Unknown state */
6669 return WINED3DERR_DRIVERINTERNALERROR;
6673 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6675 /** FIXME: Resource tracking needs to be done,
6676 * The closes we can do to this is set the priorities of all managed textures low
6677 * and then reset them.
6678 ***********************************************************/
6679 FIXME("(%p) : stub\n", This);
6680 return WINED3D_OK;
6683 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6684 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6685 if(surface->Flags & SFLAG_DIBSECTION) {
6686 /* Release the DC */
6687 SelectObject(surface->hDC, surface->dib.holdbitmap);
6688 DeleteDC(surface->hDC);
6689 /* Release the DIB section */
6690 DeleteObject(surface->dib.DIBsection);
6691 surface->dib.bitmap_data = NULL;
6692 surface->resource.allocatedMemory = NULL;
6693 surface->Flags &= ~SFLAG_DIBSECTION;
6695 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6696 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6697 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6698 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6699 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6700 } else {
6701 surface->pow2Width = surface->pow2Height = 1;
6702 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6703 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6705 if(surface->glDescription.textureName) {
6706 ENTER_GL();
6707 glDeleteTextures(1, &surface->glDescription.textureName);
6708 LEAVE_GL();
6709 surface->glDescription.textureName = 0;
6711 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6712 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6713 surface->Flags |= SFLAG_NONPOW2;
6714 } else {
6715 surface->Flags &= ~SFLAG_NONPOW2;
6717 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6718 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6721 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6723 IWineD3DSwapChainImpl *swapchain;
6724 HRESULT hr;
6725 BOOL DisplayModeChanged = FALSE;
6726 WINED3DDISPLAYMODE mode;
6727 TRACE("(%p)\n", This);
6729 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6730 if(FAILED(hr)) {
6731 ERR("Failed to get the first implicit swapchain\n");
6732 return hr;
6735 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6736 * on an existing gl context, so there's no real need for recreation.
6738 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6740 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6742 TRACE("New params:\n");
6743 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6744 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6745 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6746 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6747 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6748 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6749 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6750 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6751 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6752 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6753 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6754 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6755 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6757 /* No special treatment of these parameters. Just store them */
6758 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6759 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6760 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6761 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6763 /* What to do about these? */
6764 if(*pPresentationParameters->BackBufferCount != 0 &&
6765 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6766 ERR("Cannot change the back buffer count yet\n");
6768 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6769 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6770 ERR("Cannot change the back buffer format yet\n");
6772 if(*pPresentationParameters->hDeviceWindow != NULL &&
6773 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6774 ERR("Cannot change the device window yet\n");
6776 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6777 ERR("What do do about a changed auto depth stencil parameter?\n");
6780 if(*pPresentationParameters->Windowed) {
6781 mode.Width = swapchain->orig_width;
6782 mode.Height = swapchain->orig_height;
6783 mode.RefreshRate = 0;
6784 mode.Format = swapchain->presentParms.BackBufferFormat;
6785 } else {
6786 mode.Width = *pPresentationParameters->BackBufferWidth;
6787 mode.Height = *pPresentationParameters->BackBufferHeight;
6788 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6789 mode.Format = swapchain->presentParms.BackBufferFormat;
6792 /* Should Width == 800 && Height == 0 set 800x600? */
6793 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6794 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6795 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6797 WINED3DVIEWPORT vp;
6798 int i;
6800 vp.X = 0;
6801 vp.Y = 0;
6802 vp.Width = *pPresentationParameters->BackBufferWidth;
6803 vp.Height = *pPresentationParameters->BackBufferHeight;
6804 vp.MinZ = 0;
6805 vp.MaxZ = 1;
6807 if(!*pPresentationParameters->Windowed) {
6808 DisplayModeChanged = TRUE;
6810 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6811 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6813 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6814 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6815 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6818 /* Now set the new viewport */
6819 IWineD3DDevice_SetViewport(iface, &vp);
6822 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6823 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6824 DisplayModeChanged) {
6825 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6828 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6829 return WINED3D_OK;
6832 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6834 /** FIXME: always true at the moment **/
6835 if(!bEnableDialogs) {
6836 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6838 return WINED3D_OK;
6842 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6844 TRACE("(%p) : pParameters %p\n", This, pParameters);
6846 *pParameters = This->createParms;
6847 return WINED3D_OK;
6850 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6851 IWineD3DSwapChain *swapchain;
6852 HRESULT hrc = WINED3D_OK;
6854 TRACE("Relaying to swapchain\n");
6856 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6857 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6858 IWineD3DSwapChain_Release(swapchain);
6860 return;
6863 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6864 IWineD3DSwapChain *swapchain;
6865 HRESULT hrc = WINED3D_OK;
6867 TRACE("Relaying to swapchain\n");
6869 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6870 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6871 IWineD3DSwapChain_Release(swapchain);
6873 return;
6877 /** ********************************************************
6878 * Notification functions
6879 ** ********************************************************/
6880 /** This function must be called in the release of a resource when ref == 0,
6881 * the contents of resource must still be correct,
6882 * any handels to other resource held by the caller must be closed
6883 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6884 *****************************************************/
6885 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6887 ResourceList* resourceList;
6889 TRACE("(%p) : resource %p\n", This, resource);
6890 #if 0
6891 EnterCriticalSection(&resourceStoreCriticalSection);
6892 #endif
6893 /* add a new texture to the frot of the linked list */
6894 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6895 resourceList->resource = resource;
6897 /* Get the old head */
6898 resourceList->next = This->resources;
6900 This->resources = resourceList;
6901 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6903 #if 0
6904 LeaveCriticalSection(&resourceStoreCriticalSection);
6905 #endif
6906 return;
6909 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6911 ResourceList* resourceList = NULL;
6912 ResourceList* previousResourceList = NULL;
6914 TRACE("(%p) : resource %p\n", This, resource);
6916 #if 0
6917 EnterCriticalSection(&resourceStoreCriticalSection);
6918 #endif
6919 resourceList = This->resources;
6921 while (resourceList != NULL) {
6922 if(resourceList->resource == resource) break;
6923 previousResourceList = resourceList;
6924 resourceList = resourceList->next;
6927 if (resourceList == NULL) {
6928 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6929 #if 0
6930 LeaveCriticalSection(&resourceStoreCriticalSection);
6931 #endif
6932 return;
6933 } else {
6934 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6936 /* make sure we don't leave a hole in the list */
6937 if (previousResourceList != NULL) {
6938 previousResourceList->next = resourceList->next;
6939 } else {
6940 This->resources = resourceList->next;
6943 #if 0
6944 LeaveCriticalSection(&resourceStoreCriticalSection);
6945 #endif
6946 return;
6950 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6952 int counter;
6954 TRACE("(%p) : resource %p\n", This, resource);
6955 switch(IWineD3DResource_GetType(resource)){
6956 case WINED3DRTYPE_SURFACE:
6957 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6958 break;
6959 case WINED3DRTYPE_TEXTURE:
6960 case WINED3DRTYPE_CUBETEXTURE:
6961 case WINED3DRTYPE_VOLUMETEXTURE:
6962 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6963 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6964 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6965 This->stateBlock->textures[counter] = NULL;
6967 if (This->updateStateBlock != This->stateBlock ){
6968 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6969 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6970 This->updateStateBlock->textures[counter] = NULL;
6974 break;
6975 case WINED3DRTYPE_VOLUME:
6976 /* TODO: nothing really? */
6977 break;
6978 case WINED3DRTYPE_VERTEXBUFFER:
6979 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6981 int streamNumber;
6982 TRACE("Cleaning up stream pointers\n");
6984 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6985 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6986 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6988 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6989 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6990 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6991 This->updateStateBlock->streamSource[streamNumber] = 0;
6992 /* Set changed flag? */
6995 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) */
6996 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6997 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6998 This->stateBlock->streamSource[streamNumber] = 0;
7001 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7002 else { /* This shouldn't happen */
7003 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7005 #endif
7009 break;
7010 case WINED3DRTYPE_INDEXBUFFER:
7011 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7012 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7013 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7014 This->updateStateBlock->pIndexData = NULL;
7017 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7018 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7019 This->stateBlock->pIndexData = NULL;
7023 break;
7024 default:
7025 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7026 break;
7030 /* Remove the resoruce from the resourceStore */
7031 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7033 TRACE("Resource released\n");
7037 /**********************************************************
7038 * IWineD3DDevice VTbl follows
7039 **********************************************************/
7041 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7043 /*** IUnknown methods ***/
7044 IWineD3DDeviceImpl_QueryInterface,
7045 IWineD3DDeviceImpl_AddRef,
7046 IWineD3DDeviceImpl_Release,
7047 /*** IWineD3DDevice methods ***/
7048 IWineD3DDeviceImpl_GetParent,
7049 /*** Creation methods**/
7050 IWineD3DDeviceImpl_CreateVertexBuffer,
7051 IWineD3DDeviceImpl_CreateIndexBuffer,
7052 IWineD3DDeviceImpl_CreateStateBlock,
7053 IWineD3DDeviceImpl_CreateSurface,
7054 IWineD3DDeviceImpl_CreateTexture,
7055 IWineD3DDeviceImpl_CreateVolumeTexture,
7056 IWineD3DDeviceImpl_CreateVolume,
7057 IWineD3DDeviceImpl_CreateCubeTexture,
7058 IWineD3DDeviceImpl_CreateQuery,
7059 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7060 IWineD3DDeviceImpl_CreateVertexDeclaration,
7061 IWineD3DDeviceImpl_CreateVertexShader,
7062 IWineD3DDeviceImpl_CreatePixelShader,
7063 IWineD3DDeviceImpl_CreatePalette,
7064 /*** Odd functions **/
7065 IWineD3DDeviceImpl_Init3D,
7066 IWineD3DDeviceImpl_Uninit3D,
7067 IWineD3DDeviceImpl_SetFullscreen,
7068 IWineD3DDeviceImpl_EnumDisplayModes,
7069 IWineD3DDeviceImpl_EvictManagedResources,
7070 IWineD3DDeviceImpl_GetAvailableTextureMem,
7071 IWineD3DDeviceImpl_GetBackBuffer,
7072 IWineD3DDeviceImpl_GetCreationParameters,
7073 IWineD3DDeviceImpl_GetDeviceCaps,
7074 IWineD3DDeviceImpl_GetDirect3D,
7075 IWineD3DDeviceImpl_GetDisplayMode,
7076 IWineD3DDeviceImpl_SetDisplayMode,
7077 IWineD3DDeviceImpl_GetHWND,
7078 IWineD3DDeviceImpl_SetHWND,
7079 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7080 IWineD3DDeviceImpl_GetRasterStatus,
7081 IWineD3DDeviceImpl_GetSwapChain,
7082 IWineD3DDeviceImpl_Reset,
7083 IWineD3DDeviceImpl_SetDialogBoxMode,
7084 IWineD3DDeviceImpl_SetCursorProperties,
7085 IWineD3DDeviceImpl_SetCursorPosition,
7086 IWineD3DDeviceImpl_ShowCursor,
7087 IWineD3DDeviceImpl_TestCooperativeLevel,
7088 /*** Getters and setters **/
7089 IWineD3DDeviceImpl_SetClipPlane,
7090 IWineD3DDeviceImpl_GetClipPlane,
7091 IWineD3DDeviceImpl_SetClipStatus,
7092 IWineD3DDeviceImpl_GetClipStatus,
7093 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7094 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7095 IWineD3DDeviceImpl_SetDepthStencilSurface,
7096 IWineD3DDeviceImpl_GetDepthStencilSurface,
7097 IWineD3DDeviceImpl_SetFVF,
7098 IWineD3DDeviceImpl_GetFVF,
7099 IWineD3DDeviceImpl_SetGammaRamp,
7100 IWineD3DDeviceImpl_GetGammaRamp,
7101 IWineD3DDeviceImpl_SetIndices,
7102 IWineD3DDeviceImpl_GetIndices,
7103 IWineD3DDeviceImpl_SetLight,
7104 IWineD3DDeviceImpl_GetLight,
7105 IWineD3DDeviceImpl_SetLightEnable,
7106 IWineD3DDeviceImpl_GetLightEnable,
7107 IWineD3DDeviceImpl_SetMaterial,
7108 IWineD3DDeviceImpl_GetMaterial,
7109 IWineD3DDeviceImpl_SetNPatchMode,
7110 IWineD3DDeviceImpl_GetNPatchMode,
7111 IWineD3DDeviceImpl_SetPaletteEntries,
7112 IWineD3DDeviceImpl_GetPaletteEntries,
7113 IWineD3DDeviceImpl_SetPixelShader,
7114 IWineD3DDeviceImpl_GetPixelShader,
7115 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7116 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7117 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7118 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7119 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7120 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7121 IWineD3DDeviceImpl_SetRenderState,
7122 IWineD3DDeviceImpl_GetRenderState,
7123 IWineD3DDeviceImpl_SetRenderTarget,
7124 IWineD3DDeviceImpl_GetRenderTarget,
7125 IWineD3DDeviceImpl_SetFrontBackBuffers,
7126 IWineD3DDeviceImpl_SetSamplerState,
7127 IWineD3DDeviceImpl_GetSamplerState,
7128 IWineD3DDeviceImpl_SetScissorRect,
7129 IWineD3DDeviceImpl_GetScissorRect,
7130 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7131 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7132 IWineD3DDeviceImpl_SetStreamSource,
7133 IWineD3DDeviceImpl_GetStreamSource,
7134 IWineD3DDeviceImpl_SetStreamSourceFreq,
7135 IWineD3DDeviceImpl_GetStreamSourceFreq,
7136 IWineD3DDeviceImpl_SetTexture,
7137 IWineD3DDeviceImpl_GetTexture,
7138 IWineD3DDeviceImpl_SetTextureStageState,
7139 IWineD3DDeviceImpl_GetTextureStageState,
7140 IWineD3DDeviceImpl_SetTransform,
7141 IWineD3DDeviceImpl_GetTransform,
7142 IWineD3DDeviceImpl_SetVertexDeclaration,
7143 IWineD3DDeviceImpl_GetVertexDeclaration,
7144 IWineD3DDeviceImpl_SetVertexShader,
7145 IWineD3DDeviceImpl_GetVertexShader,
7146 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7147 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7148 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7149 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7150 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7151 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7152 IWineD3DDeviceImpl_SetViewport,
7153 IWineD3DDeviceImpl_GetViewport,
7154 IWineD3DDeviceImpl_MultiplyTransform,
7155 IWineD3DDeviceImpl_ValidateDevice,
7156 IWineD3DDeviceImpl_ProcessVertices,
7157 /*** State block ***/
7158 IWineD3DDeviceImpl_BeginStateBlock,
7159 IWineD3DDeviceImpl_EndStateBlock,
7160 /*** Scene management ***/
7161 IWineD3DDeviceImpl_BeginScene,
7162 IWineD3DDeviceImpl_EndScene,
7163 IWineD3DDeviceImpl_Present,
7164 IWineD3DDeviceImpl_Clear,
7165 /*** Drawing ***/
7166 IWineD3DDeviceImpl_DrawPrimitive,
7167 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7168 IWineD3DDeviceImpl_DrawPrimitiveUP,
7169 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7170 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7171 IWineD3DDeviceImpl_DrawRectPatch,
7172 IWineD3DDeviceImpl_DrawTriPatch,
7173 IWineD3DDeviceImpl_DeletePatch,
7174 IWineD3DDeviceImpl_ColorFill,
7175 IWineD3DDeviceImpl_UpdateTexture,
7176 IWineD3DDeviceImpl_UpdateSurface,
7177 IWineD3DDeviceImpl_StretchRect,
7178 IWineD3DDeviceImpl_GetRenderTargetData,
7179 IWineD3DDeviceImpl_GetFrontBufferData,
7180 /*** Internal use IWineD3DDevice methods ***/
7181 IWineD3DDeviceImpl_SetupTextureStates,
7182 /*** object tracking ***/
7183 IWineD3DDeviceImpl_ResourceReleased
7187 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7188 WINED3DRS_ALPHABLENDENABLE ,
7189 WINED3DRS_ALPHAFUNC ,
7190 WINED3DRS_ALPHAREF ,
7191 WINED3DRS_ALPHATESTENABLE ,
7192 WINED3DRS_BLENDOP ,
7193 WINED3DRS_COLORWRITEENABLE ,
7194 WINED3DRS_DESTBLEND ,
7195 WINED3DRS_DITHERENABLE ,
7196 WINED3DRS_FILLMODE ,
7197 WINED3DRS_FOGDENSITY ,
7198 WINED3DRS_FOGEND ,
7199 WINED3DRS_FOGSTART ,
7200 WINED3DRS_LASTPIXEL ,
7201 WINED3DRS_SHADEMODE ,
7202 WINED3DRS_SRCBLEND ,
7203 WINED3DRS_STENCILENABLE ,
7204 WINED3DRS_STENCILFAIL ,
7205 WINED3DRS_STENCILFUNC ,
7206 WINED3DRS_STENCILMASK ,
7207 WINED3DRS_STENCILPASS ,
7208 WINED3DRS_STENCILREF ,
7209 WINED3DRS_STENCILWRITEMASK ,
7210 WINED3DRS_STENCILZFAIL ,
7211 WINED3DRS_TEXTUREFACTOR ,
7212 WINED3DRS_WRAP0 ,
7213 WINED3DRS_WRAP1 ,
7214 WINED3DRS_WRAP2 ,
7215 WINED3DRS_WRAP3 ,
7216 WINED3DRS_WRAP4 ,
7217 WINED3DRS_WRAP5 ,
7218 WINED3DRS_WRAP6 ,
7219 WINED3DRS_WRAP7 ,
7220 WINED3DRS_ZENABLE ,
7221 WINED3DRS_ZFUNC ,
7222 WINED3DRS_ZWRITEENABLE
7225 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7226 WINED3DTSS_ADDRESSW ,
7227 WINED3DTSS_ALPHAARG0 ,
7228 WINED3DTSS_ALPHAARG1 ,
7229 WINED3DTSS_ALPHAARG2 ,
7230 WINED3DTSS_ALPHAOP ,
7231 WINED3DTSS_BUMPENVLOFFSET ,
7232 WINED3DTSS_BUMPENVLSCALE ,
7233 WINED3DTSS_BUMPENVMAT00 ,
7234 WINED3DTSS_BUMPENVMAT01 ,
7235 WINED3DTSS_BUMPENVMAT10 ,
7236 WINED3DTSS_BUMPENVMAT11 ,
7237 WINED3DTSS_COLORARG0 ,
7238 WINED3DTSS_COLORARG1 ,
7239 WINED3DTSS_COLORARG2 ,
7240 WINED3DTSS_COLOROP ,
7241 WINED3DTSS_RESULTARG ,
7242 WINED3DTSS_TEXCOORDINDEX ,
7243 WINED3DTSS_TEXTURETRANSFORMFLAGS
7246 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7247 WINED3DSAMP_ADDRESSU ,
7248 WINED3DSAMP_ADDRESSV ,
7249 WINED3DSAMP_ADDRESSW ,
7250 WINED3DSAMP_BORDERCOLOR ,
7251 WINED3DSAMP_MAGFILTER ,
7252 WINED3DSAMP_MINFILTER ,
7253 WINED3DSAMP_MIPFILTER ,
7254 WINED3DSAMP_MIPMAPLODBIAS ,
7255 WINED3DSAMP_MAXMIPLEVEL ,
7256 WINED3DSAMP_MAXANISOTROPY ,
7257 WINED3DSAMP_SRGBTEXTURE ,
7258 WINED3DSAMP_ELEMENTINDEX
7261 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7262 WINED3DRS_AMBIENT ,
7263 WINED3DRS_AMBIENTMATERIALSOURCE ,
7264 WINED3DRS_CLIPPING ,
7265 WINED3DRS_CLIPPLANEENABLE ,
7266 WINED3DRS_COLORVERTEX ,
7267 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7268 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7269 WINED3DRS_FOGDENSITY ,
7270 WINED3DRS_FOGEND ,
7271 WINED3DRS_FOGSTART ,
7272 WINED3DRS_FOGTABLEMODE ,
7273 WINED3DRS_FOGVERTEXMODE ,
7274 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7275 WINED3DRS_LIGHTING ,
7276 WINED3DRS_LOCALVIEWER ,
7277 WINED3DRS_MULTISAMPLEANTIALIAS ,
7278 WINED3DRS_MULTISAMPLEMASK ,
7279 WINED3DRS_NORMALIZENORMALS ,
7280 WINED3DRS_PATCHEDGESTYLE ,
7281 WINED3DRS_POINTSCALE_A ,
7282 WINED3DRS_POINTSCALE_B ,
7283 WINED3DRS_POINTSCALE_C ,
7284 WINED3DRS_POINTSCALEENABLE ,
7285 WINED3DRS_POINTSIZE ,
7286 WINED3DRS_POINTSIZE_MAX ,
7287 WINED3DRS_POINTSIZE_MIN ,
7288 WINED3DRS_POINTSPRITEENABLE ,
7289 WINED3DRS_RANGEFOGENABLE ,
7290 WINED3DRS_SPECULARMATERIALSOURCE ,
7291 WINED3DRS_TWEENFACTOR ,
7292 WINED3DRS_VERTEXBLEND
7295 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7296 WINED3DTSS_TEXCOORDINDEX ,
7297 WINED3DTSS_TEXTURETRANSFORMFLAGS
7300 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7301 WINED3DSAMP_DMAPOFFSET