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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
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 )
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;
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);
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; \
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; \
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); \
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); \
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) {
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);
166 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
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");
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");
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);
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:
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");
218 case WINED3DLIGHT_SPOT:
220 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
221 checkGLcall("glLightfv");
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");
232 case WINED3DLIGHT_DIRECTIONAL:
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");
243 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
246 /* Restore the modelview matrix */
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
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;
294 ptr = list_head( &This->glsl_shader_progs );
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",
302 This->stateBlock->glsl_program = curLink;
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) {
321 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
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
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));
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;
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;
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 );
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;
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));
456 VTRACE(("Activating appropriate texture state %d\n", Sampler));
457 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
459 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
460 checkGLcall("glActiveTextureARB");
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");
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);
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);
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,
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(...)");
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);
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);
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);
572 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
575 HeapFree(GetProcessHeap(), 0, This->render_targets);
577 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
579 /* TODO: Clean up all the surfaces and textures! */
580 /* NOTE: You must release the parent if the object was created via a callback
581 ** ***************************/
583 /* Delete any GLSL shader programs that may exist */
584 if (This->vs_selected_mode == SHADER_GLSL ||
585 This->ps_selected_mode == SHADER_GLSL)
586 delete_glsl_shader_list(iface);
588 /* Release the update stateblock */
589 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
590 if(This->updateStateBlock != This->stateBlock)
591 FIXME("(%p) Something's still holding the Update stateblock\n",This);
593 This->updateStateBlock = NULL;
594 { /* because were not doing proper internal refcounts releasing the primary state block
595 causes recursion with the extra checks in ResourceReleased, to avoid this we have
596 to set this->stateBlock = NULL; first */
597 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
598 This->stateBlock = NULL;
600 /* Release the stateblock */
601 if(IWineD3DStateBlock_Release(stateBlock) > 0){
602 FIXME("(%p) Something's still holding the Update stateblock\n",This);
606 if (This->resources != NULL ) {
607 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
608 dumpResources(This->resources);
612 IWineD3D_Release(This->wineD3D);
613 This->wineD3D = NULL;
614 HeapFree(GetProcessHeap(), 0, This);
615 TRACE("Freed device %p\n", This);
621 /**********************************************************
622 * IWineD3DDevice implementation follows
623 **********************************************************/
624 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
626 *pParent = This->parent;
627 IUnknown_AddRef(This->parent);
631 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
632 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
633 GLenum error, glUsage;
634 DWORD vboUsage = object->resource.usage;
635 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
636 WARN("Creating a vbo failed once, not trying again\n");
640 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
643 /* Make sure that the gl error is cleared. Do not use checkGLcall
644 * here because checkGLcall just prints a fixme and continues. However,
645 * if an error during VBO creation occurs we can fall back to non-vbo operation
646 * with full functionality(but performance loss)
648 while(glGetError() != GL_NO_ERROR);
650 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
651 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
652 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
653 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
654 * to check if the rhw and color values are in the correct format.
657 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
658 error = glGetError();
659 if(object->vbo == 0 || error != GL_NO_ERROR) {
660 WARN("Failed to create a VBO with error %d\n", error);
664 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
665 error = glGetError();
666 if(error != GL_NO_ERROR) {
667 WARN("Failed to bind the VBO, error %d\n", error);
671 /* Transformed vertices are horribly inflexible. If the app specifies an
672 * vertex buffer with transformed vertices in default pool without DYNAMIC
673 * usage assume DYNAMIC usage and print a warning. The app will have to update
674 * the vertices regularily for them to be useful
676 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
677 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
678 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
679 vboUsage |= WINED3DUSAGE_DYNAMIC;
682 /* Don't use static, because dx apps tend to update the buffer
683 * quite often even if they specify 0 usage
685 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
686 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
687 TRACE("Gl usage = GL_STREAM_DRAW\n");
688 glUsage = GL_STREAM_DRAW_ARB;
690 case D3DUSAGE_WRITEONLY:
691 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
692 glUsage = GL_DYNAMIC_DRAW_ARB;
694 case D3DUSAGE_DYNAMIC:
695 TRACE("Gl usage = GL_STREAM_COPY\n");
696 glUsage = GL_STREAM_COPY_ARB;
699 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
700 glUsage = GL_DYNAMIC_COPY_ARB;
704 /* Reserve memory for the buffer. The amount of data won't change
705 * so we are safe with calling glBufferData once with a NULL ptr and
706 * calling glBufferSubData on updates
708 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
709 error = glGetError();
710 if(error != GL_NO_ERROR) {
711 WARN("glBufferDataARB failed with error %d\n", error);
719 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
720 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
721 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
723 object->Flags |= VBFLAG_VBOCREATEFAIL;
728 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
729 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
732 IWineD3DVertexBufferImpl *object;
733 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
734 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
736 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
738 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
739 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
741 if(Size == 0) return WINED3DERR_INVALIDCALL;
743 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
744 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
748 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
749 * drawStridedFast (half-life 2).
751 * Basically converting the vertices in the buffer is quite expensive, and observations
752 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
753 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
755 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
756 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
757 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
758 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
760 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
761 * more. In this call we can convert dx7 buffers too.
763 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
764 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
765 (dxVersion > 7 || !conv) ) {
768 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
769 if(dxVersion == 7 && object->vbo) {
770 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
771 object->resource.allocatedMemory = NULL;
778 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
779 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
780 HANDLE *sharedHandle, IUnknown *parent) {
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DIndexBufferImpl *object;
783 TRACE("(%p) Creating index buffer\n", This);
785 /* Allocate the storage for the device */
786 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
789 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
790 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
793 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
794 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
795 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
800 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
803 IWineD3DStateBlockImpl *object;
807 D3DCREATEOBJECTINSTANCE(object, StateBlock)
808 object->blockType = Type;
810 /* Special case - Used during initialization to produce a placeholder stateblock
811 so other functions called can update a state block */
812 if (Type == WINED3DSBT_INIT) {
813 /* Don't bother increasing the reference count otherwise a device will never
814 be freed due to circular dependencies */
818 temp_result = allocate_shader_constants(object);
819 if (WINED3D_OK != temp_result)
822 /* Otherwise, might as well set the whole state block to the appropriate values */
823 if (This->stateBlock != NULL)
824 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
826 memset(object->streamFreq, 1, sizeof(object->streamFreq));
828 /* Reset the ref and type after kludging it */
829 object->wineD3DDevice = This;
831 object->blockType = Type;
833 TRACE("Updating changed flags appropriate for type %d\n", Type);
835 if (Type == WINED3DSBT_ALL) {
837 TRACE("ALL => Pretend everything has changed\n");
838 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
840 } else if (Type == WINED3DSBT_PIXELSTATE) {
842 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
843 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
845 object->changed.pixelShader = TRUE;
847 /* Pixel Shader Constants */
848 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
849 object->changed.pixelShaderConstantsF[i] = TRUE;
850 for (i = 0; i < MAX_CONST_B; ++i)
851 object->changed.pixelShaderConstantsB[i] = TRUE;
852 for (i = 0; i < MAX_CONST_I; ++i)
853 object->changed.pixelShaderConstantsI[i] = TRUE;
855 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
856 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
858 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
859 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
860 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
863 for (j = 0 ; j < 16; j++) {
864 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
866 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
870 } else if (Type == WINED3DSBT_VERTEXSTATE) {
872 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
873 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
875 object->changed.vertexShader = TRUE;
877 /* Vertex Shader Constants */
878 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
879 object->changed.vertexShaderConstantsF[i] = TRUE;
880 for (i = 0; i < MAX_CONST_B; ++i)
881 object->changed.vertexShaderConstantsB[i] = TRUE;
882 for (i = 0; i < MAX_CONST_I; ++i)
883 object->changed.vertexShaderConstantsI[i] = TRUE;
885 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
886 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
888 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
889 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
890 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
893 for (j = 0 ; j < 16; j++){
894 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
895 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
899 /* Duplicate light chain */
901 PLIGHTINFOEL *src = NULL;
902 PLIGHTINFOEL *dst = NULL;
903 PLIGHTINFOEL *newEl = NULL;
904 src = This->stateBlock->lights;
905 object->lights = NULL;
909 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
910 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
911 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
913 newEl->changed = TRUE;
914 newEl->enabledChanged = TRUE;
916 object->lights = newEl;
927 FIXME("Unrecognized state block type %d\n", Type);
930 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
935 /* ************************************
937 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
940 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
942 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.
944 ******************************** */
946 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) {
947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
948 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
949 unsigned int pow2Width, pow2Height;
950 unsigned int Size = 1;
951 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
952 TRACE("(%p) Create surface\n",This);
954 /** FIXME: Check ranges on the inputs are valid
957 * [in] Quality level. The valid range is between zero and one less than the level
958 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
959 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
960 * values of paired render targets, depth stencil surfaces, and the MultiSample type
962 *******************************/
967 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
969 * If this flag is set, the contents of the depth stencil buffer will be
970 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
971 * with a different depth surface.
973 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
974 ***************************/
976 if(MultisampleQuality < 0) {
977 FIXME("Invalid multisample level %d\n", MultisampleQuality);
978 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
981 if(MultisampleQuality > 0) {
982 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
983 MultisampleQuality=0;
986 /** FIXME: Check that the format is supported
988 *******************************/
990 /* Non-power2 support */
991 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
995 /* Find the nearest pow2 match */
996 pow2Width = pow2Height = 1;
997 while (pow2Width < Width) pow2Width <<= 1;
998 while (pow2Height < Height) pow2Height <<= 1;
1001 if (pow2Width > Width || pow2Height > Height) {
1002 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
1003 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
1004 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1005 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1006 This, Width, Height);
1007 return WINED3DERR_NOTAVAILABLE;
1011 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1012 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1014 *********************************/
1015 if (WINED3DFMT_UNKNOWN == Format) {
1017 } else if (Format == WINED3DFMT_DXT1) {
1018 /* DXT1 is half byte per pixel */
1019 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1021 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1022 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1023 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1025 /* The pitch is a multiple of 4 bytes */
1026 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1030 /** Create and initialise the surface resource **/
1031 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1032 /* "Standalone" surface */
1033 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1035 object->currentDesc.Width = Width;
1036 object->currentDesc.Height = Height;
1037 object->currentDesc.MultiSampleType = MultiSample;
1038 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1040 /* Setup some glformat defaults */
1041 object->glDescription.glFormat = tableEntry->glFormat;
1042 object->glDescription.glFormatInternal = tableEntry->glInternal;
1043 object->glDescription.glType = tableEntry->glType;
1045 object->glDescription.textureName = 0;
1046 object->glDescription.level = Level;
1047 object->glDescription.target = GL_TEXTURE_2D;
1050 object->pow2Width = pow2Width;
1051 object->pow2Height = pow2Height;
1054 object->Flags = 0; /* We start without flags set */
1055 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1056 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1057 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1058 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1061 if (WINED3DFMT_UNKNOWN != Format) {
1062 object->bytesPerPixel = tableEntry->bpp;
1063 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1064 object->pow2Size *= pow2Height;
1066 object->bytesPerPixel = 0;
1067 object->pow2Size = 0;
1070 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1072 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1074 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1075 * this function is too deep to need to care about things like this.
1076 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1077 * ****************************************/
1079 case WINED3DPOOL_SCRATCH:
1081 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1082 which are mutually exclusive, setting lockable to true\n");
1085 case WINED3DPOOL_SYSTEMMEM:
1086 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1087 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1088 case WINED3DPOOL_MANAGED:
1089 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1090 Usage of DYNAMIC which are mutually exclusive, not doing \
1091 anything just telling you.\n");
1093 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1094 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1095 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1096 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1099 FIXME("(%p) Unknown pool %d\n", This, Pool);
1103 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1104 FIXME("Trying to create a render target that isn't in the default pool\n");
1107 /* mark the texture as dirty so that it gets loaded first time around*/
1108 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1109 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1110 This, Width, Height, Format, debug_d3dformat(Format),
1111 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1113 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1114 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1115 This->ddraw_primary = (IWineD3DSurface *) object;
1117 /* Look at the implementation and set the correct Vtable */
1119 case SURFACE_OPENGL:
1120 /* Nothing to do, it's set already */
1124 object->lpVtbl = &IWineGDISurface_Vtbl;
1128 /* To be sure to catch this */
1129 ERR("Unknown requested surface implementation %d!\n", Impl);
1130 IWineD3DSurface_Release((IWineD3DSurface *) object);
1131 return WINED3DERR_INVALIDCALL;
1134 /* Call the private setup routine */
1135 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1139 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1140 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1141 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1142 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DTextureImpl *object;
1150 unsigned int pow2Width;
1151 unsigned int pow2Height;
1154 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1155 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1156 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1158 /* TODO: It should only be possible to create textures for formats
1159 that are reported as supported */
1160 if (WINED3DFMT_UNKNOWN >= Format) {
1161 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1162 return WINED3DERR_INVALIDCALL;
1165 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1166 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1167 object->width = Width;
1168 object->height = Height;
1170 /** Non-power2 support **/
1171 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1173 pow2Height = Height;
1175 /* Find the nearest pow2 match */
1176 pow2Width = pow2Height = 1;
1177 while (pow2Width < Width) pow2Width <<= 1;
1178 while (pow2Height < Height) pow2Height <<= 1;
1181 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1182 /* Precalculated scaling for 'faked' non power of two texture coords */
1183 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1184 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1185 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1187 /* Calculate levels for mip mapping */
1189 TRACE("calculating levels %d\n", object->baseTexture.levels);
1190 object->baseTexture.levels++;
1193 while (tmpW > 1 || tmpH > 1) {
1194 tmpW = max(1, tmpW >> 1);
1195 tmpH = max(1, tmpH >> 1);
1196 object->baseTexture.levels++;
1198 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1201 /* Generate all the surfaces */
1204 for (i = 0; i < object->baseTexture.levels; i++)
1206 /* use the callback to create the texture surface */
1207 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1208 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1209 FIXME("Failed to create surface %p\n", object);
1211 object->surfaces[i] = NULL;
1212 IWineD3DTexture_Release((IWineD3DTexture *)object);
1218 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1219 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1220 /* calculate the next mipmap level */
1221 tmpW = max(1, tmpW >> 1);
1222 tmpH = max(1, tmpH >> 1);
1225 TRACE("(%p) : Created texture %p\n", This, object);
1229 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1230 UINT Width, UINT Height, UINT Depth,
1231 UINT Levels, DWORD Usage,
1232 WINED3DFORMAT Format, WINED3DPOOL Pool,
1233 IWineD3DVolumeTexture **ppVolumeTexture,
1234 HANDLE *pSharedHandle, IUnknown *parent,
1235 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1238 IWineD3DVolumeTextureImpl *object;
1244 /* TODO: It should only be possible to create textures for formats
1245 that are reported as supported */
1246 if (WINED3DFMT_UNKNOWN >= Format) {
1247 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1248 return WINED3DERR_INVALIDCALL;
1251 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1252 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1254 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1255 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1257 object->width = Width;
1258 object->height = Height;
1259 object->depth = Depth;
1261 /* Calculate levels for mip mapping */
1263 object->baseTexture.levels++;
1267 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1268 tmpW = max(1, tmpW >> 1);
1269 tmpH = max(1, tmpH >> 1);
1270 tmpD = max(1, tmpD >> 1);
1271 object->baseTexture.levels++;
1273 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1276 /* Generate all the surfaces */
1281 for (i = 0; i < object->baseTexture.levels; i++)
1283 /* Create the volume */
1284 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
1285 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1287 /* Set its container to this object */
1288 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1290 /* calcualte the next mipmap level */
1291 tmpW = max(1, tmpW >> 1);
1292 tmpH = max(1, tmpH >> 1);
1293 tmpD = max(1, tmpD >> 1);
1296 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1297 TRACE("(%p) : Created volume texture %p\n", This, object);
1301 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1302 UINT Width, UINT Height, UINT Depth,
1304 WINED3DFORMAT Format, WINED3DPOOL Pool,
1305 IWineD3DVolume** ppVolume,
1306 HANDLE* pSharedHandle, IUnknown *parent) {
1308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1310 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1312 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1314 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1315 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1317 object->currentDesc.Width = Width;
1318 object->currentDesc.Height = Height;
1319 object->currentDesc.Depth = Depth;
1320 object->bytesPerPixel = formatDesc->bpp;
1322 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1323 object->lockable = TRUE;
1324 object->locked = FALSE;
1325 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1326 object->dirty = TRUE;
1328 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1331 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1332 UINT Levels, DWORD Usage,
1333 WINED3DFORMAT Format, WINED3DPOOL Pool,
1334 IWineD3DCubeTexture **ppCubeTexture,
1335 HANDLE *pSharedHandle, IUnknown *parent,
1336 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1343 unsigned int pow2EdgeLength = EdgeLength;
1345 /* TODO: It should only be possible to create textures for formats
1346 that are reported as supported */
1347 if (WINED3DFMT_UNKNOWN >= Format) {
1348 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1349 return WINED3DERR_INVALIDCALL;
1352 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1353 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1355 TRACE("(%p) Create Cube Texture\n", This);
1357 /** Non-power2 support **/
1359 /* Find the nearest pow2 match */
1361 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1363 object->edgeLength = EdgeLength;
1364 /* TODO: support for native non-power 2 */
1365 /* Precalculated scaling for 'faked' non power of two texture coords */
1366 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1368 /* Calculate levels for mip mapping */
1370 object->baseTexture.levels++;
1373 tmpW = max(1, tmpW >> 1);
1374 object->baseTexture.levels++;
1376 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1379 /* Generate all the surfaces */
1381 for (i = 0; i < object->baseTexture.levels; i++) {
1383 /* Create the 6 faces */
1384 for (j = 0; j < 6; j++) {
1386 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1387 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1389 if(hr!= WINED3D_OK) {
1393 for (l = 0; l < j; l++) {
1394 IWineD3DSurface_Release(object->surfaces[j][i]);
1396 for (k = 0; k < i; k++) {
1397 for (l = 0; l < 6; l++) {
1398 IWineD3DSurface_Release(object->surfaces[l][j]);
1402 FIXME("(%p) Failed to create surface\n",object);
1403 HeapFree(GetProcessHeap(),0,object);
1404 *ppCubeTexture = NULL;
1407 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1408 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1410 tmpW = max(1, tmpW >> 1);
1413 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1414 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1418 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1420 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1422 if (NULL == ppQuery) {
1423 /* Just a check to see if we support this type of query */
1424 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1426 case WINED3DQUERYTYPE_OCCLUSION:
1427 TRACE("(%p) occlusion query\n", This);
1428 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1431 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1433 case WINED3DQUERYTYPE_VCACHE:
1434 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1435 case WINED3DQUERYTYPE_VERTEXSTATS:
1436 case WINED3DQUERYTYPE_EVENT:
1437 case WINED3DQUERYTYPE_TIMESTAMP:
1438 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1439 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1440 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1441 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1442 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1443 case WINED3DQUERYTYPE_PIXELTIMINGS:
1444 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1445 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1447 FIXME("(%p) Unhandled query type %d\n", This, Type);
1452 D3DCREATEOBJECTINSTANCE(object, Query)
1453 object->type = Type;
1454 /* allocated the 'extended' data based on the type of query requested */
1456 case WINED3DQUERYTYPE_OCCLUSION:
1457 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1458 TRACE("(%p) Allocating data for an occlusion query\n", This);
1459 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1460 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1463 case WINED3DQUERYTYPE_VCACHE:
1464 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1465 case WINED3DQUERYTYPE_VERTEXSTATS:
1466 case WINED3DQUERYTYPE_EVENT:
1467 case WINED3DQUERYTYPE_TIMESTAMP:
1468 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1469 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1470 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1471 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1472 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1473 case WINED3DQUERYTYPE_PIXELTIMINGS:
1474 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1475 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1477 object->extendedData = 0;
1478 FIXME("(%p) Unhandled query type %d\n",This , Type);
1480 TRACE("(%p) : Created Query %p\n", This, object);
1484 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1485 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1487 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1488 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1492 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1494 XVisualInfo template;
1495 GLXContext oldContext;
1496 Drawable oldDrawable;
1497 HRESULT hr = WINED3D_OK;
1499 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1501 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1502 * does a device hold a reference to a swap chain giving them a lifetime of the device
1503 * or does the swap chain notify the device of its destruction.
1504 *******************************/
1506 /* Check the params */
1507 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1508 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1509 return WINED3DERR_INVALIDCALL;
1510 } else if (*pPresentationParameters->BackBufferCount > 1) {
1511 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");
1514 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1516 /*********************
1517 * Lookup the window Handle and the relating X window handle
1518 ********************/
1520 /* Setup hwnd we are using, plus which display this equates to */
1521 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1522 if (!object->win_handle) {
1523 object->win_handle = This->createParms.hFocusWindow;
1526 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1527 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1528 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1529 return WINED3DERR_NOTAVAILABLE;
1531 hDc = GetDC(object->win_handle);
1532 object->display = get_display(hDc);
1533 ReleaseDC(object->win_handle, hDc);
1534 TRACE("Using a display of %p %p\n", object->display, hDc);
1536 if (NULL == object->display || NULL == hDc) {
1537 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1538 return WINED3DERR_NOTAVAILABLE;
1541 if (object->win == 0) {
1542 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1543 return WINED3DERR_NOTAVAILABLE;
1546 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1547 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1550 * Create an opengl context for the display visual
1551 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1552 * use different properties after that point in time. FIXME: How to handle when requested format
1553 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1554 * it chooses is identical to the one already being used!
1555 **********************************/
1557 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1560 /* Create a new context for this swapchain */
1561 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1562 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1563 (or the best possible if none is requested) */
1564 TRACE("Found x visual ID : %ld\n", template.visualid);
1566 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1567 if (NULL == object->visInfo) {
1568 ERR("cannot really get XVisual\n");
1570 return WINED3DERR_NOTAVAILABLE;
1573 /* Write out some debug info about the visual/s */
1574 TRACE("Using x visual ID : %ld\n", template.visualid);
1575 TRACE(" visual info: %p\n", object->visInfo);
1576 TRACE(" num items : %d\n", num);
1577 for (n = 0;n < num; n++) {
1578 TRACE("=====item=====: %d\n", n + 1);
1579 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1580 TRACE(" screen : %d\n", object->visInfo[n].screen);
1581 TRACE(" depth : %u\n", object->visInfo[n].depth);
1582 TRACE(" class : %d\n", object->visInfo[n].class);
1583 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1584 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1585 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1586 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1587 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1588 /* log some extra glx info */
1589 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1590 TRACE(" gl_aux_buffers : %d\n", value);
1591 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1592 TRACE(" gl_buffer_size : %d\n", value);
1593 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1594 TRACE(" gl_red_size : %d\n", value);
1595 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1596 TRACE(" gl_green_size : %d\n", value);
1597 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1598 TRACE(" gl_blue_size : %d\n", value);
1599 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1600 TRACE(" gl_alpha_size : %d\n", value);
1601 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1602 TRACE(" gl_depth_size : %d\n", value);
1603 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1604 TRACE(" gl_stencil_size : %d\n", value);
1606 /* Now choose a similar visual ID*/
1608 #ifdef USE_CONTEXT_MANAGER
1610 /** TODO: use a context mamager **/
1614 IWineD3DSwapChain *implSwapChain;
1615 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1616 /* The first time around we create the context that is shared with all other swapchains and render targets */
1617 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1618 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1621 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1622 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1623 /* and create a new context with the implicit swapchains context as the shared context */
1624 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1625 IWineD3DSwapChain_Release(implSwapChain);
1630 XFree(object->visInfo);
1631 object->visInfo = NULL;
1635 if (!object->glCtx) {
1636 ERR("Failed to create GLX context\n");
1637 return WINED3DERR_NOTAVAILABLE;
1639 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1640 object->win_handle, object->glCtx, object->win, object->visInfo);
1643 /*********************
1644 * Windowed / Fullscreen
1645 *******************/
1648 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1649 * so we should really check to see if there is a fullscreen swapchain already
1650 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1651 **************************************/
1653 if (!*(pPresentationParameters->Windowed)) {
1659 /* Get info on the current display setup */
1660 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1661 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1664 /* Change the display settings */
1665 memset(&devmode, 0, sizeof(DEVMODEW));
1666 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1667 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1668 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1669 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1670 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1671 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1673 /* Make popup window */
1674 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1675 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1676 *(pPresentationParameters->BackBufferWidth),
1677 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1679 /* For GetDisplayMode */
1680 This->ddraw_width = devmode.dmPelsWidth;
1681 This->ddraw_height = devmode.dmPelsHeight;
1682 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1686 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1687 * then the corresponding dimension of the client area of the hDeviceWindow
1688 * (or the focus window, if hDeviceWindow is NULL) is taken.
1689 **********************/
1691 if (*(pPresentationParameters->Windowed) &&
1692 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1693 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1696 GetClientRect(object->win_handle, &Rect);
1698 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1699 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1700 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1702 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1703 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1704 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1708 /*********************
1709 * finish off parameter initialization
1710 *******************/
1712 /* Put the correct figures in the presentation parameters */
1713 TRACE("Copying across presentation parameters\n");
1714 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1715 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1716 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1717 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1718 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1719 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1720 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1721 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1722 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1723 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1724 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1725 object->presentParms.Flags = *(pPresentationParameters->Flags);
1726 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1727 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1730 /*********************
1731 * Create the back, front and stencil buffers
1732 *******************/
1734 TRACE("calling rendertarget CB\n");
1735 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1737 object->presentParms.BackBufferWidth,
1738 object->presentParms.BackBufferHeight,
1739 object->presentParms.BackBufferFormat,
1740 object->presentParms.MultiSampleType,
1741 object->presentParms.MultiSampleQuality,
1742 TRUE /* Lockable */,
1743 &object->frontBuffer,
1744 NULL /* pShared (always null)*/);
1745 if (object->frontBuffer != NULL)
1746 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1748 if(object->presentParms.BackBufferCount > 0) {
1751 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1752 if(!object->backBuffer) {
1753 ERR("Out of memory\n");
1755 if (object->frontBuffer) {
1756 IUnknown *bufferParent;
1757 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1758 IUnknown_Release(bufferParent); /* once for the get parent */
1759 if (IUnknown_Release(bufferParent) > 0) {
1760 FIXME("(%p) Something's still holding the front buffer\n",This);
1763 HeapFree(GetProcessHeap(), 0, object);
1764 return E_OUTOFMEMORY;
1767 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1768 TRACE("calling rendertarget CB\n");
1769 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1771 object->presentParms.BackBufferWidth,
1772 object->presentParms.BackBufferHeight,
1773 object->presentParms.BackBufferFormat,
1774 object->presentParms.MultiSampleType,
1775 object->presentParms.MultiSampleQuality,
1776 TRUE /* Lockable */,
1777 &object->backBuffer[i],
1778 NULL /* pShared (always null)*/);
1779 if(hr == WINED3D_OK && object->backBuffer[i]) {
1780 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1786 object->backBuffer = NULL;
1789 if (object->backBuffer != NULL) {
1791 glDrawBuffer(GL_BACK);
1792 checkGLcall("glDrawBuffer(GL_BACK)");
1795 /* Single buffering - draw to front buffer */
1797 glDrawBuffer(GL_FRONT);
1798 checkGLcall("glDrawBuffer(GL_FRONT)");
1802 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1803 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1804 TRACE("Creating depth stencil buffer\n");
1805 if (This->depthStencilBuffer == NULL ) {
1806 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1808 object->presentParms.BackBufferWidth,
1809 object->presentParms.BackBufferHeight,
1810 object->presentParms.AutoDepthStencilFormat,
1811 object->presentParms.MultiSampleType,
1812 object->presentParms.MultiSampleQuality,
1813 FALSE /* FIXME: Discard */,
1814 &This->depthStencilBuffer,
1815 NULL /* pShared (always null)*/ );
1816 if (This->depthStencilBuffer != NULL)
1817 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1820 /** TODO: A check on width, height and multisample types
1821 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1822 ****************************/
1823 object->wantsDepthStencilBuffer = TRUE;
1825 object->wantsDepthStencilBuffer = FALSE;
1828 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1831 /*********************
1832 * init the default renderTarget management
1833 *******************/
1834 object->drawable = object->win;
1835 object->render_ctx = object->glCtx;
1837 if (hr == WINED3D_OK) {
1838 /*********************
1839 * Setup some defaults and clear down the buffers
1840 *******************/
1842 /** save current context and drawable **/
1843 oldContext = glXGetCurrentContext();
1844 oldDrawable = glXGetCurrentDrawable();
1846 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1847 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1848 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1850 checkGLcall("glXMakeCurrent");
1852 TRACE("Setting up the screen\n");
1853 /* Clear the screen */
1854 glClearColor(1.0, 0.0, 0.0, 0.0);
1855 checkGLcall("glClearColor");
1858 glClearStencil(0xffff);
1860 checkGLcall("glClear");
1862 glColor3f(1.0, 1.0, 1.0);
1863 checkGLcall("glColor3f");
1865 glEnable(GL_LIGHTING);
1866 checkGLcall("glEnable");
1868 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1869 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1871 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1872 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1874 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1875 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1877 /* switch back to the original context (if there was one)*/
1878 if (This->swapchains) {
1879 /** TODO: restore the context and drawable **/
1880 glXMakeCurrent(object->display, oldDrawable, oldContext);
1883 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1884 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1885 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1886 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1887 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1891 TRACE("Set swapchain to %p\n", object);
1892 } else { /* something went wrong so clean up */
1893 IUnknown* bufferParent;
1894 if (object->frontBuffer) {
1896 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1897 IUnknown_Release(bufferParent); /* once for the get parent */
1898 if (IUnknown_Release(bufferParent) > 0) {
1899 FIXME("(%p) Something's still holding the front buffer\n",This);
1902 if (object->backBuffer) {
1904 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1905 if(object->backBuffer[i]) {
1906 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1907 IUnknown_Release(bufferParent); /* once for the get parent */
1908 if (IUnknown_Release(bufferParent) > 0) {
1909 FIXME("(%p) Something's still holding the back buffer\n",This);
1913 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1914 object->backBuffer = NULL;
1916 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1917 /* Clean up the context */
1918 /* check that we are the current context first (we shouldn't be though!) */
1919 if (object->glCtx != 0) {
1920 if(glXGetCurrentContext() == object->glCtx) {
1921 glXMakeCurrent(object->display, None, NULL);
1923 glXDestroyContext(object->display, object->glCtx);
1925 HeapFree(GetProcessHeap(), 0, object);
1932 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1933 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1935 TRACE("(%p)\n", This);
1937 return This->NumberOfSwapChains;
1940 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1942 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1944 if(iSwapChain < This->NumberOfSwapChains) {
1945 *pSwapChain = This->swapchains[iSwapChain];
1946 IWineD3DSwapChain_AddRef(*pSwapChain);
1947 TRACE("(%p) returning %p\n", This, *pSwapChain);
1950 TRACE("Swapchain out of range\n");
1952 return WINED3DERR_INVALIDCALL;
1957 * Vertex Declaration
1959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1961 IWineD3DVertexDeclarationImpl *object = NULL;
1962 HRESULT hr = WINED3D_OK;
1963 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1964 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1967 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1972 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1975 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1976 HRESULT hr = WINED3D_OK;
1977 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1978 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1980 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1982 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1983 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1984 if (pDeclaration != NULL) {
1985 IWineD3DVertexDeclaration *vertexDeclaration;
1986 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1987 if (WINED3D_OK == hr) {
1988 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1989 object->vertexDeclaration = vertexDeclaration;
1991 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1992 IWineD3DVertexShader_Release(*ppVertexShader);
1993 return WINED3DERR_INVALIDCALL;
1997 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1999 if (WINED3D_OK != hr) {
2000 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
2001 IWineD3DVertexShader_Release(*ppVertexShader);
2002 return WINED3DERR_INVALIDCALL;
2005 #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. */
2006 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
2017 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2019 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2020 HRESULT hr = WINED3D_OK;
2022 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2023 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2024 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2025 if (WINED3D_OK == hr) {
2026 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2028 WARN("(%p) : Failed to create pixel shader\n", This);
2034 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2036 IWineD3DPaletteImpl *object;
2038 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2040 /* Create the new object */
2041 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2043 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2044 return E_OUTOFMEMORY;
2047 object->lpVtbl = &IWineD3DPalette_Vtbl;
2049 object->Flags = Flags;
2050 object->parent = Parent;
2051 object->wineD3DDevice = This;
2052 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2054 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2057 HeapFree( GetProcessHeap(), 0, object);
2058 return E_OUTOFMEMORY;
2061 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2063 IWineD3DPalette_Release((IWineD3DPalette *) object);
2067 *Palette = (IWineD3DPalette *) object;
2072 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2074 IWineD3DSwapChainImpl *swapchain;
2077 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2078 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2080 /* TODO: Test if OpenGL is compiled in and loaded */
2082 /* Setup the implicit swapchain */
2083 TRACE("Creating implicit swapchain\n");
2084 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2085 WARN("Failed to create implicit swapchain\n");
2086 return WINED3DERR_INVALIDCALL;
2089 This->NumberOfSwapChains = 1;
2090 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2091 if(!This->swapchains) {
2092 ERR("Out of memory!\n");
2093 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2094 return E_OUTOFMEMORY;
2096 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2098 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2099 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2100 This->render_targets[0] = swapchain->backBuffer[0];
2103 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2104 This->render_targets[0] = swapchain->frontBuffer;
2106 IWineD3DSurface_AddRef(This->render_targets[0]);
2107 /* Depth Stencil support */
2108 This->stencilBufferTarget = This->depthStencilBuffer;
2109 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2110 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
2112 if (NULL != This->stencilBufferTarget) {
2113 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2116 /* Set up some starting GL setup */
2119 * Initialize openGL extension related variables
2120 * with Default values
2123 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2124 /* Setup all the devices defaults */
2125 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2127 IWineD3DImpl_CheckGraphicsMemory();
2131 /* Initialize our list of GLSL programs */
2132 list_init(&This->glsl_shader_progs);
2134 { /* Set a default viewport */
2138 vp.Width = *(pPresentationParameters->BackBufferWidth);
2139 vp.Height = *(pPresentationParameters->BackBufferHeight);
2142 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2145 /* Initialize the current view state */
2146 This->modelview_valid = 1;
2147 This->proj_valid = 0;
2148 This->view_ident = 1;
2149 This->last_was_rhw = 0;
2150 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2151 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2153 /* Clear the screen */
2154 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2156 /* Mark all states dirty. The Setters will not mark a state dirty when the new value is equal to the old value
2157 * This might create a problem in 2 situations:
2158 * ->The D3D default value is 0, but the opengl default value is something else
2159 * ->D3D7 unintialized D3D and reinitializes it. This way the context is destroyed, be the stateblock unchanged
2161 for(state = 0; state <= STATE_HIGHEST; state++) {
2162 IWineD3DDeviceImpl_MarkStateDirty(This, state);
2165 This->d3d_initialized = TRUE;
2169 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2173 TRACE("(%p)\n", This);
2175 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2177 /* Delete the mouse cursor texture */
2178 if(This->cursorTexture) {
2180 glDeleteTextures(1, &This->cursorTexture);
2182 This->cursorTexture = 0;
2185 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2186 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2189 /* Release the buffers (with sanity checks)*/
2190 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2191 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2192 if(This->depthStencilBuffer != This->stencilBufferTarget)
2193 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2195 This->stencilBufferTarget = NULL;
2197 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2198 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2199 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2201 TRACE("Setting rendertarget to NULL\n");
2202 This->render_targets[0] = NULL;
2204 if (This->depthStencilBuffer) {
2205 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2206 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2208 This->depthStencilBuffer = NULL;
2211 for(i=0; i < This->NumberOfSwapChains; i++) {
2212 TRACE("Releasing the implicit swapchain %d\n", i);
2213 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2214 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2218 HeapFree(GetProcessHeap(), 0, This->swapchains);
2219 This->swapchains = NULL;
2220 This->NumberOfSwapChains = 0;
2222 This->d3d_initialized = FALSE;
2226 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2228 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2230 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2231 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2232 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2235 This->ddraw_fullscreen = fullscreen;
2238 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2243 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2245 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2247 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2248 /* Ignore some modes if a description was passed */
2249 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2250 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2251 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2253 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2255 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2262 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2266 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2269 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2271 /* Resize the screen even without a window:
2272 * The app could have unset it with SetCooperativeLevel, but not called
2273 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2274 * but we don't have any hwnd
2277 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2278 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2279 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2280 devmode.dmPelsWidth = pMode->Width;
2281 devmode.dmPelsHeight = pMode->Height;
2283 devmode.dmDisplayFrequency = pMode->RefreshRate;
2284 if (pMode->RefreshRate != 0) {
2285 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2288 /* Only change the mode if necessary */
2289 if( (This->ddraw_width == pMode->Width) &&
2290 (This->ddraw_height == pMode->Height) &&
2291 (This->ddraw_format == pMode->Format) &&
2292 (pMode->RefreshRate == 0) ) {
2296 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2297 if (ret != DISP_CHANGE_SUCCESSFUL) {
2298 if(devmode.dmDisplayFrequency != 0) {
2299 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2300 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2301 devmode.dmDisplayFrequency = 0;
2302 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2304 if(ret != DISP_CHANGE_SUCCESSFUL) {
2305 return DDERR_INVALIDMODE;
2309 /* Store the new values */
2310 This->ddraw_width = pMode->Width;
2311 This->ddraw_height = pMode->Height;
2312 This->ddraw_format = pMode->Format;
2314 /* Only do this with a window of course */
2315 if(This->ddraw_window)
2316 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2318 /* And finally clip mouse to our screen */
2319 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2320 ClipCursor(&clip_rc);
2325 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2327 *ppD3D= This->wineD3D;
2328 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2329 IWineD3D_AddRef(*ppD3D);
2333 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2334 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2335 * into the video ram as possible and seeing how many fit
2336 * you can also get the correct initial value from nvidia and ATI's driver via X
2337 * texture memory is video memory + AGP memory
2338 *******************/
2339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2340 static BOOL showfixmes = TRUE;
2342 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2343 (wined3d_settings.emulated_textureram/(1024*1024)),
2344 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2347 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2348 (wined3d_settings.emulated_textureram/(1024*1024)),
2349 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2350 /* return simulated texture memory left */
2351 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2359 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2361 HRESULT hr = WINED3D_OK;
2363 /* Update the current state block */
2364 This->updateStateBlock->fvf = fvf;
2365 This->updateStateBlock->changed.fvf = TRUE;
2366 This->updateStateBlock->set.fvf = TRUE;
2368 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2373 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2376 *pfvf = This->stateBlock->fvf;
2381 * Get / Set Stream Source
2383 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2385 IWineD3DVertexBuffer *oldSrc;
2387 /**TODO: instance and index data, see
2388 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2390 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2393 /* D3d9 only, but shouldn't hurt d3d8 */
2396 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2398 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2399 FIXME("stream index data not supported\n");
2401 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2402 FIXME("stream instance data not supported\n");
2406 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2408 if (StreamNumber >= MAX_STREAMS) {
2409 WARN("Stream out of range %d\n", StreamNumber);
2410 return WINED3DERR_INVALIDCALL;
2413 oldSrc = This->stateBlock->streamSource[StreamNumber];
2414 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2416 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2417 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2418 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2419 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2420 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2421 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2423 /* Handle recording of state blocks */
2424 if (This->isRecordingState) {
2425 TRACE("Recording... not performing anything\n");
2429 /* Same stream object: no action */
2430 if (oldSrc == pStreamData)
2433 /* Need to do a getParent and pass the reffs up */
2434 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2435 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2436 so for now, just count internally */
2437 if (pStreamData != NULL) {
2438 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2439 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2440 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2442 vbImpl->stream = StreamNumber;
2443 vbImpl->Flags |= VBFLAG_STREAM;
2444 IWineD3DVertexBuffer_AddRef(pStreamData);
2446 if (oldSrc != NULL) {
2447 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2448 IWineD3DVertexBuffer_Release(oldSrc);
2454 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2459 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2462 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2464 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2465 FIXME("stream index data not supported\n");
2467 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2468 FIXME("stream instance data not supported\n");
2472 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2474 if (StreamNumber >= MAX_STREAMS) {
2475 WARN("Stream out of range %d\n", StreamNumber);
2476 return WINED3DERR_INVALIDCALL;
2478 *pStream = This->stateBlock->streamSource[StreamNumber];
2479 *pStride = This->stateBlock->streamStride[StreamNumber];
2481 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2484 if (*pStream == NULL) {
2485 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2486 return WINED3DERR_INVALIDCALL;
2489 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2493 /*Should be quite easy, just an extension of vertexdata
2495 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2497 The divider is a bit odd though
2499 VertexOffset = StartVertex / Divider * StreamStride +
2500 VertexIndex / Divider * StreamStride + StreamOffset
2503 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2507 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2509 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2510 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2511 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2513 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2514 FIXME("Stream indexing not fully supported\n");
2520 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2524 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2526 TRACE("(%p) : returning %d\n", This, *Divider);
2532 * Get / Set & Multiply Transform
2534 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 /* Most of this routine, comments included copied from ddraw tree initially: */
2538 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2540 /* Handle recording of state blocks */
2541 if (This->isRecordingState) {
2542 TRACE("Recording... not performing anything\n");
2543 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2544 This->updateStateBlock->set.transform[d3dts] = TRUE;
2545 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2550 * If the new matrix is the same as the current one,
2551 * we cut off any further processing. this seems to be a reasonable
2552 * optimization because as was noticed, some apps (warcraft3 for example)
2553 * tend towards setting the same matrix repeatedly for some reason.
2555 * From here on we assume that the new matrix is different, wherever it matters.
2557 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2558 TRACE("The app is setting the same matrix over again\n");
2561 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2565 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2566 where ViewMat = Camera space, WorldMat = world space.
2568 In OpenGL, camera and world space is combined into GL_MODELVIEW
2569 matrix. The Projection matrix stay projection matrix.
2572 /* Capture the times we can just ignore the change for now */
2573 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2574 This->modelview_valid = FALSE;
2577 } else if (d3dts == WINED3DTS_PROJECTION) {
2578 This->proj_valid = FALSE;
2581 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2582 /* Indexed Vertex Blending Matrices 256 -> 511 */
2583 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2584 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2588 /* Now we really are going to have to change a matrix */
2591 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2592 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2593 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2596 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2597 * NOTE: We have to reset the positions even if the light/plane is not currently
2598 * enabled, since the call to enable it will not reset the position.
2599 * NOTE2: Apparently texture transforms do NOT need reapplying
2602 PLIGHTINFOEL *lightChain = NULL;
2603 This->modelview_valid = FALSE;
2604 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2606 glMatrixMode(GL_MODELVIEW);
2607 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2609 glLoadMatrixf((const float *)lpmatrix);
2610 checkGLcall("glLoadMatrixf(...)");
2613 lightChain = This->stateBlock->lights;
2614 while (lightChain && lightChain->glIndex != -1) {
2615 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2616 checkGLcall("glLightfv posn");
2617 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2618 checkGLcall("glLightfv dirn");
2619 lightChain = lightChain->next;
2622 /* Reset Clipping Planes if clipping is enabled */
2623 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2624 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2625 checkGLcall("glClipPlane");
2629 } else { /* What was requested!?? */
2630 WARN("invalid matrix specified: %i\n", d3dts);
2633 /* Release lock, all done */
2638 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2641 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2645 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2646 WINED3DMATRIX *mat = NULL;
2649 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2650 * below means it will be recorded in a state block change, but it
2651 * works regardless where it is recorded.
2652 * If this is found to be wrong, change to StateBlock.
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2657 if (State < HIGHEST_TRANSFORMSTATE)
2659 mat = &This->updateStateBlock->transforms[State];
2661 FIXME("Unhandled transform state!!\n");
2664 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2666 /* Apply change via set transform - will reapply to eg. lights this way */
2667 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2673 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2674 you can reference any indexes you want as long as that number max are enabled at any
2675 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2676 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2677 but when recording, just build a chain pretty much of commands to be replayed. */
2679 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2681 PLIGHTINFOEL *object, *temp;
2683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2684 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2686 /* If recording state block, just add to end of lights chain */
2687 if (This->isRecordingState) {
2688 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2689 if (NULL == object) {
2690 return WINED3DERR_OUTOFVIDEOMEMORY;
2692 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2693 object->OriginalIndex = Index;
2694 object->glIndex = -1;
2695 object->changed = TRUE;
2697 /* Add to the END of the chain of lights changes to be replayed */
2698 if (This->updateStateBlock->lights == NULL) {
2699 This->updateStateBlock->lights = object;
2701 temp = This->updateStateBlock->lights;
2702 while (temp->next != NULL) temp=temp->next;
2703 temp->next = object;
2705 TRACE("Recording... not performing anything more\n");
2709 /* Ok, not recording any longer so do real work */
2710 object = This->stateBlock->lights;
2711 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2713 /* If we didn't find it in the list of lights, time to add it */
2714 if (object == NULL) {
2715 PLIGHTINFOEL *insertAt,*prevPos;
2717 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2718 if (NULL == object) {
2719 return WINED3DERR_OUTOFVIDEOMEMORY;
2721 object->OriginalIndex = Index;
2722 object->glIndex = -1;
2724 /* Add it to the front of list with the idea that lights will be changed as needed
2725 BUT after any lights currently assigned GL indexes */
2726 insertAt = This->stateBlock->lights;
2728 while (insertAt != NULL && insertAt->glIndex != -1) {
2730 insertAt = insertAt->next;
2733 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2734 This->stateBlock->lights = object;
2735 } else if (insertAt == NULL) { /* End of list */
2736 prevPos->next = object;
2737 object->prev = prevPos;
2738 } else { /* Middle of chain */
2739 if (prevPos == NULL) {
2740 This->stateBlock->lights = object;
2742 prevPos->next = object;
2744 object->prev = prevPos;
2745 object->next = insertAt;
2746 insertAt->prev = object;
2750 /* Initialize the object */
2751 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,
2752 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2753 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2754 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2755 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2756 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2757 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2759 /* Save away the information */
2760 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2762 switch (pLight->Type) {
2763 case WINED3DLIGHT_POINT:
2765 object->lightPosn[0] = pLight->Position.x;
2766 object->lightPosn[1] = pLight->Position.y;
2767 object->lightPosn[2] = pLight->Position.z;
2768 object->lightPosn[3] = 1.0f;
2769 object->cutoff = 180.0f;
2773 case WINED3DLIGHT_DIRECTIONAL:
2775 object->lightPosn[0] = -pLight->Direction.x;
2776 object->lightPosn[1] = -pLight->Direction.y;
2777 object->lightPosn[2] = -pLight->Direction.z;
2778 object->lightPosn[3] = 0.0;
2779 object->exponent = 0.0f;
2780 object->cutoff = 180.0f;
2783 case WINED3DLIGHT_SPOT:
2785 object->lightPosn[0] = pLight->Position.x;
2786 object->lightPosn[1] = pLight->Position.y;
2787 object->lightPosn[2] = pLight->Position.z;
2788 object->lightPosn[3] = 1.0;
2791 object->lightDirn[0] = pLight->Direction.x;
2792 object->lightDirn[1] = pLight->Direction.y;
2793 object->lightDirn[2] = pLight->Direction.z;
2794 object->lightDirn[3] = 1.0;
2797 * opengl-ish and d3d-ish spot lights use too different models for the
2798 * light "intensity" as a function of the angle towards the main light direction,
2799 * so we only can approximate very roughly.
2800 * however spot lights are rather rarely used in games (if ever used at all).
2801 * furthermore if still used, probably nobody pays attention to such details.
2803 if (pLight->Falloff == 0) {
2806 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2808 if (rho < 0.0001) rho = 0.0001f;
2809 object->exponent = -0.3/log(cos(rho/2));
2810 if (object->exponent > 128.0) {
2811 object->exponent = 128.0;
2813 object->cutoff = pLight->Phi*90/M_PI;
2819 FIXME("Unrecognized light type %d\n", pLight->Type);
2822 /* Update the live definitions if the light is currently assigned a glIndex */
2823 if (object->glIndex != -1) {
2824 setup_light(iface, object->glIndex, object);
2829 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2830 PLIGHTINFOEL *lightInfo = NULL;
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2834 /* Locate the light in the live lights */
2835 lightInfo = This->stateBlock->lights;
2836 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2838 if (lightInfo == NULL) {
2839 TRACE("Light information requested but light not defined\n");
2840 return WINED3DERR_INVALIDCALL;
2843 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2848 * Get / Set Light Enable
2849 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2851 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2852 PLIGHTINFOEL *lightInfo = NULL;
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2856 /* Tests show true = 128...not clear why */
2858 Enable = Enable? 128: 0;
2860 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2861 if (This->isRecordingState) {
2862 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2863 if (NULL == lightInfo) {
2864 return WINED3DERR_OUTOFVIDEOMEMORY;
2866 lightInfo->OriginalIndex = Index;
2867 lightInfo->glIndex = -1;
2868 lightInfo->enabledChanged = TRUE;
2869 lightInfo->lightEnabled = Enable;
2871 /* Add to the END of the chain of lights changes to be replayed */
2872 if (This->updateStateBlock->lights == NULL) {
2873 This->updateStateBlock->lights = lightInfo;
2875 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2876 while (temp->next != NULL) temp=temp->next;
2877 temp->next = lightInfo;
2879 TRACE("Recording... not performing anything more\n");
2883 /* Not recording... So, locate the light in the live lights */
2884 lightInfo = This->stateBlock->lights;
2885 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2887 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2888 if (lightInfo == NULL) {
2890 TRACE("Light enabled requested but light not defined, so defining one!\n");
2891 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2893 /* Search for it again! Should be fairly quick as near head of list */
2894 lightInfo = This->stateBlock->lights;
2895 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2896 if (lightInfo == NULL) {
2897 FIXME("Adding default lights has failed dismally\n");
2898 return WINED3DERR_INVALIDCALL;
2902 /* OK, we now have a light... */
2905 /* If we are disabling it, check it was enabled, and
2906 still only do something if it has assigned a glIndex (which it should have!) */
2907 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2908 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2910 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2911 checkGLcall("glDisable GL_LIGHT0+Index");
2914 TRACE("Nothing to do as light was not enabled\n");
2916 lightInfo->lightEnabled = Enable;
2919 /* We are enabling it. If it is enabled, it's really simple */
2920 if (lightInfo->lightEnabled) {
2922 TRACE("Nothing to do as light was enabled\n");
2924 /* If it already has a glIndex, it's still simple */
2925 } else if (lightInfo->glIndex != -1) {
2926 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2927 lightInfo->lightEnabled = Enable;
2929 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2930 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2933 /* Otherwise got to find space - lights are ordered gl indexes first */
2935 PLIGHTINFOEL *bsf = NULL;
2936 PLIGHTINFOEL *pos = This->stateBlock->lights;
2937 PLIGHTINFOEL *prev = NULL;
2941 /* Try to minimize changes as much as possible */
2942 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2944 /* Try to remember which index can be replaced if necessary */
2945 if (bsf==NULL && !pos->lightEnabled) {
2946 /* Found a light we can replace, save as best replacement */
2950 /* Step to next space */
2956 /* If we have too many active lights, fail the call */
2957 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2958 FIXME("Program requests too many concurrent lights\n");
2959 return WINED3DERR_INVALIDCALL;
2961 /* If we have allocated all lights, but not all are enabled,
2962 reuse one which is not enabled */
2963 } else if (Index == This->maxConcurrentLights) {
2964 /* use bsf - Simply swap the new light and the BSF one */
2965 PLIGHTINFOEL *bsfNext = bsf->next;
2966 PLIGHTINFOEL *bsfPrev = bsf->prev;
2969 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2970 if (bsf->prev != NULL) {
2971 bsf->prev->next = lightInfo;
2973 This->stateBlock->lights = lightInfo;
2976 /* If not side by side, lots of chains to update */
2977 if (bsf->next != lightInfo) {
2978 lightInfo->prev->next = bsf;
2979 bsf->next->prev = lightInfo;
2980 bsf->next = lightInfo->next;
2981 bsf->prev = lightInfo->prev;
2982 lightInfo->next = bsfNext;
2983 lightInfo->prev = bsfPrev;
2987 bsf->prev = lightInfo;
2988 bsf->next = lightInfo->next;
2989 lightInfo->next = bsf;
2990 lightInfo->prev = bsfPrev;
2995 glIndex = bsf->glIndex;
2997 lightInfo->glIndex = glIndex;
2998 lightInfo->lightEnabled = Enable;
3000 /* Finally set up the light in gl itself */
3001 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
3003 setup_light(iface, glIndex, lightInfo);
3004 glEnable(GL_LIGHT0 + glIndex);
3005 checkGLcall("glEnable GL_LIGHT0 new setup");
3008 /* If we reached the end of the allocated lights, with space in the
3009 gl lights, setup a new light */
3010 } else if (pos->glIndex == -1) {
3012 /* We reached the end of the allocated gl lights, so already
3013 know the index of the next one! */
3015 lightInfo->glIndex = glIndex;
3016 lightInfo->lightEnabled = Enable;
3018 /* In an ideal world, it's already in the right place */
3019 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
3020 /* No need to move it */
3022 /* Remove this light from the list */
3023 lightInfo->prev->next = lightInfo->next;
3024 if (lightInfo->next != NULL) {
3025 lightInfo->next->prev = lightInfo->prev;
3028 /* Add in at appropriate place (inbetween prev and pos) */
3029 lightInfo->prev = prev;
3030 lightInfo->next = pos;
3032 This->stateBlock->lights = lightInfo;
3034 prev->next = lightInfo;
3037 pos->prev = lightInfo;
3041 /* Finally set up the light in gl itself */
3042 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3044 setup_light(iface, glIndex, lightInfo);
3045 glEnable(GL_LIGHT0 + glIndex);
3046 checkGLcall("glEnable GL_LIGHT0 new setup");
3055 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3057 PLIGHTINFOEL *lightInfo = NULL;
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 TRACE("(%p) : for idx(%d)\n", This, Index);
3061 /* Locate the light in the live lights */
3062 lightInfo = This->stateBlock->lights;
3063 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3065 if (lightInfo == NULL) {
3066 TRACE("Light enabled state requested but light not defined\n");
3067 return WINED3DERR_INVALIDCALL;
3069 *pEnable = lightInfo->lightEnabled;
3074 * Get / Set Clip Planes
3076 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3080 /* Validate Index */
3081 if (Index >= GL_LIMITS(clipplanes)) {
3082 TRACE("Application has requested clipplane this device doesn't support\n");
3083 return WINED3DERR_INVALIDCALL;
3086 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3087 This->updateStateBlock->set.clipplane[Index] = TRUE;
3088 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3089 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3090 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3091 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3093 /* Handle recording of state blocks */
3094 if (This->isRecordingState) {
3095 TRACE("Recording... not performing anything\n");
3103 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3104 glMatrixMode(GL_MODELVIEW);
3106 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3108 TRACE("Clipplane [%f,%f,%f,%f]\n",
3109 This->updateStateBlock->clipplane[Index][0],
3110 This->updateStateBlock->clipplane[Index][1],
3111 This->updateStateBlock->clipplane[Index][2],
3112 This->updateStateBlock->clipplane[Index][3]);
3113 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3114 checkGLcall("glClipPlane");
3122 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 TRACE("(%p) : for idx %d\n", This, Index);
3126 /* Validate Index */
3127 if (Index >= GL_LIMITS(clipplanes)) {
3128 TRACE("Application has requested clipplane this device doesn't support\n");
3129 return WINED3DERR_INVALIDCALL;
3132 pPlane[0] = This->stateBlock->clipplane[Index][0];
3133 pPlane[1] = This->stateBlock->clipplane[Index][1];
3134 pPlane[2] = This->stateBlock->clipplane[Index][2];
3135 pPlane[3] = This->stateBlock->clipplane[Index][3];
3140 * Get / Set Clip Plane Status
3141 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 FIXME("(%p) : stub\n", This);
3146 if (NULL == pClipStatus) {
3147 return WINED3DERR_INVALIDCALL;
3149 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3150 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3154 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 FIXME("(%p) : stub\n", This);
3157 if (NULL == pClipStatus) {
3158 return WINED3DERR_INVALIDCALL;
3160 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3161 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3166 * Get / Set Material
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 This->updateStateBlock->changed.material = TRUE;
3172 This->updateStateBlock->set.material = TRUE;
3173 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3175 /* Handle recording of state blocks */
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3182 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3183 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3184 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3185 pMaterial->Ambient.b, pMaterial->Ambient.a);
3186 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3187 pMaterial->Specular.b, pMaterial->Specular.a);
3188 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3189 pMaterial->Emissive.b, pMaterial->Emissive.a);
3190 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3192 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3193 checkGLcall("glMaterialfv(GL_AMBIENT)");
3194 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3195 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3197 /* Only change material color if specular is enabled, otherwise it is set to black */
3198 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3199 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3200 checkGLcall("glMaterialfv(GL_SPECULAR");
3202 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3203 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3204 checkGLcall("glMaterialfv(GL_SPECULAR");
3206 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3207 checkGLcall("glMaterialfv(GL_EMISSION)");
3208 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3209 checkGLcall("glMaterialf(GL_SHININESS");
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3218 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3219 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3220 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3221 pMaterial->Ambient.b, pMaterial->Ambient.a);
3222 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3223 pMaterial->Specular.b, pMaterial->Specular.a);
3224 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3225 pMaterial->Emissive.b, pMaterial->Emissive.a);
3226 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3234 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3235 UINT BaseVertexIndex) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 IWineD3DIndexBuffer *oldIdxs;
3239 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3240 oldIdxs = This->updateStateBlock->pIndexData;
3242 This->updateStateBlock->changed.indices = TRUE;
3243 This->updateStateBlock->set.indices = TRUE;
3244 This->updateStateBlock->pIndexData = pIndexData;
3245 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3247 /* Handle recording of state blocks */
3248 if (This->isRecordingState) {
3249 TRACE("Recording... not performing anything\n");
3253 if (NULL != pIndexData) {
3254 IWineD3DIndexBuffer_AddRef(pIndexData);
3256 if (NULL != oldIdxs) {
3257 IWineD3DIndexBuffer_Release(oldIdxs);
3262 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 *ppIndexData = This->stateBlock->pIndexData;
3267 /* up ref count on ppindexdata */
3269 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3270 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3271 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3273 TRACE("(%p) No index data set\n", This);
3275 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3281 * Get / Set Viewports
3283 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 TRACE("(%p)\n", This);
3287 This->updateStateBlock->changed.viewport = TRUE;
3288 This->updateStateBlock->set.viewport = TRUE;
3289 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3291 /* Handle recording of state blocks */
3292 if (This->isRecordingState) {
3293 TRACE("Recording... not performing anything\n");
3296 This->viewport_changed = TRUE;
3300 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3301 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3303 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3304 checkGLcall("glDepthRange");
3305 /* Note: GL requires lower left, DirectX supplies upper left */
3306 /* TODO: replace usage of renderTarget with context management */
3307 glViewport(pViewport->X,
3308 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3309 pViewport->Width, pViewport->Height);
3311 checkGLcall("glViewport");
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 TRACE("(%p)\n", This);
3322 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3327 * Get / Set Render States
3328 * TODO: Verify against dx9 definitions
3330 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 DWORD oldValue = This->stateBlock->renderState[State];
3335 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3337 This->updateStateBlock->changed.renderState[State] = TRUE;
3338 This->updateStateBlock->set.renderState[State] = TRUE;
3339 This->updateStateBlock->renderState[State] = Value;
3341 /* Handle recording of state blocks */
3342 if (This->isRecordingState) {
3343 TRACE("Recording... not performing anything\n");
3347 /* Compared here and not before the assignment to allow proper stateblock recording */
3348 if(Value == oldValue) {
3349 TRACE("Application is setting the old value over, nothing to do\n");
3351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3357 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3360 *pValue = This->stateBlock->renderState[State];
3365 * Get / Set Sampler States
3366 * TODO: Verify against dx9 definitions
3369 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 * SetSampler is designed to allow for more than the standard up to 8 textures
3373 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3374 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3376 * http://developer.nvidia.com/object/General_FAQ.html#t6
3378 * There are two new settings for GForce
3380 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3381 * and the texture one:
3382 * GL_MAX_TEXTURE_COORDS_ARB.
3383 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3385 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
3386 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
3387 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
3388 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
3389 return WINED3DERR_INVALIDCALL;
3392 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
3393 debug_d3dsamplerstate(Type), Type, Value);
3394 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3395 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
3396 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3398 /* Handle recording of state blocks */
3399 if (This->isRecordingState) {
3400 TRACE("Recording... not performing anything\n");
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3409 /** TODO: check that sampler is in range **/
3410 *Value = This->stateBlock->samplerState[Sampler][Type];
3411 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
3416 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3421 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
3422 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
3423 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
3425 winHeight = windowRect.bottom - windowRect.top;
3426 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
3427 pRect->right - pRect->left, pRect->bottom - pRect->top);
3429 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
3430 checkGLcall("glScissor");
3436 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3438 GLint scissorBox[4];
3441 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
3442 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
3443 pRect->left = scissorBox[0];
3444 pRect->top = scissorBox[1];
3445 pRect->right = scissorBox[0] + scissorBox[2];
3446 pRect->bottom = scissorBox[1] + scissorBox[3];
3447 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3452 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3454 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3456 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3458 This->updateStateBlock->vertexDecl = pDecl;
3459 This->updateStateBlock->changed.vertexDecl = TRUE;
3460 This->updateStateBlock->set.vertexDecl = TRUE;
3462 if (This->isRecordingState) {
3463 TRACE("Recording... not performing anything\n");
3466 if (NULL != pDecl) {
3467 IWineD3DVertexDeclaration_AddRef(pDecl);
3469 if (NULL != oldDecl) {
3470 IWineD3DVertexDeclaration_Release(oldDecl);
3475 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3478 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3480 *ppDecl = This->stateBlock->vertexDecl;
3481 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3485 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3489 This->updateStateBlock->vertexShader = pShader;
3490 This->updateStateBlock->changed.vertexShader = TRUE;
3491 This->updateStateBlock->set.vertexShader = TRUE;
3493 if (This->isRecordingState) {
3494 TRACE("Recording... not performing anything\n");
3497 if (NULL != pShader) {
3498 IWineD3DVertexShader_AddRef(pShader);
3500 if (NULL != oldShader) {
3501 IWineD3DVertexShader_Release(oldShader);
3504 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3506 * TODO: merge HAL shaders context switching from prototype
3511 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 if (NULL == ppShader) {
3515 return WINED3DERR_INVALIDCALL;
3517 *ppShader = This->stateBlock->vertexShader;
3518 if( NULL != *ppShader)
3519 IWineD3DVertexShader_AddRef(*ppShader);
3521 TRACE("(%p) : returning %p\n", This, *ppShader);
3525 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3526 IWineD3DDevice *iface,
3528 CONST BOOL *srcData,
3531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3532 int i, cnt = min(count, MAX_CONST_B - start);
3534 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3535 iface, srcData, start, count);
3537 if (srcData == NULL || cnt < 0)
3538 return WINED3DERR_INVALIDCALL;
3540 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3541 for (i = 0; i < cnt; i++)
3542 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3544 for (i = start; i < cnt + start; ++i) {
3545 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3546 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3552 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3553 IWineD3DDevice *iface,
3558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3559 int cnt = min(count, MAX_CONST_B - start);
3561 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3562 iface, dstData, start, count);
3564 if (dstData == NULL || cnt < 0)
3565 return WINED3DERR_INVALIDCALL;
3567 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3571 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3572 IWineD3DDevice *iface,
3577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3578 int i, cnt = min(count, MAX_CONST_I - start);
3580 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3581 iface, srcData, start, count);
3583 if (srcData == NULL || cnt < 0)
3584 return WINED3DERR_INVALIDCALL;
3586 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3587 for (i = 0; i < cnt; i++)
3588 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3589 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3591 for (i = start; i < cnt + start; ++i) {
3592 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3593 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3599 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3600 IWineD3DDevice *iface,
3605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3606 int cnt = min(count, MAX_CONST_I - start);
3608 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3609 iface, dstData, start, count);
3611 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3612 return WINED3DERR_INVALIDCALL;
3614 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3618 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3619 IWineD3DDevice *iface,
3621 CONST float *srcData,
3624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3625 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3627 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3628 iface, srcData, start, count);
3630 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
3631 return WINED3DERR_INVALIDCALL;
3633 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3634 for (i = 0; i < cnt; i++)
3635 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3636 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3638 for (i = start; i < cnt + start; ++i) {
3639 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3640 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3642 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3643 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3645 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3651 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3652 IWineD3DDevice *iface,
3657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3658 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3660 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3661 iface, dstData, start, count);
3663 if (dstData == NULL || cnt < 0)
3664 return WINED3DERR_INVALIDCALL;
3666 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3670 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3672 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3673 This->updateStateBlock->pixelShader = pShader;
3674 This->updateStateBlock->changed.pixelShader = TRUE;
3675 This->updateStateBlock->set.pixelShader = TRUE;
3677 /* Handle recording of state blocks */
3678 if (This->isRecordingState) {
3679 TRACE("Recording... not performing anything\n");
3682 if (NULL != pShader) {
3683 IWineD3DPixelShader_AddRef(pShader);
3685 if (NULL != oldShader) {
3686 IWineD3DPixelShader_Release(oldShader);
3689 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3691 * TODO: merge HAL shaders context switching from prototype
3696 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3699 if (NULL == ppShader) {
3700 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3701 return WINED3DERR_INVALIDCALL;
3704 *ppShader = This->stateBlock->pixelShader;
3705 if (NULL != *ppShader) {
3706 IWineD3DPixelShader_AddRef(*ppShader);
3708 TRACE("(%p) : returning %p\n", This, *ppShader);
3712 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3713 IWineD3DDevice *iface,
3715 CONST BOOL *srcData,
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 int i, cnt = min(count, MAX_CONST_B - start);
3721 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3722 iface, srcData, start, count);
3724 if (srcData == NULL || cnt < 0)
3725 return WINED3DERR_INVALIDCALL;
3727 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3728 for (i = 0; i < cnt; i++)
3729 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3731 for (i = start; i < cnt + start; ++i) {
3732 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3733 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3739 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3740 IWineD3DDevice *iface,
3745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3746 int cnt = min(count, MAX_CONST_B - start);
3748 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3749 iface, dstData, start, count);
3751 if (dstData == NULL || cnt < 0)
3752 return WINED3DERR_INVALIDCALL;
3754 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3759 IWineD3DDevice *iface,
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 int i, cnt = min(count, MAX_CONST_I - start);
3767 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3768 iface, srcData, start, count);
3770 if (srcData == NULL || cnt < 0)
3771 return WINED3DERR_INVALIDCALL;
3773 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3774 for (i = 0; i < cnt; i++)
3775 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3776 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3778 for (i = start; i < cnt + start; ++i) {
3779 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3780 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3786 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3787 IWineD3DDevice *iface,
3792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3793 int cnt = min(count, MAX_CONST_I - start);
3795 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3796 iface, dstData, start, count);
3798 if (dstData == NULL || cnt < 0)
3799 return WINED3DERR_INVALIDCALL;
3801 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3805 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3806 IWineD3DDevice *iface,
3808 CONST float *srcData,
3811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3812 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3814 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3815 iface, srcData, start, count);
3817 if (srcData == NULL || cnt < 0)
3818 return WINED3DERR_INVALIDCALL;
3820 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3821 for (i = 0; i < cnt; i++)
3822 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3823 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3825 for (i = start; i < cnt + start; ++i) {
3826 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3827 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3829 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3830 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3832 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3838 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3839 IWineD3DDevice *iface,
3844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3845 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3847 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3848 iface, dstData, start, count);
3850 if (dstData == NULL || cnt < 0)
3851 return WINED3DERR_INVALIDCALL;
3853 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3857 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3859 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3860 char *dest_ptr, *dest_conv = NULL;
3862 DWORD DestFVF = dest->fvf;
3864 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3868 if (SrcFVF & WINED3DFVF_NORMAL) {
3869 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3872 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3873 ERR("Source has no position mask\n");
3874 return WINED3DERR_INVALIDCALL;
3877 /* We might access VBOs from this code, so hold the lock */
3880 if (dest->resource.allocatedMemory == NULL) {
3881 /* This may happen if we do direct locking into a vbo. Unlikely,
3882 * but theoretically possible(ddraw processvertices test)
3884 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3885 if(!dest->resource.allocatedMemory) {
3887 ERR("Out of memory\n");
3888 return E_OUTOFMEMORY;
3892 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3893 checkGLcall("glBindBufferARB");
3894 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3896 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3898 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3899 checkGLcall("glUnmapBufferARB");
3903 /* Get a pointer into the destination vbo(create one if none exists) and
3904 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3906 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3911 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3912 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3914 ERR("glMapBuffer failed\n");
3915 /* Continue without storing converted vertices */
3920 * a) WINED3DRS_CLIPPING is enabled
3921 * b) WINED3DVOP_CLIP is passed
3923 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3924 static BOOL warned = FALSE;
3926 * The clipping code is not quite correct. Some things need
3927 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3928 * so disable clipping for now.
3929 * (The graphics in Half-Life are broken, and my processvertices
3930 * test crashes with IDirect3DDevice3)
3936 FIXME("Clipping is broken and disabled for now\n");
3938 } else doClip = FALSE;
3939 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3941 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3944 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3947 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3948 WINED3DTS_PROJECTION,
3950 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3951 WINED3DTS_WORLDMATRIX(0),
3954 TRACE("View mat:\n");
3955 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); \
3956 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); \
3957 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); \
3958 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); \
3960 TRACE("Proj mat:\n");
3961 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); \
3962 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); \
3963 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); \
3964 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); \
3966 TRACE("World mat:\n");
3967 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); \
3968 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); \
3969 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); \
3970 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); \
3972 /* Get the viewport */
3973 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3974 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3975 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3977 multiply_matrix(&mat,&view_mat,&world_mat);
3978 multiply_matrix(&mat,&proj_mat,&mat);
3980 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3982 for (i = 0; i < dwCount; i+= 1) {
3983 unsigned int tex_index;
3985 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3986 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3987 /* The position first */
3989 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3991 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3993 /* Multiplication with world, view and projection matrix */
3994 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);
3995 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);
3996 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);
3997 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);
3999 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4001 /* WARNING: The following things are taken from d3d7 and were not yet checked
4002 * against d3d8 or d3d9!
4005 /* Clipping conditions: From
4006 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4008 * A vertex is clipped if it does not match the following requirements
4012 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4014 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4015 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4020 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4021 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4024 /* "Normal" viewport transformation (not clipped)
4025 * 1) The values are divided by rhw
4026 * 2) The y axis is negative, so multiply it with -1
4027 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4028 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4029 * 4) Multiply x with Width/2 and add Width/2
4030 * 5) The same for the height
4031 * 6) Add the viewpoint X and Y to the 2D coordinates and
4032 * The minimum Z value to z
4033 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4035 * Well, basically it's simply a linear transformation into viewport
4047 z *= vp.MaxZ - vp.MinZ;
4049 x += vp.Width / 2 + vp.X;
4050 y += vp.Height / 2 + vp.Y;
4055 /* That vertex got clipped
4056 * Contrary to OpenGL it is not dropped completely, it just
4057 * undergoes a different calculation.
4059 TRACE("Vertex got clipped\n");
4066 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4067 * outside of the main vertex buffer memory. That needs some more
4072 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4075 ( (float *) dest_ptr)[0] = x;
4076 ( (float *) dest_ptr)[1] = y;
4077 ( (float *) dest_ptr)[2] = z;
4078 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4080 dest_ptr += 3 * sizeof(float);
4082 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4083 dest_ptr += sizeof(float);
4088 ( (float *) dest_conv)[0] = x * w;
4089 ( (float *) dest_conv)[1] = y * w;
4090 ( (float *) dest_conv)[2] = z * w;
4091 ( (float *) dest_conv)[3] = w;
4093 dest_conv += 3 * sizeof(float);
4095 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4096 dest_conv += sizeof(float);
4100 if (DestFVF & WINED3DFVF_PSIZE) {
4101 dest_ptr += sizeof(DWORD);
4102 if(dest_conv) dest_conv += sizeof(DWORD);
4104 if (DestFVF & WINED3DFVF_NORMAL) {
4106 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4107 /* AFAIK this should go into the lighting information */
4108 FIXME("Didn't expect the destination to have a normal\n");
4109 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4111 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4115 if (DestFVF & WINED3DFVF_DIFFUSE) {
4117 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4119 static BOOL warned = FALSE;
4122 ERR("No diffuse color in source, but destination has one\n");
4126 *( (DWORD *) dest_ptr) = 0xffffffff;
4127 dest_ptr += sizeof(DWORD);
4130 *( (DWORD *) dest_conv) = 0xffffffff;
4131 dest_conv += sizeof(DWORD);
4135 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4137 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4138 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4139 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4140 dest_conv += sizeof(DWORD);
4145 if (DestFVF & WINED3DFVF_SPECULAR) {
4146 /* What's the color value in the feedback buffer? */
4148 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4150 static BOOL warned = FALSE;
4153 ERR("No specular color in source, but destination has one\n");
4157 *( (DWORD *) dest_ptr) = 0xFF000000;
4158 dest_ptr += sizeof(DWORD);
4161 *( (DWORD *) dest_conv) = 0xFF000000;
4162 dest_conv += sizeof(DWORD);
4166 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4168 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4169 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4170 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4171 dest_conv += sizeof(DWORD);
4176 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4178 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4179 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4181 ERR("No source texture, but destination requests one\n");
4182 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4183 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4186 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4188 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4195 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4196 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
4203 #undef copy_and_next
4205 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
4206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4207 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
4208 WineDirect3DVertexStridedData strided;
4209 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4212 WARN("NULL source vertex buffer\n");
4213 return WINED3DERR_INVALIDCALL;
4215 /* We don't need the source vbo because this buffer is only used as
4216 * a source for ProcessVertices. Avoid wasting resources by converting the
4217 * buffer and loading the VBO
4220 TRACE("Releasing the source vbo, it won't be needed\n");
4222 if(!SrcImpl->resource.allocatedMemory) {
4223 /* Rescue the data from the buffer */
4225 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
4226 if(!SrcImpl->resource.allocatedMemory) {
4227 ERR("Out of memory\n");
4228 return E_OUTOFMEMORY;
4232 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
4233 checkGLcall("glBindBufferARB");
4235 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4237 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
4240 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4241 checkGLcall("glUnmapBufferARB");
4246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4247 checkGLcall("glBindBufferARB");
4248 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
4249 checkGLcall("glDeleteBuffersARB");
4255 memset(&strided, 0, sizeof(strided));
4256 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
4258 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4262 * Apply / Get / Set Texture Stage States
4263 * TODO: Verify against dx9 definitions
4266 /* 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 */
4267 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
4268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4269 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
4270 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4272 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4274 /* Check that the stage is within limits */
4275 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
4276 TRACE("Attempt to access invalid texture rejected\n");
4283 case WINED3DTSS_ALPHAOP :
4284 case WINED3DTSS_COLOROP :
4285 /* nothing to do as moved to drawprim for now */
4287 case WINED3DTSS_ADDRESSW :
4288 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
4289 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
4290 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
4293 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
4294 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
4295 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
4296 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
4299 case WINED3DTSS_TEXCOORDINDEX :
4301 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
4303 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
4304 one flag, you can still specify an index value, which the system uses to
4305 determine the texture wrapping mode.
4306 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
4307 means use the vertex position (camera-space) as the input texture coordinates
4308 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
4309 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
4310 to the TEXCOORDINDEX value */
4313 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
4315 switch (Value & 0xFFFF0000) {
4316 case WINED3DTSS_TCI_PASSTHRU:
4317 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
4318 glDisable(GL_TEXTURE_GEN_S);
4319 glDisable(GL_TEXTURE_GEN_T);
4320 glDisable(GL_TEXTURE_GEN_R);
4321 glDisable(GL_TEXTURE_GEN_Q);
4322 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
4325 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
4326 /* CameraSpacePosition means use the vertex position, transformed to camera space,
4327 as the input texture coordinates for this stage's texture transformation. This
4328 equates roughly to EYE_LINEAR */
4330 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4331 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4332 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4333 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4334 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
4336 glMatrixMode(GL_MODELVIEW);
4339 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4340 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4341 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4342 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4345 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
4346 glEnable(GL_TEXTURE_GEN_S);
4347 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4348 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4349 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4350 glEnable(GL_TEXTURE_GEN_T);
4351 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4352 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4353 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4354 glEnable(GL_TEXTURE_GEN_R);
4355 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4356 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
4357 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
4361 case WINED3DTSS_TCI_CAMERASPACENORMAL:
4363 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4364 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4365 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4366 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4367 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4368 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
4370 glMatrixMode(GL_MODELVIEW);
4373 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4374 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4375 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4376 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4379 glEnable(GL_TEXTURE_GEN_S);
4380 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4381 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4382 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4383 glEnable(GL_TEXTURE_GEN_T);
4384 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4385 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4386 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4387 glEnable(GL_TEXTURE_GEN_R);
4388 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4389 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
4390 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
4395 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
4397 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
4398 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
4399 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
4400 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
4401 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
4402 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
4404 glMatrixMode(GL_MODELVIEW);
4407 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
4408 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
4409 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
4410 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
4413 glEnable(GL_TEXTURE_GEN_S);
4414 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
4415 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4416 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4417 glEnable(GL_TEXTURE_GEN_T);
4418 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
4419 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4420 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4421 glEnable(GL_TEXTURE_GEN_R);
4422 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
4423 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
4424 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
4429 /* Unhandled types: */
4432 /* ? disable GL_TEXTURE_GEN_n ? */
4433 glDisable(GL_TEXTURE_GEN_S);
4434 glDisable(GL_TEXTURE_GEN_T);
4435 glDisable(GL_TEXTURE_GEN_R);
4436 glDisable(GL_TEXTURE_GEN_Q);
4437 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
4444 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
4445 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);
4448 case WINED3DTSS_BUMPENVMAT00 :
4449 case WINED3DTSS_BUMPENVMAT01 :
4450 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
4452 case WINED3DTSS_BUMPENVMAT10 :
4453 case WINED3DTSS_BUMPENVMAT11 :
4454 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
4457 case WINED3DTSS_BUMPENVLSCALE :
4458 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4461 case WINED3DTSS_BUMPENVLOFFSET :
4462 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4465 case WINED3DTSS_RESULTARG :
4466 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4470 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
4471 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
4480 * Get / Set Texture Stage States
4481 * TODO: Verify against dx9 definitions
4483 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4488 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4490 /* Reject invalid texture units */
4491 if (Stage >= GL_LIMITS(texture_stages)) {
4492 TRACE("Attempt to access invalid texture rejected\n");
4493 return WINED3DERR_INVALIDCALL;
4496 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4497 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4498 This->updateStateBlock->textureState[Stage][Type] = Value;
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4506 *pValue = This->updateStateBlock->textureState[Stage][Type];
4513 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4516 IWineD3DBaseTexture *oldTexture;
4518 oldTexture = This->updateStateBlock->textures[Stage];
4519 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4521 #if 0 /* TODO: check so vertex textures */
4522 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4523 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4528 /* Reject invalid texture units */
4529 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
4530 WARN("Attempt to access invalid texture rejected\n");
4531 return WINED3DERR_INVALIDCALL;
4534 if(pTexture != NULL) {
4535 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4537 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4538 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4539 return WINED3DERR_INVALIDCALL;
4543 oldTexture = This->updateStateBlock->textures[Stage];
4544 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4545 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4547 This->updateStateBlock->set.textures[Stage] = TRUE;
4548 This->updateStateBlock->changed.textures[Stage] = TRUE;
4549 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4550 This->updateStateBlock->textures[Stage] = pTexture;
4552 /* Handle recording of state blocks */
4553 if (This->isRecordingState) {
4554 TRACE("Recording... not performing anything\n");
4558 /** NOTE: MSDN says that setTexture increases the reference count,
4559 * and the the application nust set the texture back to null (or have a leaky application),
4560 * This means we should pass the refcount up to the parent
4561 *******************************/
4562 if (NULL != This->updateStateBlock->textures[Stage]) {
4563 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4566 if (NULL != oldTexture) {
4567 IWineD3DBaseTexture_Release(oldTexture);
4570 /* Color keying is affected by the texture. Temporarily mark the color key state (=alpha test)
4571 * dirty until textures are integrated with the state management
4573 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORKEYENABLE));
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4584 /* Reject invalid texture units */
4585 if (Stage >= GL_LIMITS(sampler_stages)) {
4586 TRACE("Attempt to access invalid texture rejected\n");
4587 return WINED3DERR_INVALIDCALL;
4589 *ppTexture=This->stateBlock->textures[Stage];
4591 IWineD3DBaseTexture_AddRef(*ppTexture);
4599 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4600 IWineD3DSurface **ppBackBuffer) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 IWineD3DSwapChain *swapChain;
4605 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4607 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4608 if (hr == WINED3D_OK) {
4609 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4610 IWineD3DSwapChain_Release(swapChain);
4612 *ppBackBuffer = NULL;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 WARN("(%p) : stub, calling idirect3d for now\n", This);
4620 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4623 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 IWineD3DSwapChain *swapChain;
4628 if(iSwapChain > 0) {
4629 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4630 if (hr == WINED3D_OK) {
4631 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4632 IWineD3DSwapChain_Release(swapChain);
4634 FIXME("(%p) Error getting display mode\n", This);
4637 /* Don't read the real display mode,
4638 but return the stored mode instead. X11 can't change the color
4639 depth, and some apps are pretty angry if they SetDisplayMode from
4640 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4642 Also don't relay to the swapchain because with ddraw it's possible
4643 that there isn't a swapchain at all */
4644 pMode->Width = This->ddraw_width;
4645 pMode->Height = This->ddraw_height;
4646 pMode->Format = This->ddraw_format;
4647 pMode->RefreshRate = 0;
4654 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 TRACE("(%p)->(%p)\n", This, hWnd);
4658 This->ddraw_window = hWnd;
4662 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 TRACE("(%p)->(%p)\n", This, hWnd);
4666 *hWnd = This->ddraw_window;
4671 * Stateblock related functions
4674 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4676 IWineD3DStateBlockImpl *object;
4677 HRESULT temp_result;
4679 TRACE("(%p)\n", This);
4681 if (This->isRecordingState) {
4682 return WINED3DERR_INVALIDCALL;
4685 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4686 if (NULL == object ) {
4687 FIXME("(%p)Error allocating memory for stateblock\n", This);
4688 return E_OUTOFMEMORY;
4690 TRACE("(%p) created object %p\n", This, object);
4691 object->wineD3DDevice= This;
4692 /** FIXME: object->parent = parent; **/
4693 object->parent = NULL;
4694 object->blockType = WINED3DSBT_ALL;
4696 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4698 temp_result = allocate_shader_constants(object);
4699 if (WINED3D_OK != temp_result)
4702 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4703 This->updateStateBlock = object;
4704 This->isRecordingState = TRUE;
4706 TRACE("(%p) recording stateblock %p\n",This , object);
4710 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 if (!This->isRecordingState) {
4714 FIXME("(%p) not recording! returning error\n", This);
4715 *ppStateBlock = NULL;
4716 return WINED3DERR_INVALIDCALL;
4719 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4720 This->isRecordingState = FALSE;
4721 This->updateStateBlock = This->stateBlock;
4722 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4723 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4724 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4729 * Scene related functions
4731 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4732 /* At the moment we have no need for any functionality at the beginning
4734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4735 TRACE("(%p) : stub\n", This);
4739 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 TRACE("(%p)\n", This);
4743 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4745 checkGLcall("glFlush");
4747 TRACE("End Scene\n");
4748 /* If we're using FBOs this isn't needed */
4749 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_targets[0] != NULL) {
4751 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
4752 IUnknown *targetContainer = NULL;
4753 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DBaseTexture, (void **)&targetContainer)
4754 || WINED3D_OK == IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DDevice, (void **)&targetContainer)) {
4755 TRACE("(%p) : Texture rendertarget %p\n", This ,This->render_targets[0]);
4756 /** always dirtify for now. we must find a better way to see that surface have been modified
4757 (Modifications should will only occur via draw-primitive, but we do need better locking
4758 switching to render-to-texture should remove the overhead though.
4760 IWineD3DSurface_SetPBufferState(This->render_targets[0], TRUE /* inPBuffer */, FALSE /* inTexture */);
4761 IWineD3DSurface_AddDirtyRect(This->render_targets[0], NULL);
4762 IWineD3DSurface_PreLoad(This->render_targets[0]);
4763 IWineD3DSurface_SetPBufferState(This->render_targets[0], FALSE /* inPBuffer */, FALSE /* inTexture */);
4764 IUnknown_Release(targetContainer);
4767 This->sceneEnded = TRUE;
4772 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4773 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4774 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 IWineD3DSwapChain *swapChain = NULL;
4778 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4780 TRACE("(%p) Presenting the frame\n", This);
4782 for(i = 0 ; i < swapchains ; i ++) {
4784 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4785 TRACE("presentinng chain %d, %p\n", i, swapChain);
4786 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4787 IWineD3DSwapChain_Release(swapChain);
4793 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4794 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4798 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4799 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4800 GLbitfield glMask = 0;
4801 GLboolean old_ztest;
4802 GLfloat old_z_clear_value;
4803 GLint old_stencil_clear_value;
4804 GLfloat old_color_clear_value[4];
4806 CONST WINED3DRECT* curRect;
4808 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4809 Count, pRects, Flags, Z, Stencil);
4813 glEnable(GL_SCISSOR_TEST);
4814 checkGLcall("glEnable GL_SCISSOR_TEST");
4816 if (Count > 0 && pRects) {
4822 /* Only set the values up once, as they are not changing */
4823 if (Flags & WINED3DCLEAR_STENCIL) {
4824 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4825 glClearStencil(Stencil);
4826 checkGLcall("glClearStencil");
4827 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4828 glStencilMask(0xFFFFFFFF);
4831 if (Flags & WINED3DCLEAR_ZBUFFER) {
4832 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4833 glDepthMask(GL_TRUE);
4834 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4836 checkGLcall("glClearDepth");
4837 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4840 if (Flags & WINED3DCLEAR_TARGET) {
4841 TRACE("Clearing screen with glClear to color %x\n", Color);
4842 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4843 glClearColor(D3DCOLOR_R(Color),
4847 checkGLcall("glClearColor");
4849 /* Clear ALL colors! */
4850 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4851 glMask = glMask | GL_COLOR_BUFFER_BIT;
4854 /* Now process each rect in turn */
4855 for (i = 0; i < Count || i == 0; i++) {
4858 /* Note gl uses lower left, width/height */
4859 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4860 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4861 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4862 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4863 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4864 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4865 checkGLcall("glScissor");
4867 glScissor(This->stateBlock->viewport.X,
4868 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4869 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4870 This->stateBlock->viewport.Width,
4871 This->stateBlock->viewport.Height);
4872 checkGLcall("glScissor");
4875 /* Clear the selected rectangle (or full screen) */
4877 checkGLcall("glClear");
4879 /* Step to the next rectangle */
4880 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4883 /* Restore the old values (why..?) */
4884 if (Flags & WINED3DCLEAR_STENCIL) {
4885 glClearStencil(old_stencil_clear_value);
4886 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4888 if (Flags & WINED3DCLEAR_ZBUFFER) {
4889 glDepthMask(old_ztest);
4890 glClearDepth(old_z_clear_value);
4892 if (Flags & WINED3DCLEAR_TARGET) {
4893 glClearColor(old_color_clear_value[0],
4894 old_color_clear_value[1],
4895 old_color_clear_value[2],
4896 old_color_clear_value[3]);
4897 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4898 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4899 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4900 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4903 glDisable(GL_SCISSOR_TEST);
4904 checkGLcall("glDisable");
4913 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4914 UINT PrimitiveCount) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 This->stateBlock->streamIsUP = FALSE;
4919 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4920 debug_d3dprimitivetype(PrimitiveType),
4921 StartVertex, PrimitiveCount);
4922 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4923 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
4929 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4930 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4931 WINED3DPRIMITIVETYPE PrimitiveType,
4932 INT baseVIndex, UINT minIndex,
4933 UINT NumVertices, UINT startIndex, UINT primCount) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4937 IWineD3DIndexBuffer *pIB;
4938 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4940 pIB = This->stateBlock->pIndexData;
4941 This->stateBlock->streamIsUP = FALSE;
4943 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
4944 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4945 minIndex, NumVertices, startIndex, baseVIndex, primCount);
4947 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4948 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4954 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
4955 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
4960 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4961 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4962 UINT VertexStreamZeroStride) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4965 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4966 debug_d3dprimitivetype(PrimitiveType),
4967 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4969 /* release the stream source */
4970 if (This->stateBlock->streamSource[0] != NULL) {
4971 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
4974 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4975 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4976 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4977 This->stateBlock->streamIsUP = TRUE;
4979 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4980 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
4982 /* MSDN specifies stream zero settings must be set to NULL */
4983 This->stateBlock->streamStride[0] = 0;
4984 This->stateBlock->streamSource[0] = NULL;
4986 /*stream zero settings set to null at end, as per the msdn */
4990 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4991 UINT MinVertexIndex, UINT NumVertices,
4992 UINT PrimitiveCount, CONST void* pIndexData,
4993 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4994 UINT VertexStreamZeroStride) {
4996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4999 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5000 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5001 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5003 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5009 /* release the stream and index data */
5010 if (This->stateBlock->streamSource[0] != NULL) {
5011 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
5013 if (This->stateBlock->pIndexData) {
5014 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
5017 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5018 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5019 This->stateBlock->streamIsUP = TRUE;
5020 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5022 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
5024 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5025 This->stateBlock->streamSource[0] = NULL;
5026 This->stateBlock->streamStride[0] = 0;
5027 This->stateBlock->pIndexData = NULL;
5032 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5034 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
5037 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5038 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5040 HRESULT hr = WINED3D_OK;
5041 WINED3DRESOURCETYPE sourceType;
5042 WINED3DRESOURCETYPE destinationType;
5045 /* TODO: think about moving the code into IWineD3DBaseTexture */
5047 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5049 /* verify that the source and destination textures aren't NULL */
5050 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5051 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5052 This, pSourceTexture, pDestinationTexture);
5053 hr = WINED3DERR_INVALIDCALL;
5056 if (pSourceTexture == pDestinationTexture) {
5057 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5058 This, pSourceTexture, pDestinationTexture);
5059 hr = WINED3DERR_INVALIDCALL;
5061 /* Verify that the source and destination textures are the same type */
5062 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5063 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5065 if (sourceType != destinationType) {
5066 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5068 hr = WINED3DERR_INVALIDCALL;
5071 /* check that both textures have the identical numbers of levels */
5072 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5073 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5074 hr = WINED3DERR_INVALIDCALL;
5077 if (WINED3D_OK == hr) {
5079 /* Make sure that the destination texture is loaded */
5080 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5082 /* Update every surface level of the texture */
5083 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5085 switch (sourceType) {
5086 case WINED3DRTYPE_TEXTURE:
5088 IWineD3DSurface *srcSurface;
5089 IWineD3DSurface *destSurface;
5091 for (i = 0 ; i < levels ; ++i) {
5092 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5093 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5094 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5095 IWineD3DSurface_Release(srcSurface);
5096 IWineD3DSurface_Release(destSurface);
5097 if (WINED3D_OK != hr) {
5098 WARN("(%p) : Call to update surface failed\n", This);
5104 case WINED3DRTYPE_CUBETEXTURE:
5106 IWineD3DSurface *srcSurface;
5107 IWineD3DSurface *destSurface;
5108 WINED3DCUBEMAP_FACES faceType;
5110 for (i = 0 ; i < levels ; ++i) {
5111 /* Update each cube face */
5112 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5113 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5114 if (WINED3D_OK != hr) {
5115 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5117 TRACE("Got srcSurface %p\n", srcSurface);
5119 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5120 if (WINED3D_OK != hr) {
5121 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5123 TRACE("Got desrSurface %p\n", destSurface);
5125 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5126 IWineD3DSurface_Release(srcSurface);
5127 IWineD3DSurface_Release(destSurface);
5128 if (WINED3D_OK != hr) {
5129 WARN("(%p) : Call to update surface failed\n", This);
5136 #if 0 /* TODO: Add support for volume textures */
5137 case WINED3DRTYPE_VOLUMETEXTURE:
5139 IWineD3DVolume srcVolume = NULL;
5140 IWineD3DSurface destVolume = NULL;
5142 for (i = 0 ; i < levels ; ++i) {
5143 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5144 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5145 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5146 IWineD3DVolume_Release(srcSurface);
5147 IWineD3DVolume_Release(destSurface);
5148 if (WINED3D_OK != hr) {
5149 WARN("(%p) : Call to update volume failed\n", This);
5157 FIXME("(%p) : Unsupported source and destination type\n", This);
5158 hr = WINED3DERR_INVALIDCALL;
5165 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
5166 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
5167 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5170 TRACE("(%p) : stub\n", This);
5173 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5175 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
5176 * NOTE It may be best to move the code into surface to occomplish this
5177 ****************************************/
5179 WINED3DSURFACE_DESC surfaceDesc;
5180 unsigned int surfaceWidth, surfaceHeight;
5181 glDescriptor *targetGlDescription = NULL;
5182 glDescriptor *surfaceGlDescription = NULL;
5183 IWineD3DSwapChainImpl *container = NULL;
5185 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
5186 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
5187 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5189 surfaceDesc.Width = &surfaceWidth;
5190 surfaceDesc.Height = &surfaceHeight;
5191 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5192 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
5194 /* Ok, I may need to setup some kind of active swapchain reference on the device */
5195 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
5197 /* TODO: opengl Context switching for swapchains etc... */
5198 if (NULL != container || pRenderTarget == This->render_targets[0] || pRenderTarget == This->depthStencilBuffer) {
5199 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
5200 glReadBuffer(GL_BACK);
5201 vcheckGLcall("glReadBuffer(GL_BACK)");
5202 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->render_targets[0])) {
5203 glReadBuffer(GL_FRONT);
5204 vcheckGLcall("glReadBuffer(GL_FRONT)");
5205 } else if (pRenderTarget == This->depthStencilBuffer) {
5206 FIXME("Reading of depthstencil not yet supported\n");
5213 surfaceGlDescription->glFormat,
5214 surfaceGlDescription->glType,
5215 (void *)IWineD3DSurface_GetData(pSurface));
5216 vcheckGLcall("glReadPixels(...)");
5217 if(NULL != container ){
5218 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
5221 IWineD3DBaseTexture *container;
5222 GLenum textureDimensions = GL_TEXTURE_2D;
5224 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
5225 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
5226 IWineD3DBaseTexture_Release(container);
5228 /* TODO: 2D -> Cube surface coppies etc.. */
5229 if (surfaceGlDescription->target != textureDimensions) {
5230 FIXME("(%p) : Texture dimension mismatch\n", This);
5232 glEnable(textureDimensions);
5233 vcheckGLcall("glEnable(GL_TEXTURE_...)");
5234 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
5235 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
5236 vcheckGLcall("glBindTexture");
5237 glGetTexImage(surfaceGlDescription->target,
5238 surfaceGlDescription->level,
5239 surfaceGlDescription->glFormat,
5240 surfaceGlDescription->glType,
5241 (void *)IWineD3DSurface_GetData(pSurface));
5242 glDisable(textureDimensions);
5243 vcheckGLcall("glDisable(GL_TEXTURE_...)");
5250 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5251 IWineD3DSwapChain *swapChain;
5253 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5254 if(hr == WINED3D_OK) {
5255 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5256 IWineD3DSwapChain_Release(swapChain);
5261 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5263 /* return a sensible default */
5265 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5266 FIXME("(%p) : stub\n", This);
5270 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5273 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5274 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5275 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5276 return WINED3DERR_INVALIDCALL;
5278 for (j = 0; j < 256; ++j) {
5279 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5280 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5281 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5282 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5284 TRACE("(%p) : returning\n", This);
5288 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5291 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5292 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5293 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5294 return WINED3DERR_INVALIDCALL;
5296 for (j = 0; j < 256; ++j) {
5297 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5298 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5299 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5300 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5302 TRACE("(%p) : returning\n", This);
5306 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5308 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5309 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5310 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5311 return WINED3DERR_INVALIDCALL;
5313 /*TODO: stateblocks */
5314 This->currentPalette = PaletteNumber;
5315 TRACE("(%p) : returning\n", This);
5319 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5321 if (PaletteNumber == NULL) {
5322 WARN("(%p) : returning Invalid Call\n", This);
5323 return WINED3DERR_INVALIDCALL;
5325 /*TODO: stateblocks */
5326 *PaletteNumber = This->currentPalette;
5327 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5331 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5333 static BOOL showFixmes = TRUE;
5335 FIXME("(%p) : stub\n", This);
5339 This->softwareVertexProcessing = bSoftware;
5344 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5346 static BOOL showFixmes = TRUE;
5348 FIXME("(%p) : stub\n", This);
5351 return This->softwareVertexProcessing;
5355 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 IWineD3DSwapChain *swapChain;
5360 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5362 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5363 if(hr == WINED3D_OK){
5364 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5365 IWineD3DSwapChain_Release(swapChain);
5367 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5373 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5375 static BOOL showfixmes = TRUE;
5376 if(nSegments != 0.0f) {
5378 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5385 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5387 static BOOL showfixmes = TRUE;
5389 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5395 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5397 /** TODO: remove casts to IWineD3DSurfaceImpl
5398 * NOTE: move code to surface to accomplish this
5399 ****************************************/
5400 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5401 int srcWidth, srcHeight;
5402 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5403 WINED3DFORMAT destFormat, srcFormat;
5405 int destLeft, destTop;
5406 WINED3DPOOL srcPool, destPool;
5408 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5409 glDescriptor *glDescription = NULL;
5410 GLenum textureDimensions = GL_TEXTURE_2D;
5411 IWineD3DBaseTexture *baseTexture;
5413 WINED3DSURFACE_DESC winedesc;
5415 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5416 memset(&winedesc, 0, sizeof(winedesc));
5417 winedesc.Width = &srcSurfaceWidth;
5418 winedesc.Height = &srcSurfaceHeight;
5419 winedesc.Pool = &srcPool;
5420 winedesc.Format = &srcFormat;
5422 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5424 winedesc.Width = &destSurfaceWidth;
5425 winedesc.Height = &destSurfaceHeight;
5426 winedesc.Pool = &destPool;
5427 winedesc.Format = &destFormat;
5428 winedesc.Size = &destSize;
5430 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5432 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5433 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5434 return WINED3DERR_INVALIDCALL;
5437 if (destFormat == WINED3DFMT_UNKNOWN) {
5438 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5439 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5441 /* Get the update surface description */
5442 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5445 /* Make sure the surface is loaded and up to date */
5446 IWineD3DSurface_PreLoad(pDestinationSurface);
5448 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5452 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5453 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5454 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
5455 destLeft = pDestPoint ? pDestPoint->x : 0;
5456 destTop = pDestPoint ? pDestPoint->y : 0;
5459 /* This function doesn't support compressed textures
5460 the pitch is just bytesPerPixel * width */
5461 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
5462 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
5463 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
5464 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5466 /* TODO DXT formats */
5468 if(pSourceRect != NULL && pSourceRect->top != 0){
5469 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
5471 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5473 ,glDescription->level
5478 ,glDescription->glFormat
5479 ,glDescription->glType
5480 ,IWineD3DSurface_GetData(pSourceSurface)
5484 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5486 /* need to lock the surface to get the data */
5487 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5490 /* TODO: Cube and volume support */
5492 /* not a whole row so we have to do it a line at a time */
5495 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5496 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5498 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5500 glTexSubImage2D(glDescription->target
5501 ,glDescription->level
5506 ,glDescription->glFormat
5507 ,glDescription->glType
5508 ,data /* could be quicker using */
5513 } else { /* Full width, so just write out the whole texture */
5515 if (WINED3DFMT_DXT1 == destFormat ||
5516 WINED3DFMT_DXT2 == destFormat ||
5517 WINED3DFMT_DXT3 == destFormat ||
5518 WINED3DFMT_DXT4 == destFormat ||
5519 WINED3DFMT_DXT5 == destFormat) {
5520 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5521 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5522 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5523 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5524 } if (destFormat != srcFormat) {
5525 FIXME("Updating mixed format compressed texture is not curretly support\n");
5527 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5528 glDescription->level,
5529 glDescription->glFormatInternal,
5534 IWineD3DSurface_GetData(pSourceSurface));
5537 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5542 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
5544 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
5545 to repack the data from pow2Width/Height to expected Width,Height, this makes the
5546 data returned by GetData non-power2 width/height with hardware non-power2
5547 pow2Width/height are set to surface width height, repacking isn't needed so it
5548 doesn't matter which function gets called. */
5549 glTexSubImage2D(glDescription->target
5550 ,glDescription->level
5555 ,glDescription->glFormat
5556 ,glDescription->glType
5557 ,IWineD3DSurface_GetData(pSourceSurface)
5561 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
5562 glTexSubImage2D(glDescription->target
5563 ,glDescription->level
5566 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
5567 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
5568 ,glDescription->glFormat
5569 ,glDescription->glType
5570 ,IWineD3DSurface_GetData(pSourceSurface)
5576 checkGLcall("glTexSubImage2D");
5577 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
5579 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
5580 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
5581 * surface bigger than it needs to be hmm.. */
5582 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
5583 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
5584 IWineD3DBaseTexture_Release(baseTexture);
5587 glDisable(textureDimensions); /* This needs to be managed better.... */
5593 /* Implementation details at http://developer.nvidia.com/attach/6494
5595 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5596 hmm.. no longer supported use
5597 OpenGL evaluators or tessellate surfaces within your application.
5600 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5601 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5604 FIXME("(%p) : Stub\n", This);
5609 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5610 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5613 FIXME("(%p) : Stub\n", This);
5617 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 TRACE("(%p) Handle(%d)\n", This, Handle);
5620 FIXME("(%p) : Stub\n", This);
5624 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5626 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5628 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
5630 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5631 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5632 return WINED3DERR_INVALIDCALL;
5635 /* Just forward this to the DirectDraw blitting engine */
5636 memset(&BltFx, 0, sizeof(BltFx));
5637 BltFx.dwSize = sizeof(BltFx);
5638 BltFx.u5.dwFillColor = color;
5639 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
5642 /* rendertarget and deptth stencil functions */
5643 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5647 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5648 return WINED3DERR_INVALIDCALL;
5651 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5652 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5653 /* Note inc ref on returned surface */
5654 if(*ppRenderTarget != NULL)
5655 IWineD3DSurface_AddRef(*ppRenderTarget);
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5662 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5663 IWineD3DSwapChainImpl *Swapchain;
5666 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5668 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5669 if(hr != WINED3D_OK) {
5670 ERR("Can't get the swapchain\n");
5674 /* Make sure to release the swapchain */
5675 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5677 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5678 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5679 return WINED3DERR_INVALIDCALL;
5681 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5682 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5683 return WINED3DERR_INVALIDCALL;
5686 if(Swapchain->frontBuffer != Front) {
5687 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5689 if(Swapchain->frontBuffer)
5690 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5691 Swapchain->frontBuffer = Front;
5693 if(Swapchain->frontBuffer) {
5694 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5698 if(Back && !Swapchain->backBuffer) {
5699 /* We need memory for the back buffer array - only one back buffer this way */
5700 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5701 if(!Swapchain->backBuffer) {
5702 ERR("Out of memory\n");
5703 return E_OUTOFMEMORY;
5707 if(Swapchain->backBuffer[0] != Back) {
5708 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5710 if(!Swapchain->backBuffer[0]) {
5711 /* GL was told to draw to the front buffer at creation,
5714 glDrawBuffer(GL_BACK);
5715 checkGLcall("glDrawBuffer(GL_BACK)");
5716 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5717 Swapchain->presentParms.BackBufferCount = 1;
5719 /* That makes problems - disable for now */
5720 /* glDrawBuffer(GL_FRONT); */
5721 checkGLcall("glDrawBuffer(GL_FRONT)");
5722 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5723 Swapchain->presentParms.BackBufferCount = 0;
5727 if(Swapchain->backBuffer[0])
5728 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5729 Swapchain->backBuffer[0] = Back;
5731 if(Swapchain->backBuffer[0]) {
5732 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5734 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5742 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 *ppZStencilSurface = This->depthStencilBuffer;
5745 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5747 if(*ppZStencilSurface != NULL) {
5748 /* Note inc ref on returned surface */
5749 IWineD3DSurface_AddRef(*ppZStencilSurface);
5754 static void bind_fbo(IWineD3DDevice *iface) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5759 checkGLcall("glGenFramebuffersEXT()");
5761 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5762 checkGLcall("glBindFramebuffer()");
5765 /* TODO: Handle stencil attachments */
5766 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5768 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5770 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5774 if (depth_stencil_impl) {
5775 GLenum texttarget, target;
5777 IWineD3DSurface_PreLoad(depth_stencil);
5778 texttarget = depth_stencil_impl->glDescription.target;
5779 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5781 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5782 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5783 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5784 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5785 glBindTexture(target, 0);
5787 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5788 checkGLcall("glFramebufferTexture2DEXT()");
5790 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5791 checkGLcall("glFramebufferTexture2DEXT()");
5794 if (!This->render_offscreen) {
5795 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5796 checkGLcall("glBindFramebuffer()");
5800 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5804 if (idx >= GL_LIMITS(buffers)) {
5805 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5811 GLenum texttarget, target;
5813 IWineD3DSurface_PreLoad(render_target);
5814 texttarget = rtimpl->glDescription.target;
5815 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5817 glBindTexture(target, rtimpl->glDescription.textureName);
5818 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5819 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5820 glBindTexture(target, 0);
5822 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5823 checkGLcall("glFramebufferTexture2DEXT()");
5825 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5827 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5828 checkGLcall("glFramebufferTexture2DEXT()");
5830 This->draw_buffers[idx] = GL_NONE;
5833 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5834 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5835 checkGLcall("glDrawBuffers()");
5838 if (!This->render_offscreen) {
5839 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5840 checkGLcall("glBindFramebuffer()");
5844 /* internal static helper functions */
5845 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
5846 IWineD3DSurface *RenderSurface);
5848 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5850 HRESULT hr = WINED3D_OK;
5851 WINED3DVIEWPORT viewport;
5853 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5855 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5856 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5857 return WINED3DERR_INVALIDCALL;
5860 /* MSDN says that null disables the render target
5861 but a device must always be associated with a render target
5862 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5864 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5867 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5868 FIXME("Trying to set render target 0 to NULL\n");
5869 return WINED3DERR_INVALIDCALL;
5871 /* TODO: replace Impl* usage with interface usage */
5872 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5873 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);
5874 return WINED3DERR_INVALIDCALL;
5876 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
5877 * builds, but I think wine counts as a 'debug' build for now.
5878 ******************************/
5879 /* If we are trying to set what we already have, don't bother */
5880 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5881 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5883 /* Otherwise, set the render target up */
5885 if (!This->sceneEnded) {
5886 IWineD3DDevice_EndScene(iface);
5888 TRACE("clearing renderer\n");
5889 /* IWineD3DDeviceImpl_CleanRender(iface); */
5890 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5891 depending on the renter target implementation being used.
5892 A shared context implementation will share all buffers between all rendertargets (including swapchains),
5893 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5894 stencil buffer and incure an extra memory overhead */
5895 if (RenderTargetIndex == 0) {
5896 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
5901 /* Replace the render target */
5902 if (This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5903 This->render_targets[RenderTargetIndex] = pRenderTarget;
5904 if (pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5906 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5907 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5911 if (SUCCEEDED(hr)) {
5912 /* Finally, reset the viewport as the MSDN states. */
5913 /* TODO: Replace impl usage */
5914 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5915 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5918 viewport.MaxZ = 1.0f;
5919 viewport.MinZ = 0.0f;
5920 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5922 FIXME("Unknown error setting the render target\n");
5924 This->sceneEnded = FALSE;
5928 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 HRESULT hr = WINED3D_OK;
5931 IWineD3DSurface *tmp;
5933 TRACE("(%p) Swapping z-buffer\n",This);
5935 if (pNewZStencil == This->stencilBufferTarget) {
5936 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5938 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5939 * depending on the renter target implementation being used.
5940 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5941 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5942 * stencil buffer and incure an extra memory overhead
5943 ******************************************************/
5946 tmp = This->stencilBufferTarget;
5947 This->stencilBufferTarget = pNewZStencil;
5948 /* should we be calling the parent or the wined3d surface? */
5949 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5950 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5952 /** TODO: glEnable/glDisable on depth/stencil depending on
5953 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5954 **********************************************************/
5955 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5956 set_depth_stencil_fbo(iface, pNewZStencil);
5964 #ifdef GL_VERSION_1_3
5965 /* Internal functions not in DirectX */
5966 /** TODO: move this off to the opengl context manager
5967 *(the swapchain doesn't need to know anything about offscreen rendering!)
5968 ****************************************************/
5970 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
5972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5974 TRACE("(%p), %p\n", This, swapchain);
5976 if (swapchain->win != swapchain->drawable) {
5977 /* Set everything back the way it ws */
5978 swapchain->render_ctx = swapchain->glCtx;
5979 swapchain->drawable = swapchain->win;
5984 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
5985 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5989 unsigned int height;
5990 WINED3DFORMAT format;
5991 WINED3DSURFACE_DESC surfaceDesc;
5992 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
5993 surfaceDesc.Width = &width;
5994 surfaceDesc.Height = &height;
5995 surfaceDesc.Format = &format;
5996 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
5998 /* I need a get width/height function (and should do something with the format) */
5999 for (i = 0; i < CONTEXT_CACHE; ++i) {
6000 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
6001 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
6002 the pSurface can be set to 0 allowing it to be reused from cache **/
6003 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
6004 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
6005 *context = &This->contextCache[i];
6008 if (This->contextCache[i].Width == 0) {
6009 This->contextCache[i].pSurface = pSurface;
6010 This->contextCache[i].Width = width;
6011 This->contextCache[i].Height = height;
6012 *context = &This->contextCache[i];
6016 if (i == CONTEXT_CACHE) {
6017 int minUsage = 0x7FFFFFFF; /* MAX_INT */
6018 glContext *dropContext = 0;
6019 for (i = 0; i < CONTEXT_CACHE; i++) {
6020 if (This->contextCache[i].usedcount < minUsage) {
6021 dropContext = &This->contextCache[i];
6022 minUsage = This->contextCache[i].usedcount;
6025 /* clean up the context (this doesn't work for ATI at the moment */
6027 glXDestroyContext(swapchain->display, dropContext->context);
6028 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
6031 dropContext->Width = 0;
6032 dropContext->pSurface = pSurface;
6033 *context = dropContext;
6035 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
6036 for (i = 0; i < CONTEXT_CACHE; i++) {
6037 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
6041 if (*context != NULL)
6044 return E_OUTOFMEMORY;
6048 /* Reapply the device stateblock */
6049 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
6052 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6055 /* Disable recording */
6056 oldUpdateStateBlock = This->updateStateBlock;
6057 oldRecording= This->isRecordingState;
6058 This->isRecordingState = FALSE;
6059 This->updateStateBlock = This->stateBlock;
6061 /* Reapply the state block */
6062 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
6064 /* Temporaryily mark all render states dirty to force reapplication
6065 * until the context management for is integrated with the state management
6067 for(i = 1; i < WINEHIGHEST_RENDER_STATE; i++) {
6068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(i));
6071 /* Restore recording */
6072 This->isRecordingState = oldRecording;
6073 This->updateStateBlock = oldUpdateStateBlock;
6076 /* Set offscreen rendering. When rendering offscreen the surface will be
6077 * rendered upside down to compensate for the fact that D3D texture coordinates
6078 * are flipped compared to GL texture coordinates. The cullmode is affected by
6079 * this, so it must be updated. To update the cullmode stateblock recording has
6080 * to be temporarily disabled. The new state management code will hopefully
6081 * make this unnecessary */
6082 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
6085 IWineD3DStateBlockImpl *oldUpdateStateBlock;
6087 /* Nothing to update, return. */
6088 if (This->render_offscreen == isTexture) return;
6090 /* Disable recording */
6091 oldUpdateStateBlock = This->updateStateBlock;
6092 oldRecording= This->isRecordingState;
6093 This->isRecordingState = FALSE;
6094 This->updateStateBlock = This->stateBlock;
6096 This->render_offscreen = isTexture;
6097 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
6098 This->depth_copy_state = WINED3D_DCS_COPY;
6100 This->last_was_rhw = FALSE;
6101 This->proj_valid = FALSE;
6102 IWineD3DDeviceImpl_MarkStateDirty(This, WINED3DRS_CULLMODE);
6104 /* Restore recording */
6105 This->isRecordingState = oldRecording;
6106 This->updateStateBlock = oldUpdateStateBlock;
6109 /* Returns an array of compatible FBconfig(s).
6110 * The array must be freed with XFree. Requires ENTER_GL() */
6112 static GLXFBConfig* device_find_fbconfigs(
6113 IWineD3DDeviceImpl* This,
6114 IWineD3DSwapChainImpl* implicitSwapchainImpl,
6115 IWineD3DSurface* RenderSurface) {
6117 GLXFBConfig* cfgs = NULL;
6122 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
6123 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
6124 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
6127 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
6128 it StencilSurface != NULL && zBufferTarget == NULL switch it on
6131 #define PUSH1(att) attribs[nAttribs++] = (att);
6132 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
6134 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
6136 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
6137 PUSH2(GLX_X_RENDERABLE, TRUE);
6138 PUSH2(GLX_DOUBLEBUFFER, TRUE);
6139 TRACE("calling makeglcfg\n");
6140 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
6142 TRACE("calling chooseFGConfig\n");
6143 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6144 DefaultScreen(implicitSwapchainImpl->display),
6147 /* OK we didn't find the exact config, so use any reasonable match */
6148 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
6150 static BOOL show_message = TRUE;
6152 ERR("Failed to find exact match, finding alternative but you may "
6153 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
6154 show_message = FALSE;
6157 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
6158 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
6159 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
6160 PUSH2(GLX_DOUBLEBUFFER, FALSE);
6161 TRACE("calling makeglcfg\n");
6162 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
6164 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
6165 DefaultScreen(implicitSwapchainImpl->display),
6170 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
6171 BackBufferFormat, debug_d3dformat(BackBufferFormat),
6172 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
6176 for (i = 0; i < nCfgs; ++i) {
6177 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
6178 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
6179 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
6181 if (NULL != This->renderTarget) {
6183 vcheckGLcall("glFlush");
6184 /** This is only useful if the old render target was a swapchain,
6185 * we need to supercede this with a function that displays
6186 * the current buffer on the screen. This is easy to do in glx1.3 but
6187 * we need to do copy-write pixels in glx 1.2.
6188 ************************************************/
6189 glXSwapBuffers(implicitSwapChainImpl->display,
6190 implicitSwapChainImpl->drawable);
6191 printf("Hit Enter to get next frame ...\n");
6202 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
6203 * the functionality needs splitting up so that we don't do more than we should do.
6204 * this only seems to impact performance a little.
6205 ******************************/
6206 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
6207 IWineD3DSurface *RenderSurface) {
6210 * Currently only active for GLX >= 1.3
6211 * for others versions we'll have to use GLXPixmaps
6213 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
6214 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
6215 * so only check OpenGL version
6216 * ..........................
6217 * I don't believe that it is a problem with NVidia headers,
6218 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
6219 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
6221 * Your application will report GLX version 1.2 on glXQueryVersion.
6222 * However, it is safe to call the GLX 1.3 functions as described below.
6224 #if defined(GL_VERSION_1_3)
6226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6227 GLXFBConfig* cfgs = NULL;
6228 IWineD3DSwapChain *currentSwapchain;
6229 IWineD3DSwapChainImpl *currentSwapchainImpl;
6230 IWineD3DSwapChain *implicitSwapchain;
6231 IWineD3DSwapChainImpl *implicitSwapchainImpl;
6232 IWineD3DSwapChain *renderSurfaceSwapchain;
6233 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
6235 /* Obtain a reference to the device implicit swapchain,
6236 * the swapchain of the current render target,
6237 * and the swapchain of the new render target.
6238 * Fallback to device implicit swapchain if the current render target doesn't have one */
6239 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
6240 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
6241 IWineD3DSurface_GetContainer(This->render_targets[0], &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
6242 if (currentSwapchain == NULL)
6243 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
6245 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
6246 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
6247 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
6252 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
6253 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
6254 **********************************************************************/
6255 if (renderSurfaceSwapchain != NULL) {
6257 /* We also need to make sure that the lights &co are also in the context of the swapchains */
6258 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
6259 TRACE("making swapchain active\n");
6260 if (RenderSurface != This->render_targets[0]) {
6261 BOOL backbuf = FALSE;
6264 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
6265 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
6273 /* This could be flagged so that some operations work directly with the front buffer */
6274 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
6276 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
6277 renderSurfaceSwapchainImpl->win,
6278 renderSurfaceSwapchainImpl->glCtx) == False) {
6280 TRACE("Error in setting current context: context %p drawable %ld !\n",
6281 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
6283 checkGLcall("glXMakeContextCurrent");
6285 /* Clean up the old context */
6286 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6288 /* Reapply the stateblock, and set the device not to render to texture */
6289 device_reapply_stateblock(This);
6290 device_render_to_texture(This, FALSE);
6293 /* Offscreen rendering: PBuffers (currently disabled).
6294 * Also note that this path is never reached if FBOs are supported */
6295 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
6296 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
6298 /** ********************************************************************
6299 * This is a quickly hacked out implementation of offscreen textures.
6300 * It will work in most cases but there may be problems if the client
6301 * modifies the texture directly, or expects the contents of the rendertarget
6304 * There are some real speed vs compatibility issues here:
6305 * we should really use a new context for every texture, but that eats ram.
6306 * we should also be restoring the texture to the pbuffer but that eats CPU
6307 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
6308 * but if this means reusing the display backbuffer then we need to make sure that
6309 * states are correctly preserved.
6310 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
6311 * and gain a good performance increase at the cost of compatibility.
6312 * I would suggest that, when this is the case, a user configurable flag be made
6313 * available, allowing the user to choose the best emulated experience for them.
6314 *********************************************************************/
6316 XVisualInfo *visinfo;
6317 glContext *newContext;
6319 /* Here were using a shared context model */
6320 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
6321 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6324 /* If the context doesn't exist then create a new one */
6325 /* TODO: This should really be part of findGlContext */
6326 if (NULL == newContext->context) {
6331 TRACE("making new buffer\n");
6332 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
6333 attribs[nAttribs++] = newContext->Width;
6334 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
6335 attribs[nAttribs++] = newContext->Height;
6336 attribs[nAttribs++] = None;
6338 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
6340 /** ****************************************
6341 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
6343 * In future releases, we may provide the calls glXCreateNewContext,
6344 * glXQueryDrawable and glXMakeContextCurrent.
6345 * so until then we have to use glXGetVisualFromFBConfig &co..
6346 ********************************************/
6348 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
6350 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
6352 newContext->context = glXCreateContext(
6353 implicitSwapchainImpl->display, visinfo,
6354 implicitSwapchainImpl->glCtx, GL_TRUE);
6359 if (NULL == newContext || NULL == newContext->context) {
6360 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
6362 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
6363 if (glXMakeCurrent(implicitSwapchainImpl->display,
6364 newContext->drawable, newContext->context) == False) {
6366 TRACE("Error in setting current context: context %p drawable %ld\n",
6367 newContext->context, newContext->drawable);
6369 checkGLcall("glXMakeContextCurrent");
6371 /* Clean up the old context */
6372 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
6374 /* Reapply stateblock, and set device to render to a texture */
6375 device_reapply_stateblock(This);
6376 device_render_to_texture(This, TRUE);
6378 /* Set the current context of the swapchain to the new context */
6379 implicitSwapchainImpl->drawable = newContext->drawable;
6380 implicitSwapchainImpl->render_ctx = newContext->context;
6383 /* Same context, but update render_offscreen and cull mode */
6384 device_render_to_texture(This, TRUE);
6387 if (cfgs != NULL) XFree(cfgs);
6388 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
6389 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
6390 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
6396 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6397 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6399 /* TODO: the use of Impl is deprecated. */
6400 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6402 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6404 /* some basic validation checks */
6405 if(This->cursorTexture) {
6407 glDeleteTextures(1, &This->cursorTexture);
6409 This->cursorTexture = 0;
6413 /* MSDN: Cursor must be A8R8G8B8 */
6414 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6415 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6416 return WINED3DERR_INVALIDCALL;
6419 /* MSDN: Cursor must be smaller than the display mode */
6420 if(pSur->currentDesc.Width > This->ddraw_width ||
6421 pSur->currentDesc.Height > This->ddraw_height) {
6422 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);
6423 return WINED3DERR_INVALIDCALL;
6426 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6427 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
6428 * Texture and Blitting code to draw the cursor
6430 pSur->Flags |= SFLAG_FORCELOAD;
6431 IWineD3DSurface_PreLoad(pCursorBitmap);
6432 pSur->Flags &= ~SFLAG_FORCELOAD;
6433 /* Do not store the surface's pointer because the application may release
6434 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
6435 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
6437 This->cursorTexture = pSur->glDescription.textureName;
6438 This->cursorWidth = pSur->currentDesc.Width;
6439 This->cursorHeight = pSur->currentDesc.Height;
6440 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
6443 This->xHotSpot = XHotSpot;
6444 This->yHotSpot = YHotSpot;
6448 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6450 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6452 This->xScreenSpace = XScreenSpace;
6453 This->yScreenSpace = YScreenSpace;
6459 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6461 BOOL oldVisible = This->bCursorVisible;
6462 TRACE("(%p) : visible(%d)\n", This, bShow);
6464 if(This->cursorTexture)
6465 This->bCursorVisible = bShow;
6470 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6472 TRACE("(%p) : state (%u)\n", This, This->state);
6473 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6474 switch (This->state) {
6477 case WINED3DERR_DEVICELOST:
6479 ResourceList *resourceList = This->resources;
6480 while (NULL != resourceList) {
6481 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6482 return WINED3DERR_DEVICENOTRESET;
6483 resourceList = resourceList->next;
6485 return WINED3DERR_DEVICELOST;
6487 case WINED3DERR_DRIVERINTERNALERROR:
6488 return WINED3DERR_DRIVERINTERNALERROR;
6492 return WINED3DERR_DRIVERINTERNALERROR;
6496 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6498 /** FIXME: Resource tracking needs to be done,
6499 * The closes we can do to this is set the priorities of all managed textures low
6500 * and then reset them.
6501 ***********************************************************/
6502 FIXME("(%p) : stub\n", This);
6506 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6507 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6508 if(surface->Flags & SFLAG_DIBSECTION) {
6509 /* Release the DC */
6510 SelectObject(surface->hDC, surface->dib.holdbitmap);
6511 DeleteDC(surface->hDC);
6512 /* Release the DIB section */
6513 DeleteObject(surface->dib.DIBsection);
6514 surface->dib.bitmap_data = NULL;
6515 surface->resource.allocatedMemory = NULL;
6516 surface->Flags &= ~SFLAG_DIBSECTION;
6518 surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
6519 surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
6520 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
6521 surface->pow2Width = *pPresentationParameters->BackBufferWidth;
6522 surface->pow2Height = *pPresentationParameters->BackBufferHeight;
6524 surface->pow2Width = surface->pow2Height = 1;
6525 while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6526 while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6528 if(surface->glDescription.textureName) {
6530 glDeleteTextures(1, &surface->glDescription.textureName);
6532 surface->glDescription.textureName = 0;
6534 if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
6535 surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
6536 surface->Flags |= SFLAG_NONPOW2;
6538 surface->Flags &= ~SFLAG_NONPOW2;
6540 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6541 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6544 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6546 IWineD3DSwapChainImpl *swapchain;
6548 BOOL DisplayModeChanged = FALSE;
6549 WINED3DDISPLAYMODE mode;
6550 TRACE("(%p)\n", This);
6552 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6554 ERR("Failed to get the first implicit swapchain\n");
6558 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6559 * on an existing gl context, so there's no real need for recreation.
6561 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6563 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6565 TRACE("New params:\n");
6566 TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
6567 TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
6568 TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
6569 TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
6570 TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
6571 TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
6572 TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
6573 TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
6574 TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
6575 TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6576 TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
6577 TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
6578 TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
6580 /* No special treatment of these parameters. Just store them */
6581 swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
6582 swapchain->presentParms.Flags = *pPresentationParameters->Flags;
6583 swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
6584 swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
6586 /* What to do about these? */
6587 if(*pPresentationParameters->BackBufferCount != 0 &&
6588 *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6589 ERR("Cannot change the back buffer count yet\n");
6591 if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6592 *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6593 ERR("Cannot change the back buffer format yet\n");
6595 if(*pPresentationParameters->hDeviceWindow != NULL &&
6596 *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6597 ERR("Cannot change the device window yet\n");
6599 if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6600 ERR("What do do about a changed auto depth stencil parameter?\n");
6603 if(*pPresentationParameters->Windowed) {
6604 mode.Width = swapchain->orig_width;
6605 mode.Height = swapchain->orig_height;
6606 mode.RefreshRate = 0;
6607 mode.Format = swapchain->presentParms.BackBufferFormat;
6609 mode.Width = *pPresentationParameters->BackBufferWidth;
6610 mode.Height = *pPresentationParameters->BackBufferHeight;
6611 mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
6612 mode.Format = swapchain->presentParms.BackBufferFormat;
6615 /* Should Width == 800 && Height == 0 set 800x600? */
6616 if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
6617 (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6618 *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6625 vp.Width = *pPresentationParameters->BackBufferWidth;
6626 vp.Height = *pPresentationParameters->BackBufferHeight;
6630 if(!*pPresentationParameters->Windowed) {
6631 DisplayModeChanged = TRUE;
6633 swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
6634 swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
6636 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6637 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6638 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6641 /* Now set the new viewport */
6642 IWineD3DDevice_SetViewport(iface, &vp);
6645 if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6646 (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
6647 DisplayModeChanged) {
6648 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6651 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6655 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6657 /** FIXME: always true at the moment **/
6658 if(!bEnableDialogs) {
6659 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6665 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6667 TRACE("(%p) : pParameters %p\n", This, pParameters);
6669 *pParameters = This->createParms;
6673 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6674 IWineD3DSwapChain *swapchain;
6675 HRESULT hrc = WINED3D_OK;
6677 TRACE("Relaying to swapchain\n");
6679 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6680 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6681 IWineD3DSwapChain_Release(swapchain);
6686 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6687 IWineD3DSwapChain *swapchain;
6688 HRESULT hrc = WINED3D_OK;
6690 TRACE("Relaying to swapchain\n");
6692 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6693 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6694 IWineD3DSwapChain_Release(swapchain);
6700 /** ********************************************************
6701 * Notification functions
6702 ** ********************************************************/
6703 /** This function must be called in the release of a resource when ref == 0,
6704 * the contents of resource must still be correct,
6705 * any handels to other resource held by the caller must be closed
6706 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6707 *****************************************************/
6708 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6710 ResourceList* resourceList;
6712 TRACE("(%p) : resource %p\n", This, resource);
6714 EnterCriticalSection(&resourceStoreCriticalSection);
6716 /* add a new texture to the frot of the linked list */
6717 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6718 resourceList->resource = resource;
6720 /* Get the old head */
6721 resourceList->next = This->resources;
6723 This->resources = resourceList;
6724 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6727 LeaveCriticalSection(&resourceStoreCriticalSection);
6732 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6734 ResourceList* resourceList = NULL;
6735 ResourceList* previousResourceList = NULL;
6737 TRACE("(%p) : resource %p\n", This, resource);
6740 EnterCriticalSection(&resourceStoreCriticalSection);
6742 resourceList = This->resources;
6744 while (resourceList != NULL) {
6745 if(resourceList->resource == resource) break;
6746 previousResourceList = resourceList;
6747 resourceList = resourceList->next;
6750 if (resourceList == NULL) {
6751 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6753 LeaveCriticalSection(&resourceStoreCriticalSection);
6757 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6759 /* make sure we don't leave a hole in the list */
6760 if (previousResourceList != NULL) {
6761 previousResourceList->next = resourceList->next;
6763 This->resources = resourceList->next;
6767 LeaveCriticalSection(&resourceStoreCriticalSection);
6773 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6777 TRACE("(%p) : resource %p\n", This, resource);
6778 switch(IWineD3DResource_GetType(resource)){
6779 case WINED3DRTYPE_SURFACE:
6780 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6782 case WINED3DRTYPE_TEXTURE:
6783 case WINED3DRTYPE_CUBETEXTURE:
6784 case WINED3DRTYPE_VOLUMETEXTURE:
6785 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6786 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6787 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6788 This->stateBlock->textures[counter] = NULL;
6790 if (This->updateStateBlock != This->stateBlock ){
6791 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6792 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6793 This->updateStateBlock->textures[counter] = NULL;
6798 case WINED3DRTYPE_VOLUME:
6799 /* TODO: nothing really? */
6801 case WINED3DRTYPE_VERTEXBUFFER:
6802 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6805 TRACE("Cleaning up stream pointers\n");
6807 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6808 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6809 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6811 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6812 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6813 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6814 This->updateStateBlock->streamSource[streamNumber] = 0;
6815 /* Set changed flag? */
6818 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) */
6819 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6820 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6821 This->stateBlock->streamSource[streamNumber] = 0;
6824 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6825 else { /* This shouldn't happen */
6826 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6833 case WINED3DRTYPE_INDEXBUFFER:
6834 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6835 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6836 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6837 This->updateStateBlock->pIndexData = NULL;
6840 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6841 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6842 This->stateBlock->pIndexData = NULL;
6848 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6853 /* Remove the resoruce from the resourceStore */
6854 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6856 TRACE("Resource released\n");
6860 /**********************************************************
6861 * IWineD3DDevice VTbl follows
6862 **********************************************************/
6864 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6866 /*** IUnknown methods ***/
6867 IWineD3DDeviceImpl_QueryInterface,
6868 IWineD3DDeviceImpl_AddRef,
6869 IWineD3DDeviceImpl_Release,
6870 /*** IWineD3DDevice methods ***/
6871 IWineD3DDeviceImpl_GetParent,
6872 /*** Creation methods**/
6873 IWineD3DDeviceImpl_CreateVertexBuffer,
6874 IWineD3DDeviceImpl_CreateIndexBuffer,
6875 IWineD3DDeviceImpl_CreateStateBlock,
6876 IWineD3DDeviceImpl_CreateSurface,
6877 IWineD3DDeviceImpl_CreateTexture,
6878 IWineD3DDeviceImpl_CreateVolumeTexture,
6879 IWineD3DDeviceImpl_CreateVolume,
6880 IWineD3DDeviceImpl_CreateCubeTexture,
6881 IWineD3DDeviceImpl_CreateQuery,
6882 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6883 IWineD3DDeviceImpl_CreateVertexDeclaration,
6884 IWineD3DDeviceImpl_CreateVertexShader,
6885 IWineD3DDeviceImpl_CreatePixelShader,
6886 IWineD3DDeviceImpl_CreatePalette,
6887 /*** Odd functions **/
6888 IWineD3DDeviceImpl_Init3D,
6889 IWineD3DDeviceImpl_Uninit3D,
6890 IWineD3DDeviceImpl_SetFullscreen,
6891 IWineD3DDeviceImpl_EnumDisplayModes,
6892 IWineD3DDeviceImpl_EvictManagedResources,
6893 IWineD3DDeviceImpl_GetAvailableTextureMem,
6894 IWineD3DDeviceImpl_GetBackBuffer,
6895 IWineD3DDeviceImpl_GetCreationParameters,
6896 IWineD3DDeviceImpl_GetDeviceCaps,
6897 IWineD3DDeviceImpl_GetDirect3D,
6898 IWineD3DDeviceImpl_GetDisplayMode,
6899 IWineD3DDeviceImpl_SetDisplayMode,
6900 IWineD3DDeviceImpl_GetHWND,
6901 IWineD3DDeviceImpl_SetHWND,
6902 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6903 IWineD3DDeviceImpl_GetRasterStatus,
6904 IWineD3DDeviceImpl_GetSwapChain,
6905 IWineD3DDeviceImpl_Reset,
6906 IWineD3DDeviceImpl_SetDialogBoxMode,
6907 IWineD3DDeviceImpl_SetCursorProperties,
6908 IWineD3DDeviceImpl_SetCursorPosition,
6909 IWineD3DDeviceImpl_ShowCursor,
6910 IWineD3DDeviceImpl_TestCooperativeLevel,
6911 /*** Getters and setters **/
6912 IWineD3DDeviceImpl_SetClipPlane,
6913 IWineD3DDeviceImpl_GetClipPlane,
6914 IWineD3DDeviceImpl_SetClipStatus,
6915 IWineD3DDeviceImpl_GetClipStatus,
6916 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6917 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6918 IWineD3DDeviceImpl_SetDepthStencilSurface,
6919 IWineD3DDeviceImpl_GetDepthStencilSurface,
6920 IWineD3DDeviceImpl_SetFVF,
6921 IWineD3DDeviceImpl_GetFVF,
6922 IWineD3DDeviceImpl_SetGammaRamp,
6923 IWineD3DDeviceImpl_GetGammaRamp,
6924 IWineD3DDeviceImpl_SetIndices,
6925 IWineD3DDeviceImpl_GetIndices,
6926 IWineD3DDeviceImpl_SetLight,
6927 IWineD3DDeviceImpl_GetLight,
6928 IWineD3DDeviceImpl_SetLightEnable,
6929 IWineD3DDeviceImpl_GetLightEnable,
6930 IWineD3DDeviceImpl_SetMaterial,
6931 IWineD3DDeviceImpl_GetMaterial,
6932 IWineD3DDeviceImpl_SetNPatchMode,
6933 IWineD3DDeviceImpl_GetNPatchMode,
6934 IWineD3DDeviceImpl_SetPaletteEntries,
6935 IWineD3DDeviceImpl_GetPaletteEntries,
6936 IWineD3DDeviceImpl_SetPixelShader,
6937 IWineD3DDeviceImpl_GetPixelShader,
6938 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6939 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6940 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6941 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6942 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6943 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6944 IWineD3DDeviceImpl_SetRenderState,
6945 IWineD3DDeviceImpl_GetRenderState,
6946 IWineD3DDeviceImpl_SetRenderTarget,
6947 IWineD3DDeviceImpl_GetRenderTarget,
6948 IWineD3DDeviceImpl_SetFrontBackBuffers,
6949 IWineD3DDeviceImpl_SetSamplerState,
6950 IWineD3DDeviceImpl_GetSamplerState,
6951 IWineD3DDeviceImpl_SetScissorRect,
6952 IWineD3DDeviceImpl_GetScissorRect,
6953 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6954 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6955 IWineD3DDeviceImpl_SetStreamSource,
6956 IWineD3DDeviceImpl_GetStreamSource,
6957 IWineD3DDeviceImpl_SetStreamSourceFreq,
6958 IWineD3DDeviceImpl_GetStreamSourceFreq,
6959 IWineD3DDeviceImpl_SetTexture,
6960 IWineD3DDeviceImpl_GetTexture,
6961 IWineD3DDeviceImpl_SetTextureStageState,
6962 IWineD3DDeviceImpl_GetTextureStageState,
6963 IWineD3DDeviceImpl_SetTransform,
6964 IWineD3DDeviceImpl_GetTransform,
6965 IWineD3DDeviceImpl_SetVertexDeclaration,
6966 IWineD3DDeviceImpl_GetVertexDeclaration,
6967 IWineD3DDeviceImpl_SetVertexShader,
6968 IWineD3DDeviceImpl_GetVertexShader,
6969 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6970 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6971 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6972 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6973 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6974 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6975 IWineD3DDeviceImpl_SetViewport,
6976 IWineD3DDeviceImpl_GetViewport,
6977 IWineD3DDeviceImpl_MultiplyTransform,
6978 IWineD3DDeviceImpl_ValidateDevice,
6979 IWineD3DDeviceImpl_ProcessVertices,
6980 /*** State block ***/
6981 IWineD3DDeviceImpl_BeginStateBlock,
6982 IWineD3DDeviceImpl_EndStateBlock,
6983 /*** Scene management ***/
6984 IWineD3DDeviceImpl_BeginScene,
6985 IWineD3DDeviceImpl_EndScene,
6986 IWineD3DDeviceImpl_Present,
6987 IWineD3DDeviceImpl_Clear,
6989 IWineD3DDeviceImpl_DrawPrimitive,
6990 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6991 IWineD3DDeviceImpl_DrawPrimitiveUP,
6992 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6993 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6994 IWineD3DDeviceImpl_DrawRectPatch,
6995 IWineD3DDeviceImpl_DrawTriPatch,
6996 IWineD3DDeviceImpl_DeletePatch,
6997 IWineD3DDeviceImpl_ColorFill,
6998 IWineD3DDeviceImpl_UpdateTexture,
6999 IWineD3DDeviceImpl_UpdateSurface,
7000 IWineD3DDeviceImpl_StretchRect,
7001 IWineD3DDeviceImpl_GetRenderTargetData,
7002 IWineD3DDeviceImpl_GetFrontBufferData,
7003 /*** Internal use IWineD3DDevice methods ***/
7004 IWineD3DDeviceImpl_SetupTextureStates,
7005 /*** object tracking ***/
7006 IWineD3DDeviceImpl_ResourceReleased
7010 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7011 WINED3DRS_ALPHABLENDENABLE ,
7012 WINED3DRS_ALPHAFUNC ,
7013 WINED3DRS_ALPHAREF ,
7014 WINED3DRS_ALPHATESTENABLE ,
7016 WINED3DRS_COLORWRITEENABLE ,
7017 WINED3DRS_DESTBLEND ,
7018 WINED3DRS_DITHERENABLE ,
7019 WINED3DRS_FILLMODE ,
7020 WINED3DRS_FOGDENSITY ,
7022 WINED3DRS_FOGSTART ,
7023 WINED3DRS_LASTPIXEL ,
7024 WINED3DRS_SHADEMODE ,
7025 WINED3DRS_SRCBLEND ,
7026 WINED3DRS_STENCILENABLE ,
7027 WINED3DRS_STENCILFAIL ,
7028 WINED3DRS_STENCILFUNC ,
7029 WINED3DRS_STENCILMASK ,
7030 WINED3DRS_STENCILPASS ,
7031 WINED3DRS_STENCILREF ,
7032 WINED3DRS_STENCILWRITEMASK ,
7033 WINED3DRS_STENCILZFAIL ,
7034 WINED3DRS_TEXTUREFACTOR ,
7045 WINED3DRS_ZWRITEENABLE
7048 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7049 WINED3DTSS_ADDRESSW ,
7050 WINED3DTSS_ALPHAARG0 ,
7051 WINED3DTSS_ALPHAARG1 ,
7052 WINED3DTSS_ALPHAARG2 ,
7053 WINED3DTSS_ALPHAOP ,
7054 WINED3DTSS_BUMPENVLOFFSET ,
7055 WINED3DTSS_BUMPENVLSCALE ,
7056 WINED3DTSS_BUMPENVMAT00 ,
7057 WINED3DTSS_BUMPENVMAT01 ,
7058 WINED3DTSS_BUMPENVMAT10 ,
7059 WINED3DTSS_BUMPENVMAT11 ,
7060 WINED3DTSS_COLORARG0 ,
7061 WINED3DTSS_COLORARG1 ,
7062 WINED3DTSS_COLORARG2 ,
7063 WINED3DTSS_COLOROP ,
7064 WINED3DTSS_RESULTARG ,
7065 WINED3DTSS_TEXCOORDINDEX ,
7066 WINED3DTSS_TEXTURETRANSFORMFLAGS
7069 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7070 WINED3DSAMP_ADDRESSU ,
7071 WINED3DSAMP_ADDRESSV ,
7072 WINED3DSAMP_ADDRESSW ,
7073 WINED3DSAMP_BORDERCOLOR ,
7074 WINED3DSAMP_MAGFILTER ,
7075 WINED3DSAMP_MINFILTER ,
7076 WINED3DSAMP_MIPFILTER ,
7077 WINED3DSAMP_MIPMAPLODBIAS ,
7078 WINED3DSAMP_MAXMIPLEVEL ,
7079 WINED3DSAMP_MAXANISOTROPY ,
7080 WINED3DSAMP_SRGBTEXTURE ,
7081 WINED3DSAMP_ELEMENTINDEX
7084 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7086 WINED3DRS_AMBIENTMATERIALSOURCE ,
7087 WINED3DRS_CLIPPING ,
7088 WINED3DRS_CLIPPLANEENABLE ,
7089 WINED3DRS_COLORVERTEX ,
7090 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7091 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7092 WINED3DRS_FOGDENSITY ,
7094 WINED3DRS_FOGSTART ,
7095 WINED3DRS_FOGTABLEMODE ,
7096 WINED3DRS_FOGVERTEXMODE ,
7097 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7098 WINED3DRS_LIGHTING ,
7099 WINED3DRS_LOCALVIEWER ,
7100 WINED3DRS_MULTISAMPLEANTIALIAS ,
7101 WINED3DRS_MULTISAMPLEMASK ,
7102 WINED3DRS_NORMALIZENORMALS ,
7103 WINED3DRS_PATCHEDGESTYLE ,
7104 WINED3DRS_POINTSCALE_A ,
7105 WINED3DRS_POINTSCALE_B ,
7106 WINED3DRS_POINTSCALE_C ,
7107 WINED3DRS_POINTSCALEENABLE ,
7108 WINED3DRS_POINTSIZE ,
7109 WINED3DRS_POINTSIZE_MAX ,
7110 WINED3DRS_POINTSIZE_MIN ,
7111 WINED3DRS_POINTSPRITEENABLE ,
7112 WINED3DRS_RANGEFOGENABLE ,
7113 WINED3DRS_SPECULARMATERIALSOURCE ,
7114 WINED3DRS_TWEENFACTOR ,
7115 WINED3DRS_VERTEXBLEND
7118 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7119 WINED3DTSS_TEXCOORDINDEX ,
7120 WINED3DTSS_TEXTURETRANSFORMFLAGS
7123 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7124 WINED3DSAMP_DMAPOFFSET
7127 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7128 DWORD rep = StateTable[state].representative;
7132 if(!rep || isStateDirty(This, rep)) return;
7134 This->dirtyArray[This->numDirtyEntries++] = rep;
7137 This->isStateDirty[idx] |= (1 << shift);