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 /* TODO: Clean up all the surfaces and textures! */
576 /* NOTE: You must release the parent if the object was created via a callback
577 ** ***************************/
579 /* Delete any GLSL shader programs that may exist */
580 if (This->vs_selected_mode == SHADER_GLSL ||
581 This->ps_selected_mode == SHADER_GLSL)
582 delete_glsl_shader_list(iface);
584 /* Release the update stateblock */
585 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
586 if(This->updateStateBlock != This->stateBlock)
587 FIXME("(%p) Something's still holding the Update stateblock\n",This);
589 This->updateStateBlock = NULL;
590 { /* because were not doing proper internal refcounts releasing the primary state block
591 causes recursion with the extra checks in ResourceReleased, to avoid this we have
592 to set this->stateBlock = NULL; first */
593 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
594 This->stateBlock = NULL;
596 /* Release the stateblock */
597 if(IWineD3DStateBlock_Release(stateBlock) > 0){
598 FIXME("(%p) Something's still holding the Update stateblock\n",This);
602 if (This->resources != NULL ) {
603 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
604 dumpResources(This->resources);
608 IWineD3D_Release(This->wineD3D);
609 This->wineD3D = NULL;
610 HeapFree(GetProcessHeap(), 0, This);
611 TRACE("Freed device %p\n", This);
617 /**********************************************************
618 * IWineD3DDevice implementation follows
619 **********************************************************/
620 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
622 *pParent = This->parent;
623 IUnknown_AddRef(This->parent);
627 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
628 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
629 GLenum error, glUsage;
630 DWORD vboUsage = object->resource.usage;
631 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
632 WARN("Creating a vbo failed once, not trying again\n");
636 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
639 /* Make sure that the gl error is cleared. Do not use checkGLcall
640 * here because checkGLcall just prints a fixme and continues. However,
641 * if an error during VBO creation occurs we can fall back to non-vbo operation
642 * with full functionality(but performance loss)
644 while(glGetError() != GL_NO_ERROR);
646 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
647 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
648 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
649 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
650 * to check if the rhw and color values are in the correct format.
653 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
654 error = glGetError();
655 if(object->vbo == 0 || error != GL_NO_ERROR) {
656 WARN("Failed to create a VBO with error %d\n", error);
660 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
661 error = glGetError();
662 if(error != GL_NO_ERROR) {
663 WARN("Failed to bind the VBO, error %d\n", error);
667 /* Transformed vertices are horribly inflexible. If the app specifies an
668 * vertex buffer with transformed vertices in default pool without DYNAMIC
669 * usage assume DYNAMIC usage and print a warning. The app will have to update
670 * the vertices regularily for them to be useful
672 if(((object->fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) &&
673 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
674 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
675 vboUsage |= WINED3DUSAGE_DYNAMIC;
678 /* Don't use static, because dx apps tend to update the buffer
679 * quite often even if they specify 0 usage
681 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
682 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
683 TRACE("Gl usage = GL_STREAM_DRAW\n");
684 glUsage = GL_STREAM_DRAW_ARB;
686 case D3DUSAGE_WRITEONLY:
687 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
688 glUsage = GL_DYNAMIC_DRAW_ARB;
690 case D3DUSAGE_DYNAMIC:
691 TRACE("Gl usage = GL_STREAM_COPY\n");
692 glUsage = GL_STREAM_COPY_ARB;
695 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
696 glUsage = GL_DYNAMIC_COPY_ARB;
700 /* Reserve memory for the buffer. The amount of data won't change
701 * so we are safe with calling glBufferData once with a NULL ptr and
702 * calling glBufferSubData on updates
704 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
705 error = glGetError();
706 if(error != GL_NO_ERROR) {
707 WARN("glBufferDataARB failed with error %d\n", error);
715 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
716 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
717 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
719 object->Flags |= VBFLAG_VBOCREATEFAIL;
724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
725 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVertexBufferImpl *object;
729 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
730 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
732 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
734 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
735 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
737 if(Size == 0) return WINED3DERR_INVALIDCALL;
739 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
740 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
744 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
745 * drawStridedFast (half-life 2).
747 * Basically converting the vertices in the buffer is quite expensive, and observations
748 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
749 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
751 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
752 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
753 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
754 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
756 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
757 * more. In this call we can convert dx7 buffers too.
759 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
760 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
761 (dxVersion > 7 || !conv) ) {
764 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
765 if(dxVersion == 7 && object->vbo) {
766 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
767 object->resource.allocatedMemory = NULL;
774 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
775 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
776 HANDLE *sharedHandle, IUnknown *parent) {
777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
778 IWineD3DIndexBufferImpl *object;
779 TRACE("(%p) Creating index buffer\n", This);
781 /* Allocate the storage for the device */
782 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
785 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
786 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
789 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
790 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
791 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
796 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
799 IWineD3DStateBlockImpl *object;
803 D3DCREATEOBJECTINSTANCE(object, StateBlock)
804 object->blockType = Type;
806 /* Special case - Used during initialization to produce a placeholder stateblock
807 so other functions called can update a state block */
808 if (Type == WINED3DSBT_INIT) {
809 /* Don't bother increasing the reference count otherwise a device will never
810 be freed due to circular dependencies */
814 temp_result = allocate_shader_constants(object);
815 if (WINED3D_OK != temp_result)
818 /* Otherwise, might as well set the whole state block to the appropriate values */
819 if (This->stateBlock != NULL)
820 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
822 memset(object->streamFreq, 1, sizeof(object->streamFreq));
824 /* Reset the ref and type after kludging it */
825 object->wineD3DDevice = This;
827 object->blockType = Type;
829 TRACE("Updating changed flags appropriate for type %d\n", Type);
831 if (Type == WINED3DSBT_ALL) {
833 TRACE("ALL => Pretend everything has changed\n");
834 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
836 } else if (Type == WINED3DSBT_PIXELSTATE) {
838 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
839 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
841 object->changed.pixelShader = TRUE;
843 /* Pixel Shader Constants */
844 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
845 object->changed.pixelShaderConstantsF[i] = TRUE;
846 for (i = 0; i < MAX_CONST_B; ++i)
847 object->changed.pixelShaderConstantsB[i] = TRUE;
848 for (i = 0; i < MAX_CONST_I; ++i)
849 object->changed.pixelShaderConstantsI[i] = TRUE;
851 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
852 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
854 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
855 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
856 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
859 for (j = 0 ; j < 16; j++) {
860 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
862 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
866 } else if (Type == WINED3DSBT_VERTEXSTATE) {
868 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
869 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
871 object->changed.vertexShader = TRUE;
873 /* Vertex Shader Constants */
874 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
875 object->changed.vertexShaderConstantsF[i] = TRUE;
876 for (i = 0; i < MAX_CONST_B; ++i)
877 object->changed.vertexShaderConstantsB[i] = TRUE;
878 for (i = 0; i < MAX_CONST_I; ++i)
879 object->changed.vertexShaderConstantsI[i] = TRUE;
881 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
882 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
884 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
885 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
886 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
889 for (j = 0 ; j < 16; j++){
890 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
891 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
895 /* Duplicate light chain */
897 PLIGHTINFOEL *src = NULL;
898 PLIGHTINFOEL *dst = NULL;
899 PLIGHTINFOEL *newEl = NULL;
900 src = This->stateBlock->lights;
901 object->lights = NULL;
905 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
906 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
907 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
909 newEl->changed = TRUE;
910 newEl->enabledChanged = TRUE;
912 object->lights = newEl;
923 FIXME("Unrecognized state block type %d\n", Type);
926 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
931 /* ************************************
933 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
936 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
938 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
940 ******************************** */
942 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
944 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
945 unsigned int pow2Width, pow2Height;
946 unsigned int Size = 1;
947 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
948 TRACE("(%p) Create surface\n",This);
950 /** FIXME: Check ranges on the inputs are valid
953 * [in] Quality level. The valid range is between zero and one less than the level
954 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
955 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
956 * values of paired render targets, depth stencil surfaces, and the MultiSample type
958 *******************************/
963 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
965 * If this flag is set, the contents of the depth stencil buffer will be
966 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
967 * with a different depth surface.
969 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
970 ***************************/
972 if(MultisampleQuality < 0) {
973 FIXME("Invalid multisample level %d\n", MultisampleQuality);
974 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
977 if(MultisampleQuality > 0) {
978 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
979 MultisampleQuality=0;
982 /** FIXME: Check that the format is supported
984 *******************************/
986 /* Non-power2 support */
987 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
991 /* Find the nearest pow2 match */
992 pow2Width = pow2Height = 1;
993 while (pow2Width < Width) pow2Width <<= 1;
994 while (pow2Height < Height) pow2Height <<= 1;
997 if (pow2Width > Width || pow2Height > Height) {
998 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
999 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
1000 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1001 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
1002 This, Width, Height);
1003 return WINED3DERR_NOTAVAILABLE;
1007 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
1008 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
1010 *********************************/
1011 if (WINED3DFMT_UNKNOWN == Format) {
1013 } else if (Format == WINED3DFMT_DXT1) {
1014 /* DXT1 is half byte per pixel */
1015 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1017 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1018 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1019 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1021 /* The pitch is a multiple of 4 bytes */
1022 Size = ((pow2Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1026 /** Create and initialise the surface resource **/
1027 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1028 /* "Standalone" surface */
1029 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1031 object->currentDesc.Width = Width;
1032 object->currentDesc.Height = Height;
1033 object->currentDesc.MultiSampleType = MultiSample;
1034 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1036 /* Setup some glformat defaults */
1037 object->glDescription.glFormat = tableEntry->glFormat;
1038 object->glDescription.glFormatInternal = tableEntry->glInternal;
1039 object->glDescription.glType = tableEntry->glType;
1041 object->glDescription.textureName = 0;
1042 object->glDescription.level = Level;
1043 object->glDescription.target = GL_TEXTURE_2D;
1046 object->pow2Width = pow2Width;
1047 object->pow2Height = pow2Height;
1050 object->Flags = 0; /* We start without flags set */
1051 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1052 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1053 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1054 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1057 if (WINED3DFMT_UNKNOWN != Format) {
1058 object->bytesPerPixel = tableEntry->bpp;
1059 object->pow2Size = ((pow2Width * object->bytesPerPixel) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1060 object->pow2Size *= pow2Height;
1062 object->bytesPerPixel = 0;
1063 object->pow2Size = 0;
1066 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1068 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1070 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1071 * this function is too deep to need to care about things like this.
1072 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1073 * ****************************************/
1075 case WINED3DPOOL_SCRATCH:
1077 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE \
1078 which are mutually exclusive, setting lockable to true\n");
1081 case WINED3DPOOL_SYSTEMMEM:
1082 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1083 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1084 case WINED3DPOOL_MANAGED:
1085 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1086 Usage of DYNAMIC which are mutually exclusive, not doing \
1087 anything just telling you.\n");
1089 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1090 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1091 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1092 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1095 FIXME("(%p) Unknown pool %d\n", This, Pool);
1099 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1100 FIXME("Trying to create a render target that isn't in the default pool\n");
1103 /* mark the texture as dirty so that it gets loaded first time around*/
1104 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1105 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1106 This, Width, Height, Format, debug_d3dformat(Format),
1107 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1109 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1110 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1111 This->ddraw_primary = (IWineD3DSurface *) object;
1113 /* Look at the implementation and set the correct Vtable */
1115 case SURFACE_OPENGL:
1116 /* Nothing to do, it's set already */
1120 object->lpVtbl = &IWineGDISurface_Vtbl;
1124 /* To be sure to catch this */
1125 ERR("Unknown requested surface implementation %d!\n", Impl);
1126 IWineD3DSurface_Release((IWineD3DSurface *) object);
1127 return WINED3DERR_INVALIDCALL;
1130 /* Call the private setup routine */
1131 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1136 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1137 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1138 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141 IWineD3DTextureImpl *object;
1146 unsigned int pow2Width;
1147 unsigned int pow2Height;
1150 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1151 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1152 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1154 /* TODO: It should only be possible to create textures for formats
1155 that are reported as supported */
1156 if (WINED3DFMT_UNKNOWN >= Format) {
1157 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1158 return WINED3DERR_INVALIDCALL;
1161 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1162 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1163 object->width = Width;
1164 object->height = Height;
1166 /** Non-power2 support **/
1167 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1169 pow2Height = Height;
1171 /* Find the nearest pow2 match */
1172 pow2Width = pow2Height = 1;
1173 while (pow2Width < Width) pow2Width <<= 1;
1174 while (pow2Height < Height) pow2Height <<= 1;
1177 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1178 /* Precalculated scaling for 'faked' non power of two texture coords */
1179 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1180 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1181 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1183 /* Calculate levels for mip mapping */
1185 TRACE("calculating levels %d\n", object->baseTexture.levels);
1186 object->baseTexture.levels++;
1189 while (tmpW > 1 || tmpH > 1) {
1190 tmpW = max(1, tmpW >> 1);
1191 tmpH = max(1, tmpH >> 1);
1192 object->baseTexture.levels++;
1194 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1197 /* Generate all the surfaces */
1200 for (i = 0; i < object->baseTexture.levels; i++)
1202 /* use the callback to create the texture surface */
1203 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1204 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1205 FIXME("Failed to create surface %p\n", object);
1207 object->surfaces[i] = NULL;
1208 IWineD3DTexture_Release((IWineD3DTexture *)object);
1214 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1215 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1216 /* calculate the next mipmap level */
1217 tmpW = max(1, tmpW >> 1);
1218 tmpH = max(1, tmpH >> 1);
1221 TRACE("(%p) : Created texture %p\n", This, object);
1225 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1226 UINT Width, UINT Height, UINT Depth,
1227 UINT Levels, DWORD Usage,
1228 WINED3DFORMAT Format, WINED3DPOOL Pool,
1229 IWineD3DVolumeTexture **ppVolumeTexture,
1230 HANDLE *pSharedHandle, IUnknown *parent,
1231 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 IWineD3DVolumeTextureImpl *object;
1240 /* TODO: It should only be possible to create textures for formats
1241 that are reported as supported */
1242 if (WINED3DFMT_UNKNOWN >= Format) {
1243 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1244 return WINED3DERR_INVALIDCALL;
1247 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1248 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1250 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1251 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1253 object->width = Width;
1254 object->height = Height;
1255 object->depth = Depth;
1257 /* Calculate levels for mip mapping */
1259 object->baseTexture.levels++;
1263 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1264 tmpW = max(1, tmpW >> 1);
1265 tmpH = max(1, tmpH >> 1);
1266 tmpD = max(1, tmpD >> 1);
1267 object->baseTexture.levels++;
1269 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1272 /* Generate all the surfaces */
1277 for (i = 0; i < object->baseTexture.levels; i++)
1279 /* Create the volume */
1280 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1281 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1283 /* Set its container to this object */
1284 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1286 /* calcualte the next mipmap level */
1287 tmpW = max(1, tmpW >> 1);
1288 tmpH = max(1, tmpH >> 1);
1289 tmpD = max(1, tmpD >> 1);
1292 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1293 TRACE("(%p) : Created volume texture %p\n", This, object);
1297 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1298 UINT Width, UINT Height, UINT Depth,
1300 WINED3DFORMAT Format, WINED3DPOOL Pool,
1301 IWineD3DVolume** ppVolume,
1302 HANDLE* pSharedHandle, IUnknown *parent) {
1304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1306 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1308 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1310 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1311 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1313 object->currentDesc.Width = Width;
1314 object->currentDesc.Height = Height;
1315 object->currentDesc.Depth = Depth;
1316 object->bytesPerPixel = formatDesc->bpp;
1318 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1319 object->lockable = TRUE;
1320 object->locked = FALSE;
1321 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1322 object->dirty = TRUE;
1324 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1328 UINT Levels, DWORD Usage,
1329 WINED3DFORMAT Format, WINED3DPOOL Pool,
1330 IWineD3DCubeTexture **ppCubeTexture,
1331 HANDLE *pSharedHandle, IUnknown *parent,
1332 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1335 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1339 unsigned int pow2EdgeLength = EdgeLength;
1341 /* TODO: It should only be possible to create textures for formats
1342 that are reported as supported */
1343 if (WINED3DFMT_UNKNOWN >= Format) {
1344 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1345 return WINED3DERR_INVALIDCALL;
1348 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1349 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1351 TRACE("(%p) Create Cube Texture\n", This);
1353 /** Non-power2 support **/
1355 /* Find the nearest pow2 match */
1357 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1359 object->edgeLength = EdgeLength;
1360 /* TODO: support for native non-power 2 */
1361 /* Precalculated scaling for 'faked' non power of two texture coords */
1362 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1364 /* Calculate levels for mip mapping */
1366 object->baseTexture.levels++;
1369 tmpW = max(1, tmpW >> 1);
1370 object->baseTexture.levels++;
1372 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1375 /* Generate all the surfaces */
1377 for (i = 0; i < object->baseTexture.levels; i++) {
1379 /* Create the 6 faces */
1380 for (j = 0; j < 6; j++) {
1382 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1383 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1385 if(hr!= WINED3D_OK) {
1389 for (l = 0; l < j; l++) {
1390 IWineD3DSurface_Release(object->surfaces[j][i]);
1392 for (k = 0; k < i; k++) {
1393 for (l = 0; l < 6; l++) {
1394 IWineD3DSurface_Release(object->surfaces[l][j]);
1398 FIXME("(%p) Failed to create surface\n",object);
1399 HeapFree(GetProcessHeap(),0,object);
1400 *ppCubeTexture = NULL;
1403 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1404 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1406 tmpW = max(1, tmpW >> 1);
1409 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1410 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1414 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1416 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1418 if (NULL == ppQuery) {
1419 /* Just a check to see if we support this type of query */
1420 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1422 case WINED3DQUERYTYPE_OCCLUSION:
1423 TRACE("(%p) occlusion query\n", This);
1424 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1427 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1429 case WINED3DQUERYTYPE_VCACHE:
1430 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1431 case WINED3DQUERYTYPE_VERTEXSTATS:
1432 case WINED3DQUERYTYPE_EVENT:
1433 case WINED3DQUERYTYPE_TIMESTAMP:
1434 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1435 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1436 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1437 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1438 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1439 case WINED3DQUERYTYPE_PIXELTIMINGS:
1440 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1441 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1443 FIXME("(%p) Unhandled query type %d\n", This, Type);
1448 D3DCREATEOBJECTINSTANCE(object, Query)
1449 object->type = Type;
1450 /* allocated the 'extended' data based on the type of query requested */
1452 case WINED3DQUERYTYPE_OCCLUSION:
1453 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1454 TRACE("(%p) Allocating data for an occlusion query\n", This);
1455 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1456 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1459 case WINED3DQUERYTYPE_VCACHE:
1460 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1461 case WINED3DQUERYTYPE_VERTEXSTATS:
1462 case WINED3DQUERYTYPE_EVENT:
1463 case WINED3DQUERYTYPE_TIMESTAMP:
1464 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1465 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1466 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1467 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1468 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1469 case WINED3DQUERYTYPE_PIXELTIMINGS:
1470 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1471 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1473 object->extendedData = 0;
1474 FIXME("(%p) Unhandled query type %d\n",This , Type);
1476 TRACE("(%p) : Created Query %p\n", This, object);
1480 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1483 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1484 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1488 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1490 XVisualInfo template;
1491 GLXContext oldContext;
1492 Drawable oldDrawable;
1493 HRESULT hr = WINED3D_OK;
1495 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1497 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1498 * does a device hold a reference to a swap chain giving them a lifetime of the device
1499 * or does the swap chain notify the device of its destruction.
1500 *******************************/
1502 /* Check the params */
1503 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1504 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1505 return WINED3DERR_INVALIDCALL;
1506 } else if (*pPresentationParameters->BackBufferCount > 1) {
1507 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1510 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1512 /*********************
1513 * Lookup the window Handle and the relating X window handle
1514 ********************/
1516 /* Setup hwnd we are using, plus which display this equates to */
1517 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1518 if (!object->win_handle) {
1519 object->win_handle = This->createParms.hFocusWindow;
1522 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1523 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1524 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1525 return WINED3DERR_NOTAVAILABLE;
1527 hDc = GetDC(object->win_handle);
1528 object->display = get_display(hDc);
1529 ReleaseDC(object->win_handle, hDc);
1530 TRACE("Using a display of %p %p\n", object->display, hDc);
1532 if (NULL == object->display || NULL == hDc) {
1533 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1534 return WINED3DERR_NOTAVAILABLE;
1537 if (object->win == 0) {
1538 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1539 return WINED3DERR_NOTAVAILABLE;
1542 * Create an opengl context for the display visual
1543 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1544 * use different properties after that point in time. FIXME: How to handle when requested format
1545 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1546 * it chooses is identical to the one already being used!
1547 **********************************/
1549 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1552 /* Create a new context for this swapchain */
1553 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1554 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1555 (or the best possible if none is requested) */
1556 TRACE("Found x visual ID : %ld\n", template.visualid);
1558 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1559 if (NULL == object->visInfo) {
1560 ERR("cannot really get XVisual\n");
1562 return WINED3DERR_NOTAVAILABLE;
1565 /* Write out some debug info about the visual/s */
1566 TRACE("Using x visual ID : %ld\n", template.visualid);
1567 TRACE(" visual info: %p\n", object->visInfo);
1568 TRACE(" num items : %d\n", num);
1569 for (n = 0;n < num; n++) {
1570 TRACE("=====item=====: %d\n", n + 1);
1571 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1572 TRACE(" screen : %d\n", object->visInfo[n].screen);
1573 TRACE(" depth : %u\n", object->visInfo[n].depth);
1574 TRACE(" class : %d\n", object->visInfo[n].class);
1575 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1576 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1577 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1578 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1579 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1580 /* log some extra glx info */
1581 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1582 TRACE(" gl_aux_buffers : %d\n", value);
1583 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1584 TRACE(" gl_buffer_size : %d\n", value);
1585 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1586 TRACE(" gl_red_size : %d\n", value);
1587 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1588 TRACE(" gl_green_size : %d\n", value);
1589 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1590 TRACE(" gl_blue_size : %d\n", value);
1591 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1592 TRACE(" gl_alpha_size : %d\n", value);
1593 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1594 TRACE(" gl_depth_size : %d\n", value);
1595 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1596 TRACE(" gl_stencil_size : %d\n", value);
1598 /* Now choose a similar visual ID*/
1600 #ifdef USE_CONTEXT_MANAGER
1602 /** TODO: use a context mamager **/
1606 IWineD3DSwapChain *implSwapChain;
1607 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1608 /* The first time around we create the context that is shared with all other swapchains and render targets */
1609 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1610 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1613 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1614 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1615 /* and create a new context with the implicit swapchains context as the shared context */
1616 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1621 XFree(object->visInfo);
1622 object->visInfo = NULL;
1626 if (!object->glCtx) {
1627 ERR("Failed to create GLX context\n");
1628 return WINED3DERR_NOTAVAILABLE;
1630 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1631 object->win_handle, object->glCtx, object->win, object->visInfo);
1634 /*********************
1635 * Windowed / Fullscreen
1636 *******************/
1639 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1640 * so we should really check to see if there is a fullscreen swapchain already
1641 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1642 **************************************/
1644 if (!*(pPresentationParameters->Windowed)) {
1650 /* Get info on the current display setup */
1651 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1652 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1655 /* Change the display settings */
1656 memset(&devmode, 0, sizeof(DEVMODEW));
1657 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1658 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1659 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1660 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1661 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1662 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1664 /* Make popup window */
1665 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1666 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1667 *(pPresentationParameters->BackBufferWidth),
1668 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1670 /* For GetDisplayMode */
1671 This->ddraw_width = devmode.dmPelsWidth;
1672 This->ddraw_height = devmode.dmPelsHeight;
1673 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1677 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1678 * then the corresponding dimension of the client area of the hDeviceWindow
1679 * (or the focus window, if hDeviceWindow is NULL) is taken.
1680 **********************/
1682 if (*(pPresentationParameters->Windowed) &&
1683 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1684 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1687 GetClientRect(object->win_handle, &Rect);
1689 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1690 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1691 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1693 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1694 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1695 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1699 /*********************
1700 * finish off parameter initialization
1701 *******************/
1703 /* Put the correct figures in the presentation parameters */
1704 TRACE("Copying across presentation parameters\n");
1705 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1706 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1707 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1708 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1709 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1710 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1711 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1712 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1713 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1714 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1715 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1716 object->presentParms.Flags = *(pPresentationParameters->Flags);
1717 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1718 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1721 /*********************
1722 * Create the back, front and stencil buffers
1723 *******************/
1725 TRACE("calling rendertarget CB\n");
1726 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1727 object->presentParms.BackBufferWidth,
1728 object->presentParms.BackBufferHeight,
1729 object->presentParms.BackBufferFormat,
1730 object->presentParms.MultiSampleType,
1731 object->presentParms.MultiSampleQuality,
1732 TRUE /* Lockable */,
1733 &object->frontBuffer,
1734 NULL /* pShared (always null)*/);
1735 if (object->frontBuffer != NULL)
1736 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1738 if(object->presentParms.BackBufferCount > 0) {
1741 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1742 if(!object->backBuffer) {
1743 ERR("Out of memory\n");
1745 if (object->frontBuffer) {
1746 IUnknown *bufferParent;
1747 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1748 IUnknown_Release(bufferParent); /* once for the get parent */
1749 if (IUnknown_Release(bufferParent) > 0) {
1750 FIXME("(%p) Something's still holding the front buffer\n",This);
1753 HeapFree(GetProcessHeap(), 0, object);
1754 return E_OUTOFMEMORY;
1757 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1758 TRACE("calling rendertarget CB\n");
1759 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1760 object->presentParms.BackBufferWidth,
1761 object->presentParms.BackBufferHeight,
1762 object->presentParms.BackBufferFormat,
1763 object->presentParms.MultiSampleType,
1764 object->presentParms.MultiSampleQuality,
1765 TRUE /* Lockable */,
1766 &object->backBuffer[i],
1767 NULL /* pShared (always null)*/);
1768 if(hr == WINED3D_OK && object->backBuffer[i]) {
1769 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1775 object->backBuffer = NULL;
1778 if (object->backBuffer != NULL) {
1780 glDrawBuffer(GL_BACK);
1781 checkGLcall("glDrawBuffer(GL_BACK)");
1784 /* Single buffering - draw to front buffer */
1786 glDrawBuffer(GL_FRONT);
1787 checkGLcall("glDrawBuffer(GL_FRONT)");
1791 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1792 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1793 TRACE("Creating depth stencil buffer\n");
1794 if (This->depthStencilBuffer == NULL ) {
1795 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1796 object->presentParms.BackBufferWidth,
1797 object->presentParms.BackBufferHeight,
1798 object->presentParms.AutoDepthStencilFormat,
1799 object->presentParms.MultiSampleType,
1800 object->presentParms.MultiSampleQuality,
1801 FALSE /* FIXME: Discard */,
1802 &This->depthStencilBuffer,
1803 NULL /* pShared (always null)*/ );
1804 if (This->depthStencilBuffer != NULL)
1805 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1808 /** TODO: A check on width, height and multisample types
1809 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1810 ****************************/
1811 object->wantsDepthStencilBuffer = TRUE;
1813 object->wantsDepthStencilBuffer = FALSE;
1816 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1819 /*********************
1820 * init the default renderTarget management
1821 *******************/
1822 object->drawable = object->win;
1823 object->render_ctx = object->glCtx;
1825 if (hr == WINED3D_OK) {
1826 /*********************
1827 * Setup some defaults and clear down the buffers
1828 *******************/
1830 /** save current context and drawable **/
1831 oldContext = glXGetCurrentContext();
1832 oldDrawable = glXGetCurrentDrawable();
1834 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1835 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1836 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1838 checkGLcall("glXMakeCurrent");
1840 TRACE("Setting up the screen\n");
1841 /* Clear the screen */
1842 glClearColor(1.0, 0.0, 0.0, 0.0);
1843 checkGLcall("glClearColor");
1846 glClearStencil(0xffff);
1848 checkGLcall("glClear");
1850 glColor3f(1.0, 1.0, 1.0);
1851 checkGLcall("glColor3f");
1853 glEnable(GL_LIGHTING);
1854 checkGLcall("glEnable");
1856 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1857 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1859 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1860 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1862 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1863 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1865 /* switch back to the original context (if there was one)*/
1866 if (This->swapchains) {
1867 /** TODO: restore the context and drawable **/
1868 glXMakeCurrent(object->display, oldDrawable, oldContext);
1871 /* Set the surface alignment. This never changes, so we are safe to set it once per context*/
1872 glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);
1873 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1874 glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);
1875 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, SURFACE_ALIGNMENT);");
1879 TRACE("Set swapchain to %p\n", object);
1880 } else { /* something went wrong so clean up */
1881 IUnknown* bufferParent;
1882 if (object->frontBuffer) {
1884 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1885 IUnknown_Release(bufferParent); /* once for the get parent */
1886 if (IUnknown_Release(bufferParent) > 0) {
1887 FIXME("(%p) Something's still holding the front buffer\n",This);
1890 if (object->backBuffer) {
1892 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1893 if(object->backBuffer[i]) {
1894 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1895 IUnknown_Release(bufferParent); /* once for the get parent */
1896 if (IUnknown_Release(bufferParent) > 0) {
1897 FIXME("(%p) Something's still holding the back buffer\n",This);
1901 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1902 object->backBuffer = NULL;
1904 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1905 /* Clean up the context */
1906 /* check that we are the current context first (we shouldn't be though!) */
1907 if (object->glCtx != 0) {
1908 if(glXGetCurrentContext() == object->glCtx) {
1909 glXMakeCurrent(object->display, None, NULL);
1911 glXDestroyContext(object->display, object->glCtx);
1913 HeapFree(GetProcessHeap(), 0, object);
1920 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1921 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1923 TRACE("(%p)\n", This);
1925 return This->NumberOfSwapChains;
1928 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1930 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1932 if(iSwapChain < This->NumberOfSwapChains) {
1933 *pSwapChain = This->swapchains[iSwapChain];
1934 TRACE("(%p) returning %p\n", This, *pSwapChain);
1937 TRACE("Swapchain out of range\n");
1939 return WINED3DERR_INVALIDCALL;
1944 * Vertex Declaration
1946 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1948 IWineD3DVertexDeclarationImpl *object = NULL;
1949 HRESULT hr = WINED3D_OK;
1950 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1951 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1954 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1959 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1960 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1962 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1963 HRESULT hr = WINED3D_OK;
1964 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1965 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1967 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1969 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1970 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1971 if (pDeclaration != NULL) {
1972 IWineD3DVertexDeclaration *vertexDeclaration;
1973 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1974 if (WINED3D_OK == hr) {
1975 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1976 object->vertexDeclaration = vertexDeclaration;
1978 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1979 IWineD3DVertexShader_Release(*ppVertexShader);
1980 return WINED3DERR_INVALIDCALL;
1984 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1986 if (WINED3D_OK != hr) {
1987 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1988 IWineD3DVertexShader_Release(*ppVertexShader);
1989 return WINED3DERR_INVALIDCALL;
1992 #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. */
1993 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
2004 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2006 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2007 HRESULT hr = WINED3D_OK;
2009 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
2010 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
2011 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2012 if (WINED3D_OK == hr) {
2013 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
2015 WARN("(%p) : Failed to create pixel shader\n", This);
2021 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2023 IWineD3DPaletteImpl *object;
2025 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2027 /* Create the new object */
2028 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2030 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2031 return E_OUTOFMEMORY;
2034 object->lpVtbl = &IWineD3DPalette_Vtbl;
2036 object->Flags = Flags;
2037 object->parent = Parent;
2038 object->wineD3DDevice = This;
2039 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2041 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2044 HeapFree( GetProcessHeap(), 0, object);
2045 return E_OUTOFMEMORY;
2048 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2050 IWineD3DPalette_Release((IWineD3DPalette *) object);
2054 *Palette = (IWineD3DPalette *) object;
2059 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2061 IWineD3DSwapChainImpl *swapchain;
2063 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2064 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2066 /* TODO: Test if OpenGL is compiled in and loaded */
2068 /* Setup the implicit swapchain */
2069 TRACE("Creating implicit swapchain\n");
2070 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2071 WARN("Failed to create implicit swapchain\n");
2072 return WINED3DERR_INVALIDCALL;
2075 This->NumberOfSwapChains = 1;
2076 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2077 if(!This->swapchains) {
2078 ERR("Out of memory!\n");
2079 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2080 return E_OUTOFMEMORY;
2082 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2084 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2085 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2086 This->renderTarget = swapchain->backBuffer[0];
2089 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2090 This->renderTarget = swapchain->frontBuffer;
2092 IWineD3DSurface_AddRef(This->renderTarget);
2093 /* Depth Stencil support */
2094 This->stencilBufferTarget = This->depthStencilBuffer;
2095 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2096 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
2098 if (NULL != This->stencilBufferTarget) {
2099 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2102 /* Set up some starting GL setup */
2105 * Initialize openGL extension related variables
2106 * with Default values
2109 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2110 /* Setup all the devices defaults */
2111 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2113 IWineD3DImpl_CheckGraphicsMemory();
2117 /* Initialize our list of GLSL programs */
2118 list_init(&This->glsl_shader_progs);
2120 { /* Set a default viewport */
2124 vp.Width = *(pPresentationParameters->BackBufferWidth);
2125 vp.Height = *(pPresentationParameters->BackBufferHeight);
2128 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2131 /* Initialize the current view state */
2132 This->modelview_valid = 1;
2133 This->proj_valid = 0;
2134 This->view_ident = 1;
2135 This->last_was_rhw = 0;
2136 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2137 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2139 /* Clear the screen */
2140 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
2142 This->d3d_initialized = TRUE;
2146 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2149 IUnknown* stencilBufferParent;
2150 IUnknown* swapChainParent;
2152 TRACE("(%p)\n", This);
2154 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2156 /* Delete the mouse cursor texture */
2157 if(This->cursorTexture) {
2159 glDeleteTextures(1, &This->cursorTexture);
2161 This->cursorTexture = 0;
2164 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2165 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2168 /* Release the buffers (with sanity checks)*/
2169 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2170 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2171 if(This->depthStencilBuffer != This->stencilBufferTarget)
2172 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2174 This->stencilBufferTarget = NULL;
2176 TRACE("Releasing the render target at %p\n", This->renderTarget);
2177 if(IWineD3DSurface_Release(This->renderTarget) >0){
2178 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2180 TRACE("Setting rendertarget to NULL\n");
2181 This->renderTarget = NULL;
2183 if (This->depthStencilBuffer) {
2184 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2185 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2186 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2187 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2189 This->depthStencilBuffer = NULL;
2192 for(i=0; i < This->NumberOfSwapChains; i++) {
2193 TRACE("Releasing the implicit swapchain %d\n", i);
2194 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2195 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2196 IUnknown_Release(swapChainParent); /* once for the get parent */
2197 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2198 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2202 HeapFree(GetProcessHeap(), 0, This->swapchains);
2203 This->swapchains = NULL;
2204 This->NumberOfSwapChains = 0;
2206 This->d3d_initialized = FALSE;
2210 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2212 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2214 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2215 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2216 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2219 This->ddraw_fullscreen = fullscreen;
2222 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2227 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2229 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2231 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2232 /* Ignore some modes if a description was passed */
2233 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2234 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2235 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2237 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2239 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2246 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2250 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2252 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2254 /* Resize the screen even without a window:
2255 * The app could have unset it with SetCooperativeLevel, but not called
2256 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2257 * but we don't have any hwnd
2260 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2261 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2262 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2263 devmode.dmPelsWidth = pMode->Width;
2264 devmode.dmPelsHeight = pMode->Height;
2266 devmode.dmDisplayFrequency = pMode->RefreshRate;
2267 if (pMode->RefreshRate != 0) {
2268 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2271 /* Only change the mode if necessary */
2272 if( (This->ddraw_width == pMode->Width) &&
2273 (This->ddraw_height == pMode->Height) &&
2274 (This->ddraw_format == pMode->Format) &&
2275 (pMode->RefreshRate == 0) ) {
2279 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2280 if (ret != DISP_CHANGE_SUCCESSFUL) {
2281 if(devmode.dmDisplayFrequency != 0) {
2282 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2283 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2284 devmode.dmDisplayFrequency = 0;
2285 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2287 if(ret != DISP_CHANGE_SUCCESSFUL) {
2288 return DDERR_INVALIDMODE;
2292 /* Store the new values */
2293 This->ddraw_width = pMode->Width;
2294 This->ddraw_height = pMode->Height;
2295 This->ddraw_format = pMode->Format;
2297 /* Only do this with a window of course */
2298 if(This->ddraw_window)
2299 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2304 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2306 *ppD3D= This->wineD3D;
2307 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2311 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2312 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2313 * into the video ram as possible and seeing how many fit
2314 * you can also get the correct initial value from nvidia and ATI's driver via X
2315 * texture memory is video memory + AGP memory
2316 *******************/
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 static BOOL showfixmes = TRUE;
2320 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2321 (wined3d_settings.emulated_textureram/(1024*1024)),
2322 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2325 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2326 (wined3d_settings.emulated_textureram/(1024*1024)),
2327 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2328 /* return simulated texture memory left */
2329 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2337 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2339 HRESULT hr = WINED3D_OK;
2341 /* Update the current state block */
2342 This->updateStateBlock->fvf = fvf;
2343 This->updateStateBlock->changed.fvf = TRUE;
2344 This->updateStateBlock->set.fvf = TRUE;
2346 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2351 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2354 *pfvf = This->stateBlock->fvf;
2359 * Get / Set Stream Source
2361 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2363 IWineD3DVertexBuffer *oldSrc;
2365 /**TODO: instance and index data, see
2366 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2368 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2371 /* D3d9 only, but shouldn't hurt d3d8 */
2374 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2376 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2377 FIXME("stream index data not supported\n");
2379 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2380 FIXME("stream instance data not supported\n");
2384 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2386 if (StreamNumber >= MAX_STREAMS) {
2387 WARN("Stream out of range %d\n", StreamNumber);
2388 return WINED3DERR_INVALIDCALL;
2391 oldSrc = This->stateBlock->streamSource[StreamNumber];
2392 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2394 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2395 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2396 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2397 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2398 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2399 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2401 /* Handle recording of state blocks */
2402 if (This->isRecordingState) {
2403 TRACE("Recording... not performing anything\n");
2407 /* Same stream object: no action */
2408 if (oldSrc == pStreamData)
2411 /* Need to do a getParent and pass the reffs up */
2412 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2413 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2414 so for now, just count internally */
2415 if (pStreamData != NULL) {
2416 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2417 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2418 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2420 vbImpl->stream = StreamNumber;
2421 vbImpl->Flags |= VBFLAG_STREAM;
2422 IWineD3DVertexBuffer_AddRef(pStreamData);
2424 if (oldSrc != NULL) {
2425 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2426 IWineD3DVertexBuffer_Release(oldSrc);
2432 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2436 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2437 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2440 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2442 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2443 FIXME("stream index data not supported\n");
2445 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2446 FIXME("stream instance data not supported\n");
2450 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2452 if (StreamNumber >= MAX_STREAMS) {
2453 WARN("Stream out of range %d\n", StreamNumber);
2454 return WINED3DERR_INVALIDCALL;
2456 *pStream = This->stateBlock->streamSource[StreamNumber];
2457 *pStride = This->stateBlock->streamStride[StreamNumber];
2459 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2462 if (*pStream == NULL) {
2463 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2464 return WINED3DERR_INVALIDCALL;
2470 /*Should be quite easy, just an extension of vertexdata
2472 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2474 The divider is a bit odd though
2476 VertexOffset = StartVertex / Divider * StreamStride +
2477 VertexIndex / Divider * StreamStride + StreamOffset
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2484 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2486 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2487 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2488 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2490 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2491 FIXME("Stream indexing not fully supported\n");
2497 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2501 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2503 TRACE("(%p) : returning %d\n", This, *Divider);
2509 * Get / Set & Multiply Transform
2511 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 /* Most of this routine, comments included copied from ddraw tree initially: */
2515 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2517 /* Handle recording of state blocks */
2518 if (This->isRecordingState) {
2519 TRACE("Recording... not performing anything\n");
2520 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2521 This->updateStateBlock->set.transform[d3dts] = TRUE;
2522 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2527 * If the new matrix is the same as the current one,
2528 * we cut off any further processing. this seems to be a reasonable
2529 * optimization because as was noticed, some apps (warcraft3 for example)
2530 * tend towards setting the same matrix repeatedly for some reason.
2532 * From here on we assume that the new matrix is different, wherever it matters.
2534 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2535 TRACE("The app is setting the same matrix over again\n");
2538 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2542 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2543 where ViewMat = Camera space, WorldMat = world space.
2545 In OpenGL, camera and world space is combined into GL_MODELVIEW
2546 matrix. The Projection matrix stay projection matrix.
2549 /* Capture the times we can just ignore the change for now */
2550 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2551 This->modelview_valid = FALSE;
2554 } else if (d3dts == WINED3DTS_PROJECTION) {
2555 This->proj_valid = FALSE;
2558 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2559 /* Indexed Vertex Blending Matrices 256 -> 511 */
2560 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2561 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2565 /* Now we really are going to have to change a matrix */
2568 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2569 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2570 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2573 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2574 * NOTE: We have to reset the positions even if the light/plane is not currently
2575 * enabled, since the call to enable it will not reset the position.
2576 * NOTE2: Apparently texture transforms do NOT need reapplying
2579 PLIGHTINFOEL *lightChain = NULL;
2580 This->modelview_valid = FALSE;
2581 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2583 glMatrixMode(GL_MODELVIEW);
2584 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2586 glLoadMatrixf((const float *)lpmatrix);
2587 checkGLcall("glLoadMatrixf(...)");
2590 lightChain = This->stateBlock->lights;
2591 while (lightChain && lightChain->glIndex != -1) {
2592 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2593 checkGLcall("glLightfv posn");
2594 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2595 checkGLcall("glLightfv dirn");
2596 lightChain = lightChain->next;
2599 /* Reset Clipping Planes if clipping is enabled */
2600 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2601 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2602 checkGLcall("glClipPlane");
2606 } else { /* What was requested!?? */
2607 WARN("invalid matrix specified: %i\n", d3dts);
2610 /* Release lock, all done */
2615 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2618 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2622 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2623 WINED3DMATRIX *mat = NULL;
2626 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2627 * below means it will be recorded in a state block change, but it
2628 * works regardless where it is recorded.
2629 * If this is found to be wrong, change to StateBlock.
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2634 if (State < HIGHEST_TRANSFORMSTATE)
2636 mat = &This->updateStateBlock->transforms[State];
2638 FIXME("Unhandled transform state!!\n");
2641 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2643 /* Apply change via set transform - will reapply to eg. lights this way */
2644 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2650 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2651 you can reference any indexes you want as long as that number max are enabled at any
2652 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2653 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2654 but when recording, just build a chain pretty much of commands to be replayed. */
2656 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2658 PLIGHTINFOEL *object, *temp;
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2663 /* If recording state block, just add to end of lights chain */
2664 if (This->isRecordingState) {
2665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2666 if (NULL == object) {
2667 return WINED3DERR_OUTOFVIDEOMEMORY;
2669 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2670 object->OriginalIndex = Index;
2671 object->glIndex = -1;
2672 object->changed = TRUE;
2674 /* Add to the END of the chain of lights changes to be replayed */
2675 if (This->updateStateBlock->lights == NULL) {
2676 This->updateStateBlock->lights = object;
2678 temp = This->updateStateBlock->lights;
2679 while (temp->next != NULL) temp=temp->next;
2680 temp->next = object;
2682 TRACE("Recording... not performing anything more\n");
2686 /* Ok, not recording any longer so do real work */
2687 object = This->stateBlock->lights;
2688 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2690 /* If we didn't find it in the list of lights, time to add it */
2691 if (object == NULL) {
2692 PLIGHTINFOEL *insertAt,*prevPos;
2694 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2695 if (NULL == object) {
2696 return WINED3DERR_OUTOFVIDEOMEMORY;
2698 object->OriginalIndex = Index;
2699 object->glIndex = -1;
2701 /* Add it to the front of list with the idea that lights will be changed as needed
2702 BUT after any lights currently assigned GL indexes */
2703 insertAt = This->stateBlock->lights;
2705 while (insertAt != NULL && insertAt->glIndex != -1) {
2707 insertAt = insertAt->next;
2710 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2711 This->stateBlock->lights = object;
2712 } else if (insertAt == NULL) { /* End of list */
2713 prevPos->next = object;
2714 object->prev = prevPos;
2715 } else { /* Middle of chain */
2716 if (prevPos == NULL) {
2717 This->stateBlock->lights = object;
2719 prevPos->next = object;
2721 object->prev = prevPos;
2722 object->next = insertAt;
2723 insertAt->prev = object;
2727 /* Initialize the object */
2728 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,
2729 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2730 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2731 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2732 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2733 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2734 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2736 /* Save away the information */
2737 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2739 switch (pLight->Type) {
2740 case WINED3DLIGHT_POINT:
2742 object->lightPosn[0] = pLight->Position.x;
2743 object->lightPosn[1] = pLight->Position.y;
2744 object->lightPosn[2] = pLight->Position.z;
2745 object->lightPosn[3] = 1.0f;
2746 object->cutoff = 180.0f;
2750 case WINED3DLIGHT_DIRECTIONAL:
2752 object->lightPosn[0] = -pLight->Direction.x;
2753 object->lightPosn[1] = -pLight->Direction.y;
2754 object->lightPosn[2] = -pLight->Direction.z;
2755 object->lightPosn[3] = 0.0;
2756 object->exponent = 0.0f;
2757 object->cutoff = 180.0f;
2760 case WINED3DLIGHT_SPOT:
2762 object->lightPosn[0] = pLight->Position.x;
2763 object->lightPosn[1] = pLight->Position.y;
2764 object->lightPosn[2] = pLight->Position.z;
2765 object->lightPosn[3] = 1.0;
2768 object->lightDirn[0] = pLight->Direction.x;
2769 object->lightDirn[1] = pLight->Direction.y;
2770 object->lightDirn[2] = pLight->Direction.z;
2771 object->lightDirn[3] = 1.0;
2774 * opengl-ish and d3d-ish spot lights use too different models for the
2775 * light "intensity" as a function of the angle towards the main light direction,
2776 * so we only can approximate very roughly.
2777 * however spot lights are rather rarely used in games (if ever used at all).
2778 * furthermore if still used, probably nobody pays attention to such details.
2780 if (pLight->Falloff == 0) {
2783 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2785 if (rho < 0.0001) rho = 0.0001f;
2786 object->exponent = -0.3/log(cos(rho/2));
2787 if (object->exponent > 128.0) {
2788 object->exponent = 128.0;
2790 object->cutoff = pLight->Phi*90/M_PI;
2796 FIXME("Unrecognized light type %d\n", pLight->Type);
2799 /* Update the live definitions if the light is currently assigned a glIndex */
2800 if (object->glIndex != -1) {
2801 setup_light(iface, object->glIndex, object);
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2807 PLIGHTINFOEL *lightInfo = NULL;
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2811 /* Locate the light in the live lights */
2812 lightInfo = This->stateBlock->lights;
2813 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2815 if (lightInfo == NULL) {
2816 TRACE("Light information requested but light not defined\n");
2817 return WINED3DERR_INVALIDCALL;
2820 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2825 * Get / Set Light Enable
2826 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2829 PLIGHTINFOEL *lightInfo = NULL;
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2833 /* Tests show true = 128...not clear why */
2835 Enable = Enable? 128: 0;
2837 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2838 if (This->isRecordingState) {
2839 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2840 if (NULL == lightInfo) {
2841 return WINED3DERR_OUTOFVIDEOMEMORY;
2843 lightInfo->OriginalIndex = Index;
2844 lightInfo->glIndex = -1;
2845 lightInfo->enabledChanged = TRUE;
2846 lightInfo->lightEnabled = Enable;
2848 /* Add to the END of the chain of lights changes to be replayed */
2849 if (This->updateStateBlock->lights == NULL) {
2850 This->updateStateBlock->lights = lightInfo;
2852 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2853 while (temp->next != NULL) temp=temp->next;
2854 temp->next = lightInfo;
2856 TRACE("Recording... not performing anything more\n");
2860 /* Not recording... So, locate the light in the live lights */
2861 lightInfo = This->stateBlock->lights;
2862 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2864 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2865 if (lightInfo == NULL) {
2867 TRACE("Light enabled requested but light not defined, so defining one!\n");
2868 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2870 /* Search for it again! Should be fairly quick as near head of list */
2871 lightInfo = This->stateBlock->lights;
2872 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2873 if (lightInfo == NULL) {
2874 FIXME("Adding default lights has failed dismally\n");
2875 return WINED3DERR_INVALIDCALL;
2879 /* OK, we now have a light... */
2882 /* If we are disabling it, check it was enabled, and
2883 still only do something if it has assigned a glIndex (which it should have!) */
2884 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2885 TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
2887 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2888 checkGLcall("glDisable GL_LIGHT0+Index");
2891 TRACE("Nothing to do as light was not enabled\n");
2893 lightInfo->lightEnabled = Enable;
2896 /* We are enabling it. If it is enabled, it's really simple */
2897 if (lightInfo->lightEnabled) {
2899 TRACE("Nothing to do as light was enabled\n");
2901 /* If it already has a glIndex, it's still simple */
2902 } else if (lightInfo->glIndex != -1) {
2903 TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
2904 lightInfo->lightEnabled = Enable;
2906 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2907 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2910 /* Otherwise got to find space - lights are ordered gl indexes first */
2912 PLIGHTINFOEL *bsf = NULL;
2913 PLIGHTINFOEL *pos = This->stateBlock->lights;
2914 PLIGHTINFOEL *prev = NULL;
2918 /* Try to minimize changes as much as possible */
2919 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2921 /* Try to remember which index can be replaced if necessary */
2922 if (bsf==NULL && !pos->lightEnabled) {
2923 /* Found a light we can replace, save as best replacement */
2927 /* Step to next space */
2933 /* If we have too many active lights, fail the call */
2934 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2935 FIXME("Program requests too many concurrent lights\n");
2936 return WINED3DERR_INVALIDCALL;
2938 /* If we have allocated all lights, but not all are enabled,
2939 reuse one which is not enabled */
2940 } else if (Index == This->maxConcurrentLights) {
2941 /* use bsf - Simply swap the new light and the BSF one */
2942 PLIGHTINFOEL *bsfNext = bsf->next;
2943 PLIGHTINFOEL *bsfPrev = bsf->prev;
2946 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2947 if (bsf->prev != NULL) {
2948 bsf->prev->next = lightInfo;
2950 This->stateBlock->lights = lightInfo;
2953 /* If not side by side, lots of chains to update */
2954 if (bsf->next != lightInfo) {
2955 lightInfo->prev->next = bsf;
2956 bsf->next->prev = lightInfo;
2957 bsf->next = lightInfo->next;
2958 bsf->prev = lightInfo->prev;
2959 lightInfo->next = bsfNext;
2960 lightInfo->prev = bsfPrev;
2964 bsf->prev = lightInfo;
2965 bsf->next = lightInfo->next;
2966 lightInfo->next = bsf;
2967 lightInfo->prev = bsfPrev;
2972 glIndex = bsf->glIndex;
2974 lightInfo->glIndex = glIndex;
2975 lightInfo->lightEnabled = Enable;
2977 /* Finally set up the light in gl itself */
2978 TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
2980 setup_light(iface, glIndex, lightInfo);
2981 glEnable(GL_LIGHT0 + glIndex);
2982 checkGLcall("glEnable GL_LIGHT0 new setup");
2985 /* If we reached the end of the allocated lights, with space in the
2986 gl lights, setup a new light */
2987 } else if (pos->glIndex == -1) {
2989 /* We reached the end of the allocated gl lights, so already
2990 know the index of the next one! */
2992 lightInfo->glIndex = glIndex;
2993 lightInfo->lightEnabled = Enable;
2995 /* In an ideal world, it's already in the right place */
2996 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2997 /* No need to move it */
2999 /* Remove this light from the list */
3000 lightInfo->prev->next = lightInfo->next;
3001 if (lightInfo->next != NULL) {
3002 lightInfo->next->prev = lightInfo->prev;
3005 /* Add in at appropriate place (inbetween prev and pos) */
3006 lightInfo->prev = prev;
3007 lightInfo->next = pos;
3009 This->stateBlock->lights = lightInfo;
3011 prev->next = lightInfo;
3014 pos->prev = lightInfo;
3018 /* Finally set up the light in gl itself */
3019 TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
3021 setup_light(iface, glIndex, lightInfo);
3022 glEnable(GL_LIGHT0 + glIndex);
3023 checkGLcall("glEnable GL_LIGHT0 new setup");
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3034 PLIGHTINFOEL *lightInfo = NULL;
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 TRACE("(%p) : for idx(%d)\n", This, Index);
3038 /* Locate the light in the live lights */
3039 lightInfo = This->stateBlock->lights;
3040 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3042 if (lightInfo == NULL) {
3043 TRACE("Light enabled state requested but light not defined\n");
3044 return WINED3DERR_INVALIDCALL;
3046 *pEnable = lightInfo->lightEnabled;
3051 * Get / Set Clip Planes
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3057 /* Validate Index */
3058 if (Index >= GL_LIMITS(clipplanes)) {
3059 TRACE("Application has requested clipplane this device doesn't support\n");
3060 return WINED3DERR_INVALIDCALL;
3063 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3064 This->updateStateBlock->set.clipplane[Index] = TRUE;
3065 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3066 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3067 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3068 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3070 /* Handle recording of state blocks */
3071 if (This->isRecordingState) {
3072 TRACE("Recording... not performing anything\n");
3080 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3081 glMatrixMode(GL_MODELVIEW);
3083 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3085 TRACE("Clipplane [%f,%f,%f,%f]\n",
3086 This->updateStateBlock->clipplane[Index][0],
3087 This->updateStateBlock->clipplane[Index][1],
3088 This->updateStateBlock->clipplane[Index][2],
3089 This->updateStateBlock->clipplane[Index][3]);
3090 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3091 checkGLcall("glClipPlane");
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 TRACE("(%p) : for idx %d\n", This, Index);
3103 /* Validate Index */
3104 if (Index >= GL_LIMITS(clipplanes)) {
3105 TRACE("Application has requested clipplane this device doesn't support\n");
3106 return WINED3DERR_INVALIDCALL;
3109 pPlane[0] = This->stateBlock->clipplane[Index][0];
3110 pPlane[1] = This->stateBlock->clipplane[Index][1];
3111 pPlane[2] = This->stateBlock->clipplane[Index][2];
3112 pPlane[3] = This->stateBlock->clipplane[Index][3];
3117 * Get / Set Clip Plane Status
3118 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3122 FIXME("(%p) : stub\n", This);
3123 if (NULL == pClipStatus) {
3124 return WINED3DERR_INVALIDCALL;
3126 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3127 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 FIXME("(%p) : stub\n", This);
3134 if (NULL == pClipStatus) {
3135 return WINED3DERR_INVALIDCALL;
3137 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3138 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3143 * Get / Set Material
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 This->updateStateBlock->changed.material = TRUE;
3149 This->updateStateBlock->set.material = TRUE;
3150 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3152 /* Handle recording of state blocks */
3153 if (This->isRecordingState) {
3154 TRACE("Recording... not performing anything\n");
3159 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3160 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3161 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3162 pMaterial->Ambient.b, pMaterial->Ambient.a);
3163 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3164 pMaterial->Specular.b, pMaterial->Specular.a);
3165 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3166 pMaterial->Emissive.b, pMaterial->Emissive.a);
3167 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3169 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3170 checkGLcall("glMaterialfv(GL_AMBIENT)");
3171 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3172 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3174 /* Only change material color if specular is enabled, otherwise it is set to black */
3175 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3176 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3177 checkGLcall("glMaterialfv(GL_SPECULAR");
3179 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3180 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3181 checkGLcall("glMaterialfv(GL_SPECULAR");
3183 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3184 checkGLcall("glMaterialfv(GL_EMISSION)");
3185 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3186 checkGLcall("glMaterialf(GL_SHININESS");
3192 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3195 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3196 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3197 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3198 pMaterial->Ambient.b, pMaterial->Ambient.a);
3199 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3200 pMaterial->Specular.b, pMaterial->Specular.a);
3201 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3202 pMaterial->Emissive.b, pMaterial->Emissive.a);
3203 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3211 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3212 UINT BaseVertexIndex) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 IWineD3DIndexBuffer *oldIdxs;
3216 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3217 oldIdxs = This->updateStateBlock->pIndexData;
3219 This->updateStateBlock->changed.indices = TRUE;
3220 This->updateStateBlock->set.indices = TRUE;
3221 This->updateStateBlock->pIndexData = pIndexData;
3222 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3224 /* Handle recording of state blocks */
3225 if (This->isRecordingState) {
3226 TRACE("Recording... not performing anything\n");
3230 if (NULL != pIndexData) {
3231 IWineD3DIndexBuffer_AddRef(pIndexData);
3233 if (NULL != oldIdxs) {
3234 IWineD3DIndexBuffer_Release(oldIdxs);
3239 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 *ppIndexData = This->stateBlock->pIndexData;
3245 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3246 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3248 TRACE("(%p) No index data set\n", This);
3250 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3256 * Get / Set Viewports
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 TRACE("(%p)\n", This);
3262 This->updateStateBlock->changed.viewport = TRUE;
3263 This->updateStateBlock->set.viewport = TRUE;
3264 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3266 /* Handle recording of state blocks */
3267 if (This->isRecordingState) {
3268 TRACE("Recording... not performing anything\n");
3271 This->viewport_changed = TRUE;
3275 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3276 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3278 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3279 checkGLcall("glDepthRange");
3280 /* Note: GL requires lower left, DirectX supplies upper left */
3281 /* TODO: replace usage of renderTarget with context management */
3282 glViewport(pViewport->X,
3283 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3284 pViewport->Width, pViewport->Height);
3286 checkGLcall("glViewport");
3294 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 TRACE("(%p)\n", This);
3297 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3301 static void renderstate_stencil_twosided(
3302 IWineD3DDeviceImpl *This,
3309 GLint stencilPass ) {
3310 #if 0 /* Don't use OpenGL 2.0 calls for now */
3311 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3312 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3313 checkGLcall("glStencilFuncSeparate(...)");
3314 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3315 checkGLcall("glStencilOpSeparate(...)");
3319 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3320 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3321 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3322 GL_EXTCALL(glActiveStencilFaceEXT(face));
3323 checkGLcall("glActiveStencilFaceEXT(...)");
3324 glStencilFunc(func, ref, mask);
3325 checkGLcall("glStencilFunc(...)");
3326 glStencilOp(stencilFail, depthFail, stencilPass);
3327 checkGLcall("glStencilOp(...)");
3328 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3329 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3330 checkGLcall("glStencilFuncSeparateATI(...)");
3331 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3332 checkGLcall("glStencilOpSeparateATI(...)");
3334 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3338 static void renderstate_stencil(IWineD3DDeviceImpl *This, WINED3DRENDERSTATETYPE State, DWORD Value) {
3339 DWORD onesided_enable = FALSE;
3340 DWORD twosided_enable = FALSE;
3341 GLint func = GL_ALWAYS;
3342 GLint func_ccw = GL_ALWAYS;
3345 GLint stencilFail = GL_KEEP;
3346 GLint depthFail = GL_KEEP;
3347 GLint stencilPass = GL_KEEP;
3348 GLint stencilFail_ccw = GL_KEEP;
3349 GLint depthFail_ccw = GL_KEEP;
3350 GLint stencilPass_ccw = GL_KEEP;
3352 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3353 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3354 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3355 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3356 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3357 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3359 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3360 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3362 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3363 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3364 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3365 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3366 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3367 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3368 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3369 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3370 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3371 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3372 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3373 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3374 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3375 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3376 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3377 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3379 TRACE("(onesided %d, twosided %d, ref %x, mask %x, \
3380 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3381 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3382 onesided_enable, twosided_enable, ref, mask,
3383 func, stencilFail, depthFail, stencilPass,
3384 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3386 if (twosided_enable) {
3387 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3388 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3390 if (onesided_enable) {
3391 glEnable(GL_STENCIL_TEST);
3392 checkGLcall("glEnable GL_STENCIL_TEST");
3393 glStencilFunc(func, ref, mask);
3394 checkGLcall("glStencilFunc(...)");
3395 glStencilOp(stencilFail, depthFail, stencilPass);
3396 checkGLcall("glStencilOp(...)");
3398 glDisable(GL_STENCIL_TEST);
3399 checkGLcall("glDisable GL_STENCIL_TEST");
3405 * Get / Set Render States
3406 * TODO: Verify against dx9 definitions
3408 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 DWORD OldValue = This->stateBlock->renderState[State];
3413 /* Simple way of referring to either a DWORD or a 4 byte float */
3419 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3420 This->updateStateBlock->changed.renderState[State] = TRUE;
3421 This->updateStateBlock->set.renderState[State] = TRUE;
3422 This->updateStateBlock->renderState[State] = Value;
3424 /* Handle recording of state blocks */
3425 if (This->isRecordingState) {
3426 TRACE("Recording... not performing anything\n");
3433 case WINED3DRS_FILLMODE :
3434 switch ((WINED3DFILLMODE) Value) {
3435 case WINED3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3436 case WINED3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3437 case WINED3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3439 FIXME("Unrecognized WINED3DRS_FILLMODE value %d\n", Value);
3441 checkGLcall("glPolygonMode (fillmode)");
3444 case WINED3DRS_LIGHTING :
3446 glEnable(GL_LIGHTING);
3447 checkGLcall("glEnable GL_LIGHTING");
3449 glDisable(GL_LIGHTING);
3450 checkGLcall("glDisable GL_LIGHTING");
3454 case WINED3DRS_ZENABLE :
3455 switch ((WINED3DZBUFFERTYPE) Value) {
3456 case WINED3DZB_FALSE:
3457 glDisable(GL_DEPTH_TEST);
3458 checkGLcall("glDisable GL_DEPTH_TEST");
3460 case WINED3DZB_TRUE:
3461 glEnable(GL_DEPTH_TEST);
3462 checkGLcall("glEnable GL_DEPTH_TEST");
3464 case WINED3DZB_USEW:
3465 glEnable(GL_DEPTH_TEST);
3466 checkGLcall("glEnable GL_DEPTH_TEST");
3467 FIXME("W buffer is not well handled\n");
3470 FIXME("Unrecognized WINED3DZBUFFERTYPE value %d\n", Value);
3474 case WINED3DRS_CULLMODE :
3476 /* If we are culling "back faces with clockwise vertices" then
3477 set front faces to be counter clockwise and enable culling
3479 switch ((WINED3DCULL) Value) {
3480 case WINED3DCULL_NONE:
3481 glDisable(GL_CULL_FACE);
3482 checkGLcall("glDisable GL_CULL_FACE");
3484 case WINED3DCULL_CW:
3485 glEnable(GL_CULL_FACE);
3486 checkGLcall("glEnable GL_CULL_FACE");
3487 if (This->render_offscreen) {
3489 checkGLcall("glFrontFace GL_CW");
3491 glFrontFace(GL_CCW);
3492 checkGLcall("glFrontFace GL_CCW");
3494 glCullFace(GL_BACK);
3496 case WINED3DCULL_CCW:
3497 glEnable(GL_CULL_FACE);
3498 checkGLcall("glEnable GL_CULL_FACE");
3499 if (This->render_offscreen) {
3500 glFrontFace(GL_CCW);
3501 checkGLcall("glFrontFace GL_CCW");
3504 checkGLcall("glFrontFace GL_CW");
3506 glCullFace(GL_BACK);
3509 FIXME("Unrecognized/Unhandled WINED3DCULL value %d\n", Value);
3513 case WINED3DRS_SHADEMODE :
3514 switch ((WINED3DSHADEMODE) Value) {
3515 case WINED3DSHADE_FLAT:
3516 glShadeModel(GL_FLAT);
3517 checkGLcall("glShadeModel");
3519 case WINED3DSHADE_GOURAUD:
3520 glShadeModel(GL_SMOOTH);
3521 checkGLcall("glShadeModel");
3523 case WINED3DSHADE_PHONG:
3524 FIXME("WINED3DSHADE_PHONG isn't supported\n");
3527 FIXME("Unrecognized/Unhandled WINED3DSHADEMODE value %d\n", Value);
3531 case WINED3DRS_DITHERENABLE :
3533 glEnable(GL_DITHER);
3534 checkGLcall("glEnable GL_DITHER");
3536 glDisable(GL_DITHER);
3537 checkGLcall("glDisable GL_DITHER");
3541 case WINED3DRS_ZWRITEENABLE :
3544 checkGLcall("glDepthMask");
3547 checkGLcall("glDepthMask");
3551 case WINED3DRS_ZFUNC :
3553 int glParm = CompareFunc(Value);
3556 glDepthFunc(glParm);
3557 checkGLcall("glDepthFunc");
3562 case WINED3DRS_AMBIENT :
3565 D3DCOLORTOGLFLOAT4(Value, col);
3566 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3567 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3568 checkGLcall("glLightModel for MODEL_AMBIENT");
3573 case WINED3DRS_ALPHABLENDENABLE :
3576 checkGLcall("glEnable GL_BLEND");
3578 glDisable(GL_BLEND);
3579 checkGLcall("glDisable GL_BLEND");
3583 case WINED3DRS_SRCBLEND :
3584 case WINED3DRS_DESTBLEND :
3586 int newVal = GL_ZERO;
3588 case WINED3DBLEND_ZERO : newVal = GL_ZERO; break;
3589 case WINED3DBLEND_ONE : newVal = GL_ONE; break;
3590 case WINED3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3591 case WINED3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3592 case WINED3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3593 case WINED3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3594 case WINED3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3595 case WINED3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3596 case WINED3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3597 case WINED3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3598 case WINED3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3600 case WINED3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3601 This->srcBlend = newVal;
3602 This->dstBlend = newVal;
3605 case WINED3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3606 This->srcBlend = newVal;
3607 This->dstBlend = newVal;
3609 case WINED3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3610 case WINED3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3612 FIXME("Unrecognized src/dest blend value %d (%d)\n", Value, State);
3615 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3616 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3617 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3618 glBlendFunc(This->srcBlend, This->dstBlend);
3620 checkGLcall("glBlendFunc");
3624 case WINED3DRS_ALPHATESTENABLE :
3625 case WINED3DRS_ALPHAFUNC :
3626 case WINED3DRS_ALPHAREF :
3627 case WINED3DRS_COLORKEYENABLE :
3631 BOOL enable_ckey = FALSE;
3633 IWineD3DSurfaceImpl *surf;
3635 /* Find out if the texture on the first stage has a ckey set */
3636 if(This->stateBlock->textures[0]) {
3637 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3638 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3641 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3642 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3643 glEnable(GL_ALPHA_TEST);
3644 checkGLcall("glEnable GL_ALPHA_TEST");
3646 glDisable(GL_ALPHA_TEST);
3647 checkGLcall("glDisable GL_ALPHA_TEST");
3648 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3654 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3655 glParm = GL_NOTEQUAL;
3658 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3659 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3662 This->alphafunc = glParm;
3663 glAlphaFunc(glParm, ref);
3664 checkGLcall("glAlphaFunc");
3669 case WINED3DRS_CLIPPLANEENABLE :
3670 case WINED3DRS_CLIPPING :
3672 /* Ensure we only do the changed clip planes */
3673 DWORD enable = 0xFFFFFFFF;
3674 DWORD disable = 0x00000000;
3676 /* If enabling / disabling all */
3677 if (State == WINED3DRS_CLIPPING) {
3679 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3682 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3686 enable = Value & ~OldValue;
3687 disable = ~Value & OldValue;
3690 if (enable & WINED3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3691 if (enable & WINED3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3692 if (enable & WINED3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3693 if (enable & WINED3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3694 if (enable & WINED3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3695 if (enable & WINED3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3697 if (disable & WINED3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3698 if (disable & WINED3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3699 if (disable & WINED3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3700 if (disable & WINED3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3701 if (disable & WINED3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3702 if (disable & WINED3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3704 /** update clipping status */
3706 This->stateBlock->clip_status.ClipUnion = 0;
3707 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3709 This->stateBlock->clip_status.ClipUnion = 0;
3710 This->stateBlock->clip_status.ClipIntersection = 0;
3715 case WINED3DRS_BLENDOP :
3717 int glParm = GL_FUNC_ADD;
3719 switch ((WINED3DBLENDOP) Value) {
3720 case WINED3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3721 case WINED3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3722 case WINED3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3723 case WINED3DBLENDOP_MIN : glParm = GL_MIN; break;
3724 case WINED3DBLENDOP_MAX : glParm = GL_MAX; break;
3726 FIXME("Unrecognized/Unhandled WINED3DBLENDOP value %d\n", Value);
3729 if(GL_SUPPORT(EXT_BLEND_MINMAX)) {
3730 TRACE("glBlendEquation(%x)\n", glParm);
3731 GL_EXTCALL(glBlendEquation(glParm));
3732 checkGLcall("glBlendEquation");
3734 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3739 case WINED3DRS_TEXTUREFACTOR :
3743 /* Note the texture color applies to all textures whereas
3744 GL_TEXTURE_ENV_COLOR applies to active only */
3746 D3DCOLORTOGLFLOAT4(Value, col);
3748 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3749 /* And now the default texture color as well */
3750 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3751 /* Note the WINED3DRS value applies to all textures, but GL has one
3752 per texture, so apply it now ready to be used! */
3753 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3754 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3755 checkGLcall("glActiveTextureARB");
3757 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3760 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3761 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3767 case WINED3DRS_SPECULARENABLE :
3769 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3770 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3771 specular color. This is wrong:
3772 Separate specular color means the specular colour is maintained separately, whereas
3773 single color means it is merged in. However in both cases they are being used to
3775 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3776 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3780 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3781 * Instead, we need to setup the FinalCombiner properly.
3783 * The default setup for the FinalCombiner is:
3785 * <variable> <input> <mapping> <usage>
3786 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3787 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3788 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3789 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3790 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3791 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3792 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3794 * That's pretty much fine as it is, except for variable B, which needs to take
3795 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3796 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3800 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3801 checkGLcall("glMaterialfv");
3802 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3803 glEnable(GL_COLOR_SUM_EXT);
3805 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3807 checkGLcall("glEnable(GL_COLOR_SUM)");
3809 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3810 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3811 checkGLcall("glFinalCombinerInputNV()");
3814 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3816 /* for the case of enabled lighting: */
3817 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3818 checkGLcall("glMaterialfv");
3820 /* for the case of disabled lighting: */
3821 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3822 glDisable(GL_COLOR_SUM_EXT);
3824 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3826 checkGLcall("glDisable(GL_COLOR_SUM)");
3828 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3829 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3830 checkGLcall("glFinalCombinerInputNV()");
3836 case WINED3DRS_STENCILENABLE :
3837 case WINED3DRS_TWOSIDEDSTENCILMODE :
3838 case WINED3DRS_STENCILFUNC :
3839 case WINED3DRS_CCW_STENCILFUNC :
3840 case WINED3DRS_STENCILREF :
3841 case WINED3DRS_STENCILMASK :
3842 case WINED3DRS_STENCILFAIL :
3843 case WINED3DRS_STENCILZFAIL :
3844 case WINED3DRS_STENCILPASS :
3845 case WINED3DRS_CCW_STENCILFAIL :
3846 case WINED3DRS_CCW_STENCILZFAIL :
3847 case WINED3DRS_CCW_STENCILPASS :
3848 renderstate_stencil(This, State, Value);
3850 case WINED3DRS_STENCILWRITEMASK :
3852 glStencilMask(Value);
3853 TRACE("glStencilMask(%u)\n", Value);
3854 checkGLcall("glStencilMask");
3858 case WINED3DRS_FOGENABLE :
3862 checkGLcall("glEnable GL_FOG");
3865 checkGLcall("glDisable GL_FOG");
3870 case WINED3DRS_RANGEFOGENABLE :
3873 TRACE("Enabled RANGEFOG\n");
3875 TRACE("Disabled RANGEFOG\n");
3880 case WINED3DRS_FOGCOLOR :
3883 D3DCOLORTOGLFLOAT4(Value, col);
3884 /* Set the default alpha blend color */
3885 glFogfv(GL_FOG_COLOR, &col[0]);
3886 checkGLcall("glFog GL_FOG_COLOR");
3890 case WINED3DRS_FOGTABLEMODE :
3891 case WINED3DRS_FOGVERTEXMODE :
3893 /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */
3894 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
3895 glHint(GL_FOG_HINT, GL_FASTEST);
3896 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3897 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3898 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3899 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3901 case WINED3DFOG_EXP: {
3902 if(!This->last_was_rhw) {
3903 glFogi(GL_FOG_MODE, GL_EXP);
3904 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3905 if(GL_SUPPORT(EXT_FOG_COORD)) {
3906 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3907 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3908 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3909 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3914 case WINED3DFOG_EXP2: {
3915 if(!This->last_was_rhw) {
3916 glFogi(GL_FOG_MODE, GL_EXP2);
3917 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3918 if(GL_SUPPORT(EXT_FOG_COORD)) {
3919 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3920 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3921 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3922 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3927 case WINED3DFOG_LINEAR: {
3928 if(!This->last_was_rhw) {
3929 glFogi(GL_FOG_MODE, GL_LINEAR);
3930 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3931 if(GL_SUPPORT(EXT_FOG_COORD)) {
3932 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3933 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3934 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3935 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3940 case WINED3DFOG_NONE: {
3941 /* Both are none? According to msdn the alpha channel of the specular
3942 * color contains a fog factor. Set it in drawStridedSlow.
3943 * Same happens with Vertexfog on transformed vertices
3945 if(GL_SUPPORT(EXT_FOG_COORD)) {
3946 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3947 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3948 glFogi(GL_FOG_MODE, GL_LINEAR);
3949 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3950 glFogf(GL_FOG_START, (float) 0xff);
3951 checkGLcall("glFogfv GL_FOG_START");
3952 glFogf(GL_FOG_END, 0.0);
3953 checkGLcall("glFogfv GL_FOG_END");
3955 /* Disable GL fog, handle this in software in drawStridedSlow */
3957 checkGLcall("glDisable(GL_FOG)");
3961 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3964 glHint(GL_FOG_HINT, GL_NICEST);
3965 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3966 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3967 case WINED3DFOG_EXP:
3968 glFogi(GL_FOG_MODE, GL_EXP);
3969 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3970 if(GL_SUPPORT(EXT_FOG_COORD)) {
3971 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3972 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3973 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3974 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3977 case WINED3DFOG_EXP2:
3978 glFogi(GL_FOG_MODE, GL_EXP2);
3979 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3980 if(GL_SUPPORT(EXT_FOG_COORD)) {
3981 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3982 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3983 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3984 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3987 case WINED3DFOG_LINEAR:
3988 glFogi(GL_FOG_MODE, GL_LINEAR);
3989 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3990 if(GL_SUPPORT(EXT_FOG_COORD)) {
3991 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3992 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3993 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3994 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3997 case WINED3DFOG_NONE:
3998 default: /* Won't happen */
3999 FIXME("Unexpected WINED3DRS_FOGTABLEMODE %d\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
4002 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
4003 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
4008 case WINED3DRS_FOGSTART :
4011 glFogfv(GL_FOG_START, &tmpvalue.f);
4012 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
4013 TRACE("Fog Start == %f\n", tmpvalue.f);
4017 case WINED3DRS_FOGEND :
4020 glFogfv(GL_FOG_END, &tmpvalue.f);
4021 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4022 TRACE("Fog End == %f\n", tmpvalue.f);
4026 case WINED3DRS_FOGDENSITY :
4029 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4030 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4034 case WINED3DRS_VERTEXBLEND :
4036 This->updateStateBlock->vertex_blend = (WINED3DVERTEXBLENDFLAGS) Value;
4037 TRACE("Vertex Blending state to %d\n", Value);
4041 case WINED3DRS_TWEENFACTOR :
4044 This->updateStateBlock->tween_factor = tmpvalue.f;
4045 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4049 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4051 TRACE("Indexed Vertex Blend Enable to %u\n", (BOOL) Value);
4055 case WINED3DRS_COLORVERTEX :
4056 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4057 case WINED3DRS_SPECULARMATERIALSOURCE :
4058 case WINED3DRS_AMBIENTMATERIALSOURCE :
4059 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4061 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4063 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4064 TRACE("diff %d, amb %d, emis %d, spec %d\n",
4065 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4066 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4067 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4068 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4070 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4071 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4072 Parm = GL_AMBIENT_AND_DIFFUSE;
4076 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4078 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4080 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) {
4087 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4089 This->tracking_color = NEEDS_TRACKING;
4090 This->tracking_parm = Parm;
4094 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4099 case WINED3DRS_LINEPATTERN :
4103 WINED3DLINEPATTERN lp;
4105 tmppattern.d = Value;
4107 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4109 if (tmppattern.lp.wRepeatFactor) {
4110 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4111 checkGLcall("glLineStipple(repeat, linepattern)");
4112 glEnable(GL_LINE_STIPPLE);
4113 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4115 glDisable(GL_LINE_STIPPLE);
4116 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4121 case WINED3DRS_ZBIAS : /* D3D8 only */
4125 TRACE("ZBias value %f\n", tmpvalue.f);
4126 glPolygonOffset(0, -tmpvalue.f);
4127 checkGLcall("glPolygonOffset(0, -Value)");
4128 glEnable(GL_POLYGON_OFFSET_FILL);
4129 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4130 glEnable(GL_POLYGON_OFFSET_LINE);
4131 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4132 glEnable(GL_POLYGON_OFFSET_POINT);
4133 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4135 glDisable(GL_POLYGON_OFFSET_FILL);
4136 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4137 glDisable(GL_POLYGON_OFFSET_LINE);
4138 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4139 glDisable(GL_POLYGON_OFFSET_POINT);
4140 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4145 case WINED3DRS_NORMALIZENORMALS :
4147 glEnable(GL_NORMALIZE);
4148 checkGLcall("glEnable(GL_NORMALIZE);");
4150 glDisable(GL_NORMALIZE);
4151 checkGLcall("glDisable(GL_NORMALIZE);");
4155 case WINED3DRS_POINTSIZE :
4156 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4158 TRACE("Set point size to %f\n", tmpvalue.f);
4159 glPointSize(tmpvalue.f);
4160 checkGLcall("glPointSize(...);");
4163 case WINED3DRS_POINTSIZE_MIN :
4164 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4166 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4167 checkGLcall("glPointParameterfEXT(...);");
4169 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4173 case WINED3DRS_POINTSIZE_MAX :
4174 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4176 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4177 checkGLcall("glPointParameterfEXT(...);");
4179 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4183 case WINED3DRS_POINTSCALE_A :
4184 case WINED3DRS_POINTSCALE_B :
4185 case WINED3DRS_POINTSCALE_C :
4186 case WINED3DRS_POINTSCALEENABLE :
4189 * POINTSCALEENABLE controls how point size value is treated. If set to
4190 * true, the point size is scaled with respect to height of viewport.
4191 * When set to false point size is in pixels.
4193 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4196 /* Default values */
4197 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4200 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4201 * This means that OpenGL will clamp really small point sizes to 1.0f.
4202 * To correct for this we need to multiply by the scale factor when sizes
4203 * are less than 1.0f. scale_factor = 1.0f / point_size.
4205 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4206 if(pointSize > 0.0f) {
4207 GLfloat scaleFactor;
4209 if(pointSize < 1.0f) {
4210 scaleFactor = pointSize * pointSize;
4215 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4216 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4217 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4218 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4219 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4220 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4221 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4225 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4226 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4227 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4229 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4230 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4231 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4233 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4237 case WINED3DRS_COLORWRITEENABLE :
4239 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4240 Value & WINED3DCOLORWRITEENABLE_RED ? 1 : 0,
4241 Value & WINED3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4242 Value & WINED3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4243 Value & WINED3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4244 glColorMask(Value & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4245 Value & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4246 Value & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4247 Value & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4248 checkGLcall("glColorMask(...)");
4252 case WINED3DRS_LOCALVIEWER :
4254 GLint state = (Value) ? 1 : 0;
4255 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4256 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4260 case WINED3DRS_LASTPIXEL :
4263 TRACE("Last Pixel Drawing Enabled\n");
4265 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4270 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4273 TRACE("Software Processing Enabled\n");
4275 TRACE("Software Processing Disabled\n");
4280 /** not supported */
4281 case WINED3DRS_ZVISIBLE :
4284 return WINED3DERR_INVALIDCALL;
4286 case WINED3DRS_POINTSPRITEENABLE :
4288 /* TODO: NV_POINT_SPRITE */
4289 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4290 TRACE("Point sprites not supported\n");
4295 * Point sprites are always enabled. Value controls texture coordinate
4296 * replacement mode. Must be set true for point sprites to use
4299 glEnable(GL_POINT_SPRITE_ARB);
4300 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4303 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4304 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4306 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4307 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4311 case WINED3DRS_EDGEANTIALIAS :
4314 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4316 checkGLcall("glEnable(GL_BLEND)");
4317 glEnable(GL_LINE_SMOOTH);
4318 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4320 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4321 glDisable(GL_BLEND);
4322 checkGLcall("glDisable(GL_BLEND)");
4324 glDisable(GL_LINE_SMOOTH);
4325 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4329 case WINED3DRS_WRAP0 :
4330 case WINED3DRS_WRAP1 :
4331 case WINED3DRS_WRAP2 :
4332 case WINED3DRS_WRAP3 :
4333 case WINED3DRS_WRAP4 :
4334 case WINED3DRS_WRAP5 :
4335 case WINED3DRS_WRAP6 :
4336 case WINED3DRS_WRAP7 :
4337 case WINED3DRS_WRAP8 :
4338 case WINED3DRS_WRAP9 :
4339 case WINED3DRS_WRAP10 :
4340 case WINED3DRS_WRAP11 :
4341 case WINED3DRS_WRAP12 :
4342 case WINED3DRS_WRAP13 :
4343 case WINED3DRS_WRAP14 :
4344 case WINED3DRS_WRAP15 :
4346 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4347 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4348 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4349 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4350 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4352 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4356 ERR("(%p)->(%s,%d) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4361 case WINED3DRS_MULTISAMPLEANTIALIAS :
4363 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4365 glEnable(GL_MULTISAMPLE_ARB);
4366 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4368 glDisable(GL_MULTISAMPLE_ARB);
4369 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4373 ERR("Multisample antialiasing not supported by gl\n");
4379 case WINED3DRS_SCISSORTESTENABLE :
4382 glEnable(GL_SCISSOR_TEST);
4383 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4385 glDisable(GL_SCISSOR_TEST);
4386 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4390 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4394 glEnable(GL_POLYGON_OFFSET_FILL);
4395 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4396 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4397 checkGLcall("glPolygonOffset(...)");
4399 glDisable(GL_POLYGON_OFFSET_FILL);
4400 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4404 case WINED3DRS_ANTIALIASEDLINEENABLE :
4407 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4409 checkGLcall("glEnable(GL_BLEND)");
4410 glEnable(GL_LINE_SMOOTH);
4411 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4413 glDisable(GL_BLEND);
4414 checkGLcall("glDisable(GL_BLEND)");
4415 glDisable(GL_LINE_SMOOTH);
4416 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4420 case WINED3DRS_DEPTHBIAS :
4424 glEnable(GL_POLYGON_OFFSET_FILL);
4425 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4426 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4427 checkGLcall("glPolygonOffset(...)");
4429 glDisable(GL_POLYGON_OFFSET_FILL);
4430 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4435 case WINED3DRS_TEXTUREPERSPECTIVE :
4438 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4440 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4444 case WINED3DRS_STIPPLEDALPHA :
4447 ERR(" Stippled Alpha not supported yet.\n");
4450 case WINED3DRS_ANTIALIAS :
4453 ERR(" Antialias not supported yet.\n");
4457 case WINED3DRS_MULTISAMPLEMASK :
4459 if(0xFFFFFFFF != Value)
4460 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4464 case WINED3DRS_PATCHEDGESTYLE :
4466 if(WINED3DPATCHEDGE_DISCRETE != Value)
4467 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4471 case WINED3DRS_PATCHSEGMENTS :
4473 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4475 if(tmpvalue.d != Value)
4476 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4480 case WINED3DRS_DEBUGMONITORTOKEN :
4482 /* Only useful for "debug builds". */
4483 if(0xbaadcafe != Value) {
4484 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4485 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4486 * but our tests disagree.
4487 * We do not claim to implement a debugging lib, so do not write an ERR
4489 WARN("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4494 case WINED3DRS_POSITIONDEGREE :
4496 if(WINED3DDEGREE_CUBIC != Value)
4497 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4501 case WINED3DRS_NORMALDEGREE :
4503 if(WINED3DDEGREE_LINEAR != Value)
4504 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4508 case WINED3DRS_MINTESSELLATIONLEVEL :
4509 case WINED3DRS_MAXTESSELLATIONLEVEL :
4510 case WINED3DRS_ADAPTIVETESS_X :
4511 case WINED3DRS_ADAPTIVETESS_Y :
4512 case WINED3DRS_ADAPTIVETESS_Z :
4513 case WINED3DRS_ADAPTIVETESS_W :
4515 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4516 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4518 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4522 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4525 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4529 case WINED3DRS_COLORWRITEENABLE1 :
4530 case WINED3DRS_COLORWRITEENABLE2 :
4531 case WINED3DRS_COLORWRITEENABLE3 :
4533 /* depends on WINED3DRS_COLORWRITEENABLE. */
4534 if(0x0000000F != Value)
4535 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4539 case WINED3DRS_BLENDFACTOR :
4543 TRACE("Setting BlendFactor to %d\n", Value);
4545 D3DCOLORTOGLFLOAT4(Value, col);
4546 if (0xFFFFFFFF != Value) {
4548 checkGLcall("glEnable(GL_BLEND)");
4551 glDisable(GL_BLEND);
4552 checkGLcall("glDisable(GL_BLEND)");
4554 glBlendColor (col[0],col[1],col[2],col[3]);
4558 case WINED3DRS_SRGBWRITEENABLE :
4561 ERR("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4565 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4568 ERR("(%p)->(%s,%d) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4572 case WINED3DRS_SRCBLENDALPHA :
4573 case WINED3DRS_DESTBLENDALPHA :
4574 case WINED3DRS_BLENDOPALPHA :
4576 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4577 FIXME("(%p)->(%s,%d) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4579 TRACE("(%p)->(%s,%d): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4584 FIXME("(%p)->(%s,%d) unknown state\n", This, debug_d3drenderstate(State), Value);
4592 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
4593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4594 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
4595 *pValue = This->stateBlock->renderState[State];
4600 * Get / Set Sampler States
4601 * TODO: Verify against dx9 definitions
4604 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 * SetSampler is designed to allow for more than the standard up to 8 textures
4608 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4609 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4611 * http://developer.nvidia.com/object/General_FAQ.html#t6
4613 * There are two new settings for GForce
4615 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4616 * and the texture one:
4617 * GL_MAX_TEXTURE_COORDS_ARB.
4618 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4620 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4621 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4622 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4623 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4624 return WINED3DERR_INVALIDCALL;
4627 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
4628 debug_d3dsamplerstate(Type), Type, Value);
4629 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4630 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4631 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4633 /* Handle recording of state blocks */
4634 if (This->isRecordingState) {
4635 TRACE("Recording... not performing anything\n");
4642 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 /** TODO: check that sampler is in range **/
4645 *Value = This->stateBlock->samplerState[Sampler][Type];
4646 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
4651 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
4657 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
4658 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
4660 winHeight = windowRect.bottom - windowRect.top;
4661 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
4662 pRect->right - pRect->left, pRect->bottom - pRect->top);
4664 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
4665 checkGLcall("glScissor");
4671 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 GLint scissorBox[4];
4676 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4677 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4678 pRect->left = scissorBox[0];
4679 pRect->top = scissorBox[1];
4680 pRect->right = scissorBox[0] + scissorBox[2];
4681 pRect->bottom = scissorBox[1] + scissorBox[3];
4682 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4687 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4689 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4691 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4693 This->updateStateBlock->vertexDecl = pDecl;
4694 This->updateStateBlock->changed.vertexDecl = TRUE;
4695 This->updateStateBlock->set.vertexDecl = TRUE;
4697 if (This->isRecordingState) {
4698 TRACE("Recording... not performing anything\n");
4701 if (NULL != pDecl) {
4702 IWineD3DVertexDeclaration_AddRef(pDecl);
4704 if (NULL != oldDecl) {
4705 IWineD3DVertexDeclaration_Release(oldDecl);
4710 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4715 *ppDecl = This->stateBlock->vertexDecl;
4716 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4720 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4724 This->updateStateBlock->vertexShader = pShader;
4725 This->updateStateBlock->changed.vertexShader = TRUE;
4726 This->updateStateBlock->set.vertexShader = TRUE;
4728 if (This->isRecordingState) {
4729 TRACE("Recording... not performing anything\n");
4732 if (NULL != pShader) {
4733 IWineD3DVertexShader_AddRef(pShader);
4735 if (NULL != oldShader) {
4736 IWineD3DVertexShader_Release(oldShader);
4739 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4741 * TODO: merge HAL shaders context switching from prototype
4746 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4749 if (NULL == ppShader) {
4750 return WINED3DERR_INVALIDCALL;
4752 *ppShader = This->stateBlock->vertexShader;
4753 if( NULL != *ppShader)
4754 IWineD3DVertexShader_AddRef(*ppShader);
4756 TRACE("(%p) : returning %p\n", This, *ppShader);
4760 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4761 IWineD3DDevice *iface,
4763 CONST BOOL *srcData,
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 int i, cnt = min(count, MAX_CONST_B - start);
4769 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4770 iface, srcData, start, count);
4772 if (srcData == NULL || cnt < 0)
4773 return WINED3DERR_INVALIDCALL;
4775 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4776 for (i = 0; i < cnt; i++)
4777 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4779 for (i = start; i < cnt + start; ++i) {
4780 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4781 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4787 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4788 IWineD3DDevice *iface,
4793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4794 int cnt = min(count, MAX_CONST_B - start);
4796 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4797 iface, dstData, start, count);
4799 if (dstData == NULL || cnt < 0)
4800 return WINED3DERR_INVALIDCALL;
4802 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4806 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4807 IWineD3DDevice *iface,
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4813 int i, cnt = min(count, MAX_CONST_I - start);
4815 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4816 iface, srcData, start, count);
4818 if (srcData == NULL || cnt < 0)
4819 return WINED3DERR_INVALIDCALL;
4821 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4822 for (i = 0; i < cnt; i++)
4823 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4824 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4826 for (i = start; i < cnt + start; ++i) {
4827 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4828 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4834 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4835 IWineD3DDevice *iface,
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 int cnt = min(count, MAX_CONST_I - start);
4843 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4844 iface, dstData, start, count);
4846 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4847 return WINED3DERR_INVALIDCALL;
4849 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4853 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4854 IWineD3DDevice *iface,
4856 CONST float *srcData,
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4860 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4862 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4863 iface, srcData, start, count);
4865 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4866 return WINED3DERR_INVALIDCALL;
4868 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4869 for (i = 0; i < cnt; i++)
4870 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4871 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4873 for (i = start; i < cnt + start; ++i) {
4874 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4875 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4877 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4878 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4880 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4887 IWineD3DDevice *iface,
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4895 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4896 iface, dstData, start, count);
4898 if (dstData == NULL || cnt < 0)
4899 return WINED3DERR_INVALIDCALL;
4901 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4905 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4908 This->updateStateBlock->pixelShader = pShader;
4909 This->updateStateBlock->changed.pixelShader = TRUE;
4910 This->updateStateBlock->set.pixelShader = TRUE;
4912 /* Handle recording of state blocks */
4913 if (This->isRecordingState) {
4914 TRACE("Recording... not performing anything\n");
4917 if (NULL != pShader) {
4918 IWineD3DPixelShader_AddRef(pShader);
4920 if (NULL != oldShader) {
4921 IWineD3DPixelShader_Release(oldShader);
4924 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4926 * TODO: merge HAL shaders context switching from prototype
4931 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 if (NULL == ppShader) {
4935 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4936 return WINED3DERR_INVALIDCALL;
4939 *ppShader = This->stateBlock->pixelShader;
4940 if (NULL != *ppShader) {
4941 IWineD3DPixelShader_AddRef(*ppShader);
4943 TRACE("(%p) : returning %p\n", This, *ppShader);
4947 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4948 IWineD3DDevice *iface,
4950 CONST BOOL *srcData,
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 int i, cnt = min(count, MAX_CONST_B - start);
4956 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4957 iface, srcData, start, count);
4959 if (srcData == NULL || cnt < 0)
4960 return WINED3DERR_INVALIDCALL;
4962 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4963 for (i = 0; i < cnt; i++)
4964 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4966 for (i = start; i < cnt + start; ++i) {
4967 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4968 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4974 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4975 IWineD3DDevice *iface,
4980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4981 int cnt = min(count, MAX_CONST_B - start);
4983 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4984 iface, dstData, start, count);
4986 if (dstData == NULL || cnt < 0)
4987 return WINED3DERR_INVALIDCALL;
4989 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4993 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4994 IWineD3DDevice *iface,
4999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5000 int i, cnt = min(count, MAX_CONST_I - start);
5002 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5003 iface, srcData, start, count);
5005 if (srcData == NULL || cnt < 0)
5006 return WINED3DERR_INVALIDCALL;
5008 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
5009 for (i = 0; i < cnt; i++)
5010 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
5011 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5013 for (i = start; i < cnt + start; ++i) {
5014 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
5015 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
5021 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
5022 IWineD3DDevice *iface,
5027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5028 int cnt = min(count, MAX_CONST_I - start);
5030 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5031 iface, dstData, start, count);
5033 if (dstData == NULL || cnt < 0)
5034 return WINED3DERR_INVALIDCALL;
5036 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5040 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5041 IWineD3DDevice *iface,
5043 CONST float *srcData,
5046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5047 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5049 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5050 iface, srcData, start, count);
5052 if (srcData == NULL || cnt < 0)
5053 return WINED3DERR_INVALIDCALL;
5055 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5056 for (i = 0; i < cnt; i++)
5057 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5058 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5060 for (i = start; i < cnt + start; ++i) {
5061 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5062 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5064 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5065 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5067 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5074 IWineD3DDevice *iface,
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5082 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5083 iface, dstData, start, count);
5085 if (dstData == NULL || cnt < 0)
5086 return WINED3DERR_INVALIDCALL;
5088 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5092 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5094 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5095 char *dest_ptr, *dest_conv = NULL;
5097 DWORD DestFVF = dest->fvf;
5099 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
5103 if (SrcFVF & WINED3DFVF_NORMAL) {
5104 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5107 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
5108 ERR("Source has no position mask\n");
5109 return WINED3DERR_INVALIDCALL;
5112 /* We might access VBOs from this code, so hold the lock */
5115 if (dest->resource.allocatedMemory == NULL) {
5116 /* This may happen if we do direct locking into a vbo. Unlikely,
5117 * but theoretically possible(ddraw processvertices test)
5119 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5120 if(!dest->resource.allocatedMemory) {
5122 ERR("Out of memory\n");
5123 return E_OUTOFMEMORY;
5127 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5128 checkGLcall("glBindBufferARB");
5129 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5131 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5133 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5134 checkGLcall("glUnmapBufferARB");
5138 /* Get a pointer into the destination vbo(create one if none exists) and
5139 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5141 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5146 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5147 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5149 ERR("glMapBuffer failed\n");
5150 /* Continue without storing converted vertices */
5155 * a) WINED3DRS_CLIPPING is enabled
5156 * b) WINED3DVOP_CLIP is passed
5158 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5159 static BOOL warned = FALSE;
5161 * The clipping code is not quite correct. Some things need
5162 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5163 * so disable clipping for now.
5164 * (The graphics in Half-Life are broken, and my processvertices
5165 * test crashes with IDirect3DDevice3)
5171 FIXME("Clipping is broken and disabled for now\n");
5173 } else doClip = FALSE;
5174 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5176 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5179 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5182 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5183 WINED3DTS_PROJECTION,
5185 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5186 WINED3DTS_WORLDMATRIX(0),
5189 TRACE("View mat:\n");
5190 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); \
5191 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); \
5192 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); \
5193 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); \
5195 TRACE("Proj mat:\n");
5196 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); \
5197 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); \
5198 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); \
5199 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); \
5201 TRACE("World mat:\n");
5202 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); \
5203 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); \
5204 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); \
5205 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); \
5207 /* Get the viewport */
5208 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5209 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
5210 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5212 multiply_matrix(&mat,&view_mat,&world_mat);
5213 multiply_matrix(&mat,&proj_mat,&mat);
5215 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
5217 for (i = 0; i < dwCount; i+= 1) {
5218 unsigned int tex_index;
5220 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
5221 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
5222 /* The position first */
5224 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5226 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5228 /* Multiplication with world, view and projection matrix */
5229 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);
5230 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);
5231 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);
5232 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);
5234 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5236 /* WARNING: The following things are taken from d3d7 and were not yet checked
5237 * against d3d8 or d3d9!
5240 /* Clipping conditions: From
5241 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5243 * A vertex is clipped if it does not match the following requirements
5247 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5249 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5250 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5255 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5256 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5259 /* "Normal" viewport transformation (not clipped)
5260 * 1) The values are divided by rhw
5261 * 2) The y axis is negative, so multiply it with -1
5262 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5263 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5264 * 4) Multiply x with Width/2 and add Width/2
5265 * 5) The same for the height
5266 * 6) Add the viewpoint X and Y to the 2D coordinates and
5267 * The minimum Z value to z
5268 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5270 * Well, basically it's simply a linear transformation into viewport
5282 z *= vp.MaxZ - vp.MinZ;
5284 x += vp.Width / 2 + vp.X;
5285 y += vp.Height / 2 + vp.Y;
5290 /* That vertex got clipped
5291 * Contrary to OpenGL it is not dropped completely, it just
5292 * undergoes a different calculation.
5294 TRACE("Vertex got clipped\n");
5301 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5302 * outside of the main vertex buffer memory. That needs some more
5307 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5310 ( (float *) dest_ptr)[0] = x;
5311 ( (float *) dest_ptr)[1] = y;
5312 ( (float *) dest_ptr)[2] = z;
5313 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5315 dest_ptr += 3 * sizeof(float);
5317 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5318 dest_ptr += sizeof(float);
5323 ( (float *) dest_conv)[0] = x * w;
5324 ( (float *) dest_conv)[1] = y * w;
5325 ( (float *) dest_conv)[2] = z * w;
5326 ( (float *) dest_conv)[3] = w;
5328 dest_conv += 3 * sizeof(float);
5330 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
5331 dest_conv += sizeof(float);
5335 if (DestFVF & WINED3DFVF_PSIZE) {
5336 dest_ptr += sizeof(DWORD);
5337 if(dest_conv) dest_conv += sizeof(DWORD);
5339 if (DestFVF & WINED3DFVF_NORMAL) {
5341 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5342 /* AFAIK this should go into the lighting information */
5343 FIXME("Didn't expect the destination to have a normal\n");
5344 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5346 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5350 if (DestFVF & WINED3DFVF_DIFFUSE) {
5352 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5354 static BOOL warned = FALSE;
5357 ERR("No diffuse color in source, but destination has one\n");
5361 *( (DWORD *) dest_ptr) = 0xffffffff;
5362 dest_ptr += sizeof(DWORD);
5365 *( (DWORD *) dest_conv) = 0xffffffff;
5366 dest_conv += sizeof(DWORD);
5370 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5372 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5373 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5374 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5375 dest_conv += sizeof(DWORD);
5380 if (DestFVF & WINED3DFVF_SPECULAR) {
5381 /* What's the color value in the feedback buffer? */
5383 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5385 static BOOL warned = FALSE;
5388 ERR("No specular color in source, but destination has one\n");
5392 *( (DWORD *) dest_ptr) = 0xFF000000;
5393 dest_ptr += sizeof(DWORD);
5396 *( (DWORD *) dest_conv) = 0xFF000000;
5397 dest_conv += sizeof(DWORD);
5401 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5403 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5404 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5405 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5406 dest_conv += sizeof(DWORD);
5411 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5413 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5414 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5416 ERR("No source texture, but destination requests one\n");
5417 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5418 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5421 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5423 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5430 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5431 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5438 #undef copy_and_next
5440 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5442 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5443 WineDirect3DVertexStridedData strided;
5444 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5447 WARN("NULL source vertex buffer\n");
5448 return WINED3DERR_INVALIDCALL;
5450 /* We don't need the source vbo because this buffer is only used as
5451 * a source for ProcessVertices. Avoid wasting resources by converting the
5452 * buffer and loading the VBO
5455 TRACE("Releasing the source vbo, it won't be needed\n");
5457 if(!SrcImpl->resource.allocatedMemory) {
5458 /* Rescue the data from the buffer */
5460 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5461 if(!SrcImpl->resource.allocatedMemory) {
5462 ERR("Out of memory\n");
5463 return E_OUTOFMEMORY;
5467 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5468 checkGLcall("glBindBufferARB");
5470 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5472 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5475 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5476 checkGLcall("glUnmapBufferARB");
5481 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5482 checkGLcall("glBindBufferARB");
5483 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5484 checkGLcall("glDeleteBuffersARB");
5490 memset(&strided, 0, sizeof(strided));
5491 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5493 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5497 * Apply / Get / Set Texture Stage States
5498 * TODO: Verify against dx9 definitions
5501 /* 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 */
5502 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5504 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5505 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5507 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5509 /* Check that the stage is within limits */
5510 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5511 TRACE("Attempt to access invalid texture rejected\n");
5518 case WINED3DTSS_ALPHAOP :
5519 case WINED3DTSS_COLOROP :
5520 /* nothing to do as moved to drawprim for now */
5522 case WINED3DTSS_ADDRESSW :
5523 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5524 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5525 FIXME("Unrecognized or unsupported WINED3DTADDRESS_* value %d, state %d\n", Value, Type);
5528 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5529 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5530 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5531 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5534 case WINED3DTSS_TEXCOORDINDEX :
5536 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5538 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5539 one flag, you can still specify an index value, which the system uses to
5540 determine the texture wrapping mode.
5541 eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5542 means use the vertex position (camera-space) as the input texture coordinates
5543 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5544 state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up
5545 to the TEXCOORDINDEX value */
5548 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5550 switch (Value & 0xFFFF0000) {
5551 case WINED3DTSS_TCI_PASSTHRU:
5552 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5553 glDisable(GL_TEXTURE_GEN_S);
5554 glDisable(GL_TEXTURE_GEN_T);
5555 glDisable(GL_TEXTURE_GEN_R);
5556 glDisable(GL_TEXTURE_GEN_Q);
5557 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5560 case WINED3DTSS_TCI_CAMERASPACEPOSITION:
5561 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5562 as the input texture coordinates for this stage's texture transformation. This
5563 equates roughly to EYE_LINEAR */
5565 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5566 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5567 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5568 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5569 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5571 glMatrixMode(GL_MODELVIEW);
5574 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5575 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5576 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5577 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5580 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5581 glEnable(GL_TEXTURE_GEN_S);
5582 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5583 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5584 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5585 glEnable(GL_TEXTURE_GEN_T);
5586 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5587 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5588 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5589 glEnable(GL_TEXTURE_GEN_R);
5590 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5591 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5592 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5596 case WINED3DTSS_TCI_CAMERASPACENORMAL:
5598 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5599 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5600 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5601 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5602 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5603 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5605 glMatrixMode(GL_MODELVIEW);
5608 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5609 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5610 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5611 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5614 glEnable(GL_TEXTURE_GEN_S);
5615 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5616 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5617 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5618 glEnable(GL_TEXTURE_GEN_T);
5619 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5620 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5621 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5622 glEnable(GL_TEXTURE_GEN_R);
5623 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5624 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5625 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5630 case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5632 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5633 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5634 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5635 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5636 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5637 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5639 glMatrixMode(GL_MODELVIEW);
5642 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5643 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5644 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5645 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5648 glEnable(GL_TEXTURE_GEN_S);
5649 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5650 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5651 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5652 glEnable(GL_TEXTURE_GEN_T);
5653 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5654 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5655 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5656 glEnable(GL_TEXTURE_GEN_R);
5657 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5658 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5659 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5664 /* Unhandled types: */
5667 /* ? disable GL_TEXTURE_GEN_n ? */
5668 glDisable(GL_TEXTURE_GEN_S);
5669 glDisable(GL_TEXTURE_GEN_T);
5670 glDisable(GL_TEXTURE_GEN_R);
5671 glDisable(GL_TEXTURE_GEN_Q);
5672 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", Value);
5679 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5680 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);
5683 case WINED3DTSS_BUMPENVMAT00 :
5684 case WINED3DTSS_BUMPENVMAT01 :
5685 TRACE("BUMPENVMAT0%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5687 case WINED3DTSS_BUMPENVMAT10 :
5688 case WINED3DTSS_BUMPENVMAT11 :
5689 TRACE("BUMPENVMAT1%u Stage=%d, Type=%d, Value =%d\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5692 case WINED3DTSS_BUMPENVLSCALE :
5693 TRACE("BUMPENVLSCALE Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5696 case WINED3DTSS_BUMPENVLOFFSET :
5697 TRACE("BUMPENVLOFFSET Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5700 case WINED3DTSS_RESULTARG :
5701 TRACE("RESULTARG Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5705 /* Put back later: FIXME("(%p) : stub, Stage=%d, Type=%d, Value =%d\n", This, Stage, Type, Value); */
5706 TRACE("Still a stub, Stage=%d, Type=%d, Value =%d\n", Stage, Type, Value);
5715 * Get / Set Texture Stage States
5716 * TODO: Verify against dx9 definitions
5718 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5721 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5723 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5725 /* Reject invalid texture units */
5726 if (Stage >= GL_LIMITS(texture_stages)) {
5727 TRACE("Attempt to access invalid texture rejected\n");
5728 return WINED3DERR_INVALIDCALL;
5731 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5732 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5733 This->updateStateBlock->textureState[Stage][Type] = Value;
5738 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5741 *pValue = This->updateStateBlock->textureState[Stage][Type];
5748 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5751 IWineD3DBaseTexture *oldTexture;
5753 oldTexture = This->updateStateBlock->textures[Stage];
5754 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
5756 #if 0 /* TODO: check so vertex textures */
5757 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5758 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5763 /* Reject invalid texture units */
5764 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5765 WARN("Attempt to access invalid texture rejected\n");
5766 return WINED3DERR_INVALIDCALL;
5769 if(pTexture != NULL) {
5770 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5772 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5773 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5774 return WINED3DERR_INVALIDCALL;
5778 oldTexture = This->updateStateBlock->textures[Stage];
5779 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5780 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5782 This->updateStateBlock->set.textures[Stage] = TRUE;
5783 This->updateStateBlock->changed.textures[Stage] = TRUE;
5784 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5785 This->updateStateBlock->textures[Stage] = pTexture;
5787 /* Handle recording of state blocks */
5788 if (This->isRecordingState) {
5789 TRACE("Recording... not performing anything\n");
5793 /** NOTE: MSDN says that setTexture increases the reference count,
5794 * and the the application nust set the texture back to null (or have a leaky application),
5795 * This means we should pass the refcount up to the parent
5796 *******************************/
5797 if (NULL != This->updateStateBlock->textures[Stage]) {
5798 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5801 if (NULL != oldTexture) {
5802 IWineD3DBaseTexture_Release(oldTexture);
5805 /* Reset color keying */
5806 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5807 BOOL enable_ckey = FALSE;
5810 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5811 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5815 glAlphaFunc(GL_NOTEQUAL, 0.0);
5816 checkGLcall("glAlphaFunc");
5823 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5825 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5827 /* Reject invalid texture units */
5828 if (Stage >= GL_LIMITS(sampler_stages)) {
5829 TRACE("Attempt to access invalid texture rejected\n");
5830 return WINED3DERR_INVALIDCALL;
5832 *ppTexture=This->stateBlock->textures[Stage];
5840 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5841 IWineD3DSurface **ppBackBuffer) {
5842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5843 IWineD3DSwapChain *swapChain;
5846 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5848 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5849 if (hr == WINED3D_OK) {
5850 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5852 *ppBackBuffer = NULL;
5857 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5859 WARN("(%p) : stub, calling idirect3d for now\n", This);
5860 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5863 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5865 IWineD3DSwapChain *swapChain;
5868 if(iSwapChain > 0) {
5869 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5870 if (hr == WINED3D_OK) {
5871 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5873 FIXME("(%p) Error getting display mode\n", This);
5876 /* Don't read the real display mode,
5877 but return the stored mode instead. X11 can't change the color
5878 depth, and some apps are pretty angry if they SetDisplayMode from
5879 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5881 Also don't relay to the swapchain because with ddraw it's possible
5882 that there isn't a swapchain at all */
5883 pMode->Width = This->ddraw_width;
5884 pMode->Height = This->ddraw_height;
5885 pMode->Format = This->ddraw_format;
5886 pMode->RefreshRate = 0;
5893 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5895 TRACE("(%p)->(%p)\n", This, hWnd);
5897 This->ddraw_window = hWnd;
5901 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5903 TRACE("(%p)->(%p)\n", This, hWnd);
5905 *hWnd = This->ddraw_window;
5910 * Stateblock related functions
5913 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5915 IWineD3DStateBlockImpl *object;
5916 HRESULT temp_result;
5918 TRACE("(%p)\n", This);
5920 if (This->isRecordingState) {
5921 return WINED3DERR_INVALIDCALL;
5924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5925 if (NULL == object ) {
5926 FIXME("(%p)Error allocating memory for stateblock\n", This);
5927 return E_OUTOFMEMORY;
5929 TRACE("(%p) created object %p\n", This, object);
5930 object->wineD3DDevice= This;
5931 /** FIXME: object->parent = parent; **/
5932 object->parent = NULL;
5933 object->blockType = WINED3DSBT_ALL;
5935 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5937 temp_result = allocate_shader_constants(object);
5938 if (WINED3D_OK != temp_result)
5941 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5942 This->updateStateBlock = object;
5943 This->isRecordingState = TRUE;
5945 TRACE("(%p) recording stateblock %p\n",This , object);
5949 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5952 if (!This->isRecordingState) {
5953 FIXME("(%p) not recording! returning error\n", This);
5954 *ppStateBlock = NULL;
5955 return WINED3DERR_INVALIDCALL;
5958 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5959 This->isRecordingState = FALSE;
5960 This->updateStateBlock = This->stateBlock;
5961 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5962 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5963 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5968 * Scene related functions
5970 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5971 /* At the moment we have no need for any functionality at the beginning
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5974 TRACE("(%p) : stub\n", This);
5978 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5980 TRACE("(%p)\n", This);
5982 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5984 checkGLcall("glFlush");
5986 TRACE("End Scene\n");
5987 /* If we're using FBOs this isn't needed */
5988 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
5990 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5991 IUnknown *targetContainer = NULL;
5992 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5993 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5994 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5995 /** always dirtify for now. we must find a better way to see that surface have been modified
5996 (Modifications should will only occur via draw-primitive, but we do need better locking
5997 switching to render-to-texture should remove the overhead though.
5999 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
6000 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
6001 IWineD3DSurface_PreLoad(This->renderTarget);
6002 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
6003 IUnknown_Release(targetContainer);
6006 This->sceneEnded = TRUE;
6011 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
6012 CONST RECT* pSourceRect, CONST RECT* pDestRect,
6013 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
6014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6015 IWineD3DSwapChain *swapChain = NULL;
6017 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
6019 TRACE("(%p) Presenting the frame\n", This);
6021 for(i = 0 ; i < swapchains ; i ++) {
6023 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6024 TRACE("presentinng chain %d, %p\n", i, swapChain);
6025 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6031 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
6032 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
6036 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
6037 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6038 GLbitfield glMask = 0;
6039 GLboolean old_ztest;
6040 GLfloat old_z_clear_value;
6041 GLint old_stencil_clear_value;
6042 GLfloat old_color_clear_value[4];
6044 CONST WINED3DRECT* curRect;
6046 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
6047 Count, pRects, Flags, Z, Stencil);
6051 glEnable(GL_SCISSOR_TEST);
6052 checkGLcall("glEnable GL_SCISSOR_TEST");
6054 if (Count > 0 && pRects) {
6060 /* Only set the values up once, as they are not changing */
6061 if (Flags & WINED3DCLEAR_STENCIL) {
6062 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6063 glClearStencil(Stencil);
6064 checkGLcall("glClearStencil");
6065 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6066 glStencilMask(0xFFFFFFFF);
6069 if (Flags & WINED3DCLEAR_ZBUFFER) {
6070 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6071 glDepthMask(GL_TRUE);
6072 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6074 checkGLcall("glClearDepth");
6075 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6078 if (Flags & WINED3DCLEAR_TARGET) {
6079 TRACE("Clearing screen with glClear to color %x\n", Color);
6080 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6081 glClearColor(D3DCOLOR_R(Color),
6085 checkGLcall("glClearColor");
6087 /* Clear ALL colors! */
6088 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6089 glMask = glMask | GL_COLOR_BUFFER_BIT;
6092 /* Now process each rect in turn */
6093 for (i = 0; i < Count || i == 0; i++) {
6096 /* Note gl uses lower left, width/height */
6097 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
6098 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6099 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6100 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6101 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6102 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6103 checkGLcall("glScissor");
6105 glScissor(This->stateBlock->viewport.X,
6106 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6107 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6108 This->stateBlock->viewport.Width,
6109 This->stateBlock->viewport.Height);
6110 checkGLcall("glScissor");
6113 /* Clear the selected rectangle (or full screen) */
6115 checkGLcall("glClear");
6117 /* Step to the next rectangle */
6118 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
6121 /* Restore the old values (why..?) */
6122 if (Flags & WINED3DCLEAR_STENCIL) {
6123 glClearStencil(old_stencil_clear_value);
6124 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6126 if (Flags & WINED3DCLEAR_ZBUFFER) {
6127 glDepthMask(old_ztest);
6128 glClearDepth(old_z_clear_value);
6130 if (Flags & WINED3DCLEAR_TARGET) {
6131 glClearColor(old_color_clear_value[0],
6132 old_color_clear_value[1],
6133 old_color_clear_value[2],
6134 old_color_clear_value[3]);
6135 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6136 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6137 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6138 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6141 glDisable(GL_SCISSOR_TEST);
6142 checkGLcall("glDisable");
6151 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6152 UINT PrimitiveCount) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6155 This->stateBlock->streamIsUP = FALSE;
6157 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6158 debug_d3dprimitivetype(PrimitiveType),
6159 StartVertex, PrimitiveCount);
6160 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6161 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6167 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6168 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6169 WINED3DPRIMITIVETYPE PrimitiveType,
6170 INT baseVIndex, UINT minIndex,
6171 UINT NumVertices, UINT startIndex, UINT primCount) {
6173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6175 IWineD3DIndexBuffer *pIB;
6176 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6178 pIB = This->stateBlock->pIndexData;
6179 This->stateBlock->streamIsUP = FALSE;
6181 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6182 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6183 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6185 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6186 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6192 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6193 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6198 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6199 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6200 UINT VertexStreamZeroStride) {
6201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6203 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6204 debug_d3dprimitivetype(PrimitiveType),
6205 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6207 /* release the stream source */
6208 if (This->stateBlock->streamSource[0] != NULL) {
6209 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6212 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6213 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6214 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6215 This->stateBlock->streamIsUP = TRUE;
6217 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6218 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6220 /* MSDN specifies stream zero settings must be set to NULL */
6221 This->stateBlock->streamStride[0] = 0;
6222 This->stateBlock->streamSource[0] = NULL;
6224 /*stream zero settings set to null at end, as per the msdn */
6228 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
6229 UINT MinVertexIndex, UINT NumVertices,
6230 UINT PrimitiveCount, CONST void* pIndexData,
6231 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6232 UINT VertexStreamZeroStride) {
6234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6236 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6237 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6238 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6239 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6241 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6247 /* release the stream and index data */
6248 if (This->stateBlock->streamSource[0] != NULL) {
6249 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6251 if (This->stateBlock->pIndexData) {
6252 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6255 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6256 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6257 This->stateBlock->streamIsUP = TRUE;
6258 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6260 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6262 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6263 This->stateBlock->streamSource[0] = NULL;
6264 This->stateBlock->streamStride[0] = 0;
6265 This->stateBlock->pIndexData = NULL;
6270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6272 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6275 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6276 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6278 HRESULT hr = WINED3D_OK;
6279 WINED3DRESOURCETYPE sourceType;
6280 WINED3DRESOURCETYPE destinationType;
6283 /* TODO: think about moving the code into IWineD3DBaseTexture */
6285 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6287 /* verify that the source and destination textures aren't NULL */
6288 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6289 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6290 This, pSourceTexture, pDestinationTexture);
6291 hr = WINED3DERR_INVALIDCALL;
6294 if (pSourceTexture == pDestinationTexture) {
6295 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6296 This, pSourceTexture, pDestinationTexture);
6297 hr = WINED3DERR_INVALIDCALL;
6299 /* Verify that the source and destination textures are the same type */
6300 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6301 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6303 if (sourceType != destinationType) {
6304 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6306 hr = WINED3DERR_INVALIDCALL;
6309 /* check that both textures have the identical numbers of levels */
6310 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6311 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6312 hr = WINED3DERR_INVALIDCALL;
6315 if (WINED3D_OK == hr) {
6317 /* Make sure that the destination texture is loaded */
6318 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6320 /* Update every surface level of the texture */
6321 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6323 switch (sourceType) {
6324 case WINED3DRTYPE_TEXTURE:
6326 IWineD3DSurface *srcSurface;
6327 IWineD3DSurface *destSurface;
6329 for (i = 0 ; i < levels ; ++i) {
6330 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6331 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6332 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6333 IWineD3DSurface_Release(srcSurface);
6334 IWineD3DSurface_Release(destSurface);
6335 if (WINED3D_OK != hr) {
6336 WARN("(%p) : Call to update surface failed\n", This);
6342 case WINED3DRTYPE_CUBETEXTURE:
6344 IWineD3DSurface *srcSurface;
6345 IWineD3DSurface *destSurface;
6346 WINED3DCUBEMAP_FACES faceType;
6348 for (i = 0 ; i < levels ; ++i) {
6349 /* Update each cube face */
6350 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6351 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6352 if (WINED3D_OK != hr) {
6353 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6355 TRACE("Got srcSurface %p\n", srcSurface);
6357 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6358 if (WINED3D_OK != hr) {
6359 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6361 TRACE("Got desrSurface %p\n", destSurface);
6363 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6364 IWineD3DSurface_Release(srcSurface);
6365 IWineD3DSurface_Release(destSurface);
6366 if (WINED3D_OK != hr) {
6367 WARN("(%p) : Call to update surface failed\n", This);
6374 #if 0 /* TODO: Add support for volume textures */
6375 case WINED3DRTYPE_VOLUMETEXTURE:
6377 IWineD3DVolume srcVolume = NULL;
6378 IWineD3DSurface destVolume = NULL;
6380 for (i = 0 ; i < levels ; ++i) {
6381 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6382 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6383 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6384 IWineD3DVolume_Release(srcSurface);
6385 IWineD3DVolume_Release(destSurface);
6386 if (WINED3D_OK != hr) {
6387 WARN("(%p) : Call to update volume failed\n", This);
6395 FIXME("(%p) : Unsupported source and destination type\n", This);
6396 hr = WINED3DERR_INVALIDCALL;
6403 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6404 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6405 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6408 TRACE("(%p) : stub\n", This);
6411 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6413 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6414 * NOTE It may be best to move the code into surface to occomplish this
6415 ****************************************/
6417 WINED3DSURFACE_DESC surfaceDesc;
6418 unsigned int surfaceWidth, surfaceHeight;
6419 glDescriptor *targetGlDescription = NULL;
6420 glDescriptor *surfaceGlDescription = NULL;
6421 IWineD3DSwapChainImpl *container = NULL;
6423 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6424 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6425 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6427 surfaceDesc.Width = &surfaceWidth;
6428 surfaceDesc.Height = &surfaceHeight;
6429 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6430 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6432 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6433 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6435 /* TODO: opengl Context switching for swapchains etc... */
6436 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6437 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6438 glReadBuffer(GL_BACK);
6439 vcheckGLcall("glReadBuffer(GL_BACK)");
6440 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6441 glReadBuffer(GL_FRONT);
6442 vcheckGLcall("glReadBuffer(GL_FRONT)");
6443 } else if (pRenderTarget == This->depthStencilBuffer) {
6444 FIXME("Reading of depthstencil not yet supported\n");
6451 surfaceGlDescription->glFormat,
6452 surfaceGlDescription->glType,
6453 (void *)IWineD3DSurface_GetData(pSurface));
6454 vcheckGLcall("glReadPixels(...)");
6455 if(NULL != container ){
6456 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6459 IWineD3DBaseTexture *container;
6460 GLenum textureDimensions = GL_TEXTURE_2D;
6462 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6463 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6464 IWineD3DBaseTexture_Release(container);
6466 /* TODO: 2D -> Cube surface coppies etc.. */
6467 if (surfaceGlDescription->target != textureDimensions) {
6468 FIXME("(%p) : Texture dimension mismatch\n", This);
6470 glEnable(textureDimensions);
6471 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6472 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6473 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6474 vcheckGLcall("glBindTexture");
6475 glGetTexImage(surfaceGlDescription->target,
6476 surfaceGlDescription->level,
6477 surfaceGlDescription->glFormat,
6478 surfaceGlDescription->glType,
6479 (void *)IWineD3DSurface_GetData(pSurface));
6480 glDisable(textureDimensions);
6481 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6488 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6489 IWineD3DSwapChain *swapChain;
6491 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6492 if(hr == WINED3D_OK) {
6493 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6498 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6500 /* return a sensible default */
6502 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6503 FIXME("(%p) : stub\n", This);
6507 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6510 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6511 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6512 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6513 return WINED3DERR_INVALIDCALL;
6515 for (j = 0; j < 256; ++j) {
6516 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6517 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6518 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6519 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6521 TRACE("(%p) : returning\n", This);
6525 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6528 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6529 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6530 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6531 return WINED3DERR_INVALIDCALL;
6533 for (j = 0; j < 256; ++j) {
6534 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6535 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6536 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6537 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6539 TRACE("(%p) : returning\n", This);
6543 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6545 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6546 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6547 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6548 return WINED3DERR_INVALIDCALL;
6550 /*TODO: stateblocks */
6551 This->currentPalette = PaletteNumber;
6552 TRACE("(%p) : returning\n", This);
6556 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6558 if (PaletteNumber == NULL) {
6559 WARN("(%p) : returning Invalid Call\n", This);
6560 return WINED3DERR_INVALIDCALL;
6562 /*TODO: stateblocks */
6563 *PaletteNumber = This->currentPalette;
6564 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6568 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6570 static BOOL showFixmes = TRUE;
6572 FIXME("(%p) : stub\n", This);
6576 This->softwareVertexProcessing = bSoftware;
6581 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6583 static BOOL showFixmes = TRUE;
6585 FIXME("(%p) : stub\n", This);
6588 return This->softwareVertexProcessing;
6592 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6594 IWineD3DSwapChain *swapChain;
6597 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6599 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6600 if(hr == WINED3D_OK){
6601 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6603 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6609 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6611 static BOOL showfixmes = TRUE;
6612 if(nSegments != 0.0f) {
6614 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6621 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6623 static BOOL showfixmes = TRUE;
6625 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6631 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6633 /** TODO: remove casts to IWineD3DSurfaceImpl
6634 * NOTE: move code to surface to accomplish this
6635 ****************************************/
6636 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6637 int srcWidth, srcHeight;
6638 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6639 WINED3DFORMAT destFormat, srcFormat;
6641 int destLeft, destTop;
6642 WINED3DPOOL srcPool, destPool;
6644 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6645 glDescriptor *glDescription = NULL;
6646 GLenum textureDimensions = GL_TEXTURE_2D;
6647 IWineD3DBaseTexture *baseTexture;
6649 WINED3DSURFACE_DESC winedesc;
6651 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6652 memset(&winedesc, 0, sizeof(winedesc));
6653 winedesc.Width = &srcSurfaceWidth;
6654 winedesc.Height = &srcSurfaceHeight;
6655 winedesc.Pool = &srcPool;
6656 winedesc.Format = &srcFormat;
6658 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6660 winedesc.Width = &destSurfaceWidth;
6661 winedesc.Height = &destSurfaceHeight;
6662 winedesc.Pool = &destPool;
6663 winedesc.Format = &destFormat;
6664 winedesc.Size = &destSize;
6666 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6668 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6669 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6670 return WINED3DERR_INVALIDCALL;
6673 if (destFormat == WINED3DFMT_UNKNOWN) {
6674 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6675 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6677 /* Get the update surface description */
6678 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6681 /* Make sure the surface is loaded and up to date */
6682 IWineD3DSurface_PreLoad(pDestinationSurface);
6684 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6688 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6689 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6690 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6691 destLeft = pDestPoint ? pDestPoint->x : 0;
6692 destTop = pDestPoint ? pDestPoint->y : 0;
6695 /* This function doesn't support compressed textures
6696 the pitch is just bytesPerPixel * width */
6697 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6698 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6699 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6700 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6702 /* TODO DXT formats */
6704 if(pSourceRect != NULL && pSourceRect->top != 0){
6705 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6707 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6709 ,glDescription->level
6714 ,glDescription->glFormat
6715 ,glDescription->glType
6716 ,IWineD3DSurface_GetData(pSourceSurface)
6720 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6722 /* need to lock the surface to get the data */
6723 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6726 /* TODO: Cube and volume support */
6728 /* not a whole row so we have to do it a line at a time */
6731 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6732 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6734 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6736 glTexSubImage2D(glDescription->target
6737 ,glDescription->level
6742 ,glDescription->glFormat
6743 ,glDescription->glType
6744 ,data /* could be quicker using */
6749 } else { /* Full width, so just write out the whole texture */
6751 if (WINED3DFMT_DXT1 == destFormat ||
6752 WINED3DFMT_DXT2 == destFormat ||
6753 WINED3DFMT_DXT3 == destFormat ||
6754 WINED3DFMT_DXT4 == destFormat ||
6755 WINED3DFMT_DXT5 == destFormat) {
6756 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6757 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6758 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6759 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6760 } if (destFormat != srcFormat) {
6761 FIXME("Updating mixed format compressed texture is not curretly support\n");
6763 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6764 glDescription->level,
6765 glDescription->glFormatInternal,
6770 IWineD3DSurface_GetData(pSourceSurface));
6773 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6778 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6780 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6781 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6782 data returned by GetData non-power2 width/height with hardware non-power2
6783 pow2Width/height are set to surface width height, repacking isn't needed so it
6784 doesn't matter which function gets called. */
6785 glTexSubImage2D(glDescription->target
6786 ,glDescription->level
6791 ,glDescription->glFormat
6792 ,glDescription->glType
6793 ,IWineD3DSurface_GetData(pSourceSurface)
6797 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6798 glTexSubImage2D(glDescription->target
6799 ,glDescription->level
6802 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6803 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6804 ,glDescription->glFormat
6805 ,glDescription->glType
6806 ,IWineD3DSurface_GetData(pSourceSurface)
6812 checkGLcall("glTexSubImage2D");
6813 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6815 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6816 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6817 * surface bigger than it needs to be hmm.. */
6818 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6819 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6820 IWineD3DBaseTexture_Release(baseTexture);
6823 glDisable(textureDimensions); /* This needs to be managed better.... */
6829 /* Implementation details at http://developer.nvidia.com/attach/6494
6831 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6832 hmm.. no longer supported use
6833 OpenGL evaluators or tessellate surfaces within your application.
6836 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6837 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6839 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6840 FIXME("(%p) : Stub\n", This);
6845 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6846 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6848 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6849 FIXME("(%p) : Stub\n", This);
6853 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6855 TRACE("(%p) Handle(%d)\n", This, Handle);
6856 FIXME("(%p) : Stub\n", This);
6860 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6862 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6864 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
6866 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6867 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6868 return WINED3DERR_INVALIDCALL;
6871 /* Just forward this to the DirectDraw blitting engine */
6872 memset(&BltFx, 0, sizeof(BltFx));
6873 BltFx.dwSize = sizeof(BltFx);
6874 BltFx.u5.dwFillColor = color;
6875 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
6878 /* rendertarget and deptth stencil functions */
6879 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6882 /* FIXME: Implelent RenderTargetIndex >0 */
6883 if(RenderTargetIndex > 0)
6884 FIXME("(%p) : RenderTargetIndex %d >0 not currently supported\n", This, RenderTargetIndex);
6886 *ppRenderTarget = This->renderTarget;
6887 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6892 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6894 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6895 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6896 IWineD3DSwapChainImpl *Swapchain;
6899 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6901 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6902 if(hr != WINED3D_OK) {
6903 ERR("Can't get the swapchain\n");
6907 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6908 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6909 return WINED3DERR_INVALIDCALL;
6911 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6912 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6913 return WINED3DERR_INVALIDCALL;
6916 if(Swapchain->frontBuffer != Front) {
6917 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6919 if(Swapchain->frontBuffer)
6920 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6921 Swapchain->frontBuffer = Front;
6923 if(Swapchain->frontBuffer) {
6924 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6928 if(Back && !Swapchain->backBuffer) {
6929 /* We need memory for the back buffer array - only one back buffer this way */
6930 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6931 if(!Swapchain->backBuffer) {
6932 ERR("Out of memory\n");
6933 return E_OUTOFMEMORY;
6937 if(Swapchain->backBuffer[0] != Back) {
6938 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6940 if(!Swapchain->backBuffer[0]) {
6941 /* GL was told to draw to the front buffer at creation,
6944 glDrawBuffer(GL_BACK);
6945 checkGLcall("glDrawBuffer(GL_BACK)");
6946 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6947 Swapchain->presentParms.BackBufferCount = 1;
6949 /* That makes problems - disable for now */
6950 /* glDrawBuffer(GL_FRONT); */
6951 checkGLcall("glDrawBuffer(GL_FRONT)");
6952 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6953 Swapchain->presentParms.BackBufferCount = 0;
6957 if(Swapchain->backBuffer[0])
6958 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6959 Swapchain->backBuffer[0] = Back;
6961 if(Swapchain->backBuffer[0]) {
6962 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6964 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6972 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6974 *ppZStencilSurface = This->depthStencilBuffer;
6975 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6980 static void bind_fbo(IWineD3DDevice *iface) {
6981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6984 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
6985 checkGLcall("glGenFramebuffersEXT()");
6987 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
6988 checkGLcall("glBindFramebuffer()");
6991 /* TODO: Handle stencil attachments */
6992 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6994 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6996 This->depth_copy_state = WINED3D_DCS_NO_COPY;
7000 if (depth_stencil_impl) {
7001 GLenum texttarget, target;
7003 IWineD3DSurface_PreLoad(depth_stencil);
7004 texttarget = depth_stencil_impl->glDescription.target;
7005 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7007 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
7008 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
7009 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
7010 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
7011 glBindTexture(target, 0);
7013 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
7014 checkGLcall("glFramebufferTexture2DEXT()");
7016 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
7017 checkGLcall("glFramebufferTexture2DEXT()");
7020 if (!This->render_offscreen) {
7021 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7022 checkGLcall("glBindFramebuffer()");
7026 static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
7027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7028 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
7030 if (This->render_offscreen) {
7031 GLenum texttarget, target;
7035 IWineD3DSurface_PreLoad(render_target);
7036 texttarget = rtimpl->glDescription.target;
7037 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
7039 glBindTexture(target, rtimpl->glDescription.textureName);
7040 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
7041 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
7042 glBindTexture(target, 0);
7044 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texttarget, rtimpl->glDescription.textureName, 0));
7045 checkGLcall("glFramebufferTexture2DEXT()");
7047 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7048 checkGLcall("glBindFramebuffer()");
7052 /* internal static helper functions */
7053 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7054 IWineD3DSurface *RenderSurface);
7056 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7058 HRESULT hr = WINED3D_OK;
7059 WINED3DVIEWPORT viewport;
7061 TRACE("(%p) Swapping rendertarget\n",This);
7062 if (RenderTargetIndex > 0) {
7063 FIXME("(%p) Render targets other than the first are not supported\n",This);
7064 RenderTargetIndex = 0;
7067 /* MSDN says that null disables the render target
7068 but a device must always be associated with a render target
7069 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7071 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7074 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7075 FIXME("Trying to set render target 0 to NULL\n");
7076 return WINED3DERR_INVALIDCALL;
7078 /* TODO: replace Impl* usage with interface usage */
7079 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7080 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);
7081 return WINED3DERR_INVALIDCALL;
7083 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7084 * builds, but I think wine counts as a 'debug' build for now.
7085 ******************************/
7086 /* If we are trying to set what we already have, don't bother */
7087 if (pRenderTarget == This->renderTarget) {
7088 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7090 /* Otherwise, set the render target up */
7092 if (!This->sceneEnded) {
7093 IWineD3DDevice_EndScene(iface);
7095 TRACE("clearing renderer\n");
7096 /* IWineD3DDeviceImpl_CleanRender(iface); */
7097 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7098 depending on the renter target implementation being used.
7099 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7100 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7101 stencil buffer and incure an extra memory overhead */
7102 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7103 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7104 set_render_target_fbo(iface, pRenderTarget);
7108 if (SUCCEEDED(hr)) {
7109 /* Finally, reset the viewport as the MSDN states. */
7110 /* TODO: Replace impl usage */
7111 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7112 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7115 viewport.MaxZ = 1.0f;
7116 viewport.MinZ = 0.0f;
7117 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7119 FIXME("Unknown error setting the render target\n");
7121 This->sceneEnded = FALSE;
7125 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7127 HRESULT hr = WINED3D_OK;
7128 IWineD3DSurface *tmp;
7130 TRACE("(%p) Swapping z-buffer\n",This);
7132 if (pNewZStencil == This->stencilBufferTarget) {
7133 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7135 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7136 * depending on the renter target implementation being used.
7137 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7138 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7139 * stencil buffer and incure an extra memory overhead
7140 ******************************************************/
7143 tmp = This->stencilBufferTarget;
7144 This->stencilBufferTarget = pNewZStencil;
7145 /* should we be calling the parent or the wined3d surface? */
7146 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7147 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7149 /** TODO: glEnable/glDisable on depth/stencil depending on
7150 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7151 **********************************************************/
7152 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7153 set_depth_stencil_fbo(iface, pNewZStencil);
7161 #ifdef GL_VERSION_1_3
7162 /* Internal functions not in DirectX */
7163 /** TODO: move this off to the opengl context manager
7164 *(the swapchain doesn't need to know anything about offscreen rendering!)
7165 ****************************************************/
7167 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7171 TRACE("(%p), %p\n", This, swapchain);
7173 if (swapchain->win != swapchain->drawable) {
7174 /* Set everything back the way it ws */
7175 swapchain->render_ctx = swapchain->glCtx;
7176 swapchain->drawable = swapchain->win;
7181 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7182 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7186 unsigned int height;
7187 WINED3DFORMAT format;
7188 WINED3DSURFACE_DESC surfaceDesc;
7189 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7190 surfaceDesc.Width = &width;
7191 surfaceDesc.Height = &height;
7192 surfaceDesc.Format = &format;
7193 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7195 /* I need a get width/height function (and should do something with the format) */
7196 for (i = 0; i < CONTEXT_CACHE; ++i) {
7197 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7198 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7199 the pSurface can be set to 0 allowing it to be reused from cache **/
7200 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7201 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7202 *context = &This->contextCache[i];
7205 if (This->contextCache[i].Width == 0) {
7206 This->contextCache[i].pSurface = pSurface;
7207 This->contextCache[i].Width = width;
7208 This->contextCache[i].Height = height;
7209 *context = &This->contextCache[i];
7213 if (i == CONTEXT_CACHE) {
7214 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7215 glContext *dropContext = 0;
7216 for (i = 0; i < CONTEXT_CACHE; i++) {
7217 if (This->contextCache[i].usedcount < minUsage) {
7218 dropContext = &This->contextCache[i];
7219 minUsage = This->contextCache[i].usedcount;
7222 /* clean up the context (this doesn't work for ATI at the moment */
7224 glXDestroyContext(swapchain->display, dropContext->context);
7225 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7228 dropContext->Width = 0;
7229 dropContext->pSurface = pSurface;
7230 *context = dropContext;
7232 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7233 for (i = 0; i < CONTEXT_CACHE; i++) {
7234 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7238 if (*context != NULL)
7241 return E_OUTOFMEMORY;
7245 /* Reapply the device stateblock */
7246 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7249 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7251 /* Disable recording */
7252 oldUpdateStateBlock = This->updateStateBlock;
7253 oldRecording= This->isRecordingState;
7254 This->isRecordingState = FALSE;
7255 This->updateStateBlock = This->stateBlock;
7257 /* Reapply the state block */
7258 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7260 /* Restore recording */
7261 This->isRecordingState = oldRecording;
7262 This->updateStateBlock = oldUpdateStateBlock;
7265 /* Set offscreen rendering. When rendering offscreen the surface will be
7266 * rendered upside down to compensate for the fact that D3D texture coordinates
7267 * are flipped compared to GL texture coordinates. The cullmode is affected by
7268 * this, so it must be updated. To update the cullmode stateblock recording has
7269 * to be temporarily disabled. The new state management code will hopefully
7270 * make this unnecessary */
7271 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7275 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7277 /* Nothing to update, return. */
7278 if (This->render_offscreen == isTexture) return;
7280 /* Disable recording */
7281 oldUpdateStateBlock = This->updateStateBlock;
7282 oldRecording= This->isRecordingState;
7283 This->isRecordingState = FALSE;
7284 This->updateStateBlock = This->stateBlock;
7286 This->render_offscreen = isTexture;
7287 if (This->depth_copy_state != WINED3D_DCS_NO_COPY) {
7288 This->depth_copy_state = WINED3D_DCS_COPY;
7290 This->last_was_rhw = FALSE;
7291 This->proj_valid = FALSE;
7292 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7293 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7295 /* Restore recording */
7296 This->isRecordingState = oldRecording;
7297 This->updateStateBlock = oldUpdateStateBlock;
7300 /* Returns an array of compatible FBconfig(s).
7301 * The array must be freed with XFree. Requires ENTER_GL() */
7303 static GLXFBConfig* device_find_fbconfigs(
7304 IWineD3DDeviceImpl* This,
7305 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7306 IWineD3DSurface* RenderSurface) {
7308 GLXFBConfig* cfgs = NULL;
7313 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7314 WINED3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7315 WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7318 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7319 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7322 #define PUSH1(att) attribs[nAttribs++] = (att);
7323 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7325 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7327 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7328 PUSH2(GLX_X_RENDERABLE, TRUE);
7329 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7330 TRACE("calling makeglcfg\n");
7331 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7333 TRACE("calling chooseFGConfig\n");
7334 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7335 DefaultScreen(implicitSwapchainImpl->display),
7338 /* OK we didn't find the exact config, so use any reasonable match */
7339 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
7341 static BOOL show_message = TRUE;
7343 ERR("Failed to find exact match, finding alternative but you may "
7344 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7345 show_message = FALSE;
7348 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7349 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7350 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7351 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7352 TRACE("calling makeglcfg\n");
7353 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7355 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7356 DefaultScreen(implicitSwapchainImpl->display),
7361 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7362 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7363 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7367 for (i = 0; i < nCfgs; ++i) {
7368 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7369 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7370 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7372 if (NULL != This->renderTarget) {
7374 vcheckGLcall("glFlush");
7375 /** This is only useful if the old render target was a swapchain,
7376 * we need to supercede this with a function that displays
7377 * the current buffer on the screen. This is easy to do in glx1.3 but
7378 * we need to do copy-write pixels in glx 1.2.
7379 ************************************************/
7380 glXSwapBuffers(implicitSwapChainImpl->display,
7381 implicitSwapChainImpl->drawable);
7382 printf("Hit Enter to get next frame ...\n");
7393 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7394 * the functionality needs splitting up so that we don't do more than we should do.
7395 * this only seems to impact performance a little.
7396 ******************************/
7397 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7398 IWineD3DSurface *RenderSurface) {
7401 * Currently only active for GLX >= 1.3
7402 * for others versions we'll have to use GLXPixmaps
7404 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7405 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7406 * so only check OpenGL version
7407 * ..........................
7408 * I don't believe that it is a problem with NVidia headers,
7409 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7410 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7412 * Your application will report GLX version 1.2 on glXQueryVersion.
7413 * However, it is safe to call the GLX 1.3 functions as described below.
7415 #if defined(GL_VERSION_1_3)
7417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7418 GLXFBConfig* cfgs = NULL;
7419 IWineD3DSwapChain *currentSwapchain;
7420 IWineD3DSwapChainImpl *currentSwapchainImpl;
7421 IWineD3DSwapChain *implicitSwapchain;
7422 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7423 IWineD3DSwapChain *renderSurfaceSwapchain;
7424 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7426 /* Obtain a reference to the device implicit swapchain,
7427 * the swapchain of the current render target,
7428 * and the swapchain of the new render target.
7429 * Fallback to device implicit swapchain if the current render target doesn't have one */
7430 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7431 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7432 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
7433 if (currentSwapchain == NULL) {
7434 IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
7435 /* GetContainer currently AddRefs, but GetSwapChain doesn't.
7436 * Like this the release code for both is the same. */
7437 IWineD3DDevice_AddRef(currentSwapchain);
7440 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7441 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7442 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7447 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7448 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7449 **********************************************************************/
7450 if (renderSurfaceSwapchain != NULL) {
7452 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7453 /* FIXME: If the render target gets sent to the frontBuffer, should we be presenting it raw? */
7454 TRACE("making swapchain active\n");
7455 if (RenderSurface != This->renderTarget) {
7456 BOOL backbuf = FALSE;
7459 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7460 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7468 /* This could be flagged so that some operations work directly with the front buffer */
7469 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7471 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7472 renderSurfaceSwapchainImpl->win,
7473 renderSurfaceSwapchainImpl->glCtx) == False) {
7475 TRACE("Error in setting current context: context %p drawable %ld !\n",
7476 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7478 checkGLcall("glXMakeContextCurrent");
7480 /* Clean up the old context */
7481 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7483 /* Reapply the stateblock, and set the device not to render to texture */
7484 device_reapply_stateblock(This);
7485 device_render_to_texture(This, FALSE);
7488 /* Offscreen rendering: PBuffers (currently disabled).
7489 * Also note that this path is never reached if FBOs are supported */
7490 } else if (wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER &&
7491 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7493 /** ********************************************************************
7494 * This is a quickly hacked out implementation of offscreen textures.
7495 * It will work in most cases but there may be problems if the client
7496 * modifies the texture directly, or expects the contents of the rendertarget
7499 * There are some real speed vs compatibility issues here:
7500 * we should really use a new context for every texture, but that eats ram.
7501 * we should also be restoring the texture to the pbuffer but that eats CPU
7502 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7503 * but if this means reusing the display backbuffer then we need to make sure that
7504 * states are correctly preserved.
7505 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7506 * and gain a good performance increase at the cost of compatibility.
7507 * I would suggest that, when this is the case, a user configurable flag be made
7508 * available, allowing the user to choose the best emulated experience for them.
7509 *********************************************************************/
7511 XVisualInfo *visinfo;
7512 glContext *newContext;
7514 /* Here were using a shared context model */
7515 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7516 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7519 /* If the context doesn't exist then create a new one */
7520 /* TODO: This should really be part of findGlContext */
7521 if (NULL == newContext->context) {
7526 TRACE("making new buffer\n");
7527 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7528 attribs[nAttribs++] = newContext->Width;
7529 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7530 attribs[nAttribs++] = newContext->Height;
7531 attribs[nAttribs++] = None;
7533 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7535 /** ****************************************
7536 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7538 * In future releases, we may provide the calls glXCreateNewContext,
7539 * glXQueryDrawable and glXMakeContextCurrent.
7540 * so until then we have to use glXGetVisualFromFBConfig &co..
7541 ********************************************/
7543 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7545 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7547 newContext->context = glXCreateContext(
7548 implicitSwapchainImpl->display, visinfo,
7549 implicitSwapchainImpl->glCtx, GL_TRUE);
7554 if (NULL == newContext || NULL == newContext->context) {
7555 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7557 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7558 if (glXMakeCurrent(implicitSwapchainImpl->display,
7559 newContext->drawable, newContext->context) == False) {
7561 TRACE("Error in setting current context: context %p drawable %ld\n",
7562 newContext->context, newContext->drawable);
7564 checkGLcall("glXMakeContextCurrent");
7566 /* Clean up the old context */
7567 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7569 /* Reapply stateblock, and set device to render to a texture */
7570 device_reapply_stateblock(This);
7571 device_render_to_texture(This, TRUE);
7573 /* Set the current context of the swapchain to the new context */
7574 implicitSwapchainImpl->drawable = newContext->drawable;
7575 implicitSwapchainImpl->render_ctx = newContext->context;
7578 /* Same context, but update render_offscreen and cull mode */
7579 device_render_to_texture(This, TRUE);
7582 /* Replace the render target */
7583 if (This->renderTarget != RenderSurface) {
7584 IWineD3DSurface_Release(This->renderTarget);
7585 This->renderTarget = RenderSurface;
7586 IWineD3DSurface_AddRef(RenderSurface);
7589 if (cfgs != NULL) XFree(cfgs);
7590 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7591 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7597 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7598 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7600 /* TODO: the use of Impl is deprecated. */
7601 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7603 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7605 /* some basic validation checks */
7606 if(This->cursorTexture) {
7608 glDeleteTextures(1, &This->cursorTexture);
7610 This->cursorTexture = 0;
7614 /* MSDN: Cursor must be A8R8G8B8 */
7615 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7616 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7617 return WINED3DERR_INVALIDCALL;
7620 /* MSDN: Cursor must be smaller than the display mode */
7621 if(pSur->currentDesc.Width > This->ddraw_width ||
7622 pSur->currentDesc.Height > This->ddraw_height) {
7623 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);
7624 return WINED3DERR_INVALIDCALL;
7627 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7628 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7629 * Texture and Blitting code to draw the cursor
7631 pSur->Flags |= SFLAG_FORCELOAD;
7632 IWineD3DSurface_PreLoad(pCursorBitmap);
7633 pSur->Flags &= ~SFLAG_FORCELOAD;
7634 /* Do not store the surface's pointer because the application may release
7635 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7636 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7638 This->cursorTexture = pSur->glDescription.textureName;
7639 This->cursorWidth = pSur->currentDesc.Width;
7640 This->cursorHeight = pSur->currentDesc.Height;
7641 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7644 This->xHotSpot = XHotSpot;
7645 This->yHotSpot = YHotSpot;
7649 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7651 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7653 This->xScreenSpace = XScreenSpace;
7654 This->yScreenSpace = YScreenSpace;
7660 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7662 BOOL oldVisible = This->bCursorVisible;
7663 TRACE("(%p) : visible(%d)\n", This, bShow);
7665 if(This->cursorTexture)
7666 This->bCursorVisible = bShow;
7671 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7673 TRACE("(%p) : state (%u)\n", This, This->state);
7674 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7675 switch (This->state) {
7678 case WINED3DERR_DEVICELOST:
7680 ResourceList *resourceList = This->resources;
7681 while (NULL != resourceList) {
7682 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7683 return WINED3DERR_DEVICENOTRESET;
7684 resourceList = resourceList->next;
7686 return WINED3DERR_DEVICELOST;
7688 case WINED3DERR_DRIVERINTERNALERROR:
7689 return WINED3DERR_DRIVERINTERNALERROR;
7693 return WINED3DERR_DRIVERINTERNALERROR;
7697 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7699 /** FIXME: Resource tracking needs to be done,
7700 * The closes we can do to this is set the priorities of all managed textures low
7701 * and then reset them.
7702 ***********************************************************/
7703 FIXME("(%p) : stub\n", This);
7707 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7709 /** FIXME: Resource trascking needs to be done.
7710 * in effect this pulls all non only default
7711 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7712 * and should clear down the context and set it up according to pPresentationParameters
7713 ***********************************************************/
7714 FIXME("(%p) : stub\n", This);
7718 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7720 /** FIXME: always true at the moment **/
7721 if(!bEnableDialogs) {
7722 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7728 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7730 TRACE("(%p) : pParameters %p\n", This, pParameters);
7732 *pParameters = This->createParms;
7736 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7737 IWineD3DSwapChain *swapchain;
7738 HRESULT hrc = WINED3D_OK;
7740 TRACE("Relaying to swapchain\n");
7742 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7743 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7748 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7749 IWineD3DSwapChain *swapchain;
7750 HRESULT hrc = WINED3D_OK;
7752 TRACE("Relaying to swapchain\n");
7754 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7755 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7761 /** ********************************************************
7762 * Notification functions
7763 ** ********************************************************/
7764 /** This function must be called in the release of a resource when ref == 0,
7765 * the contents of resource must still be correct,
7766 * any handels to other resource held by the caller must be closed
7767 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7768 *****************************************************/
7769 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7771 ResourceList* resourceList;
7773 TRACE("(%p) : resource %p\n", This, resource);
7775 EnterCriticalSection(&resourceStoreCriticalSection);
7777 /* add a new texture to the frot of the linked list */
7778 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7779 resourceList->resource = resource;
7781 /* Get the old head */
7782 resourceList->next = This->resources;
7784 This->resources = resourceList;
7785 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7788 LeaveCriticalSection(&resourceStoreCriticalSection);
7793 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7795 ResourceList* resourceList = NULL;
7796 ResourceList* previousResourceList = NULL;
7798 TRACE("(%p) : resource %p\n", This, resource);
7801 EnterCriticalSection(&resourceStoreCriticalSection);
7803 resourceList = This->resources;
7805 while (resourceList != NULL) {
7806 if(resourceList->resource == resource) break;
7807 previousResourceList = resourceList;
7808 resourceList = resourceList->next;
7811 if (resourceList == NULL) {
7812 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7814 LeaveCriticalSection(&resourceStoreCriticalSection);
7818 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7820 /* make sure we don't leave a hole in the list */
7821 if (previousResourceList != NULL) {
7822 previousResourceList->next = resourceList->next;
7824 This->resources = resourceList->next;
7828 LeaveCriticalSection(&resourceStoreCriticalSection);
7834 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7838 TRACE("(%p) : resource %p\n", This, resource);
7839 switch(IWineD3DResource_GetType(resource)){
7840 case WINED3DRTYPE_SURFACE:
7841 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7843 case WINED3DRTYPE_TEXTURE:
7844 case WINED3DRTYPE_CUBETEXTURE:
7845 case WINED3DRTYPE_VOLUMETEXTURE:
7846 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7847 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7848 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7849 This->stateBlock->textures[counter] = NULL;
7851 if (This->updateStateBlock != This->stateBlock ){
7852 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7853 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7854 This->updateStateBlock->textures[counter] = NULL;
7859 case WINED3DRTYPE_VOLUME:
7860 /* TODO: nothing really? */
7862 case WINED3DRTYPE_VERTEXBUFFER:
7863 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7866 TRACE("Cleaning up stream pointers\n");
7868 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7869 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7870 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7872 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7873 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7874 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7875 This->updateStateBlock->streamSource[streamNumber] = 0;
7876 /* Set changed flag? */
7879 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) */
7880 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7881 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7882 This->stateBlock->streamSource[streamNumber] = 0;
7885 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7886 else { /* This shouldn't happen */
7887 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7894 case WINED3DRTYPE_INDEXBUFFER:
7895 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7896 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7897 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7898 This->updateStateBlock->pIndexData = NULL;
7901 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7902 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7903 This->stateBlock->pIndexData = NULL;
7909 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7914 /* Remove the resoruce from the resourceStore */
7915 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7917 TRACE("Resource released\n");
7921 /**********************************************************
7922 * IWineD3DDevice VTbl follows
7923 **********************************************************/
7925 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7927 /*** IUnknown methods ***/
7928 IWineD3DDeviceImpl_QueryInterface,
7929 IWineD3DDeviceImpl_AddRef,
7930 IWineD3DDeviceImpl_Release,
7931 /*** IWineD3DDevice methods ***/
7932 IWineD3DDeviceImpl_GetParent,
7933 /*** Creation methods**/
7934 IWineD3DDeviceImpl_CreateVertexBuffer,
7935 IWineD3DDeviceImpl_CreateIndexBuffer,
7936 IWineD3DDeviceImpl_CreateStateBlock,
7937 IWineD3DDeviceImpl_CreateSurface,
7938 IWineD3DDeviceImpl_CreateTexture,
7939 IWineD3DDeviceImpl_CreateVolumeTexture,
7940 IWineD3DDeviceImpl_CreateVolume,
7941 IWineD3DDeviceImpl_CreateCubeTexture,
7942 IWineD3DDeviceImpl_CreateQuery,
7943 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7944 IWineD3DDeviceImpl_CreateVertexDeclaration,
7945 IWineD3DDeviceImpl_CreateVertexShader,
7946 IWineD3DDeviceImpl_CreatePixelShader,
7947 IWineD3DDeviceImpl_CreatePalette,
7948 /*** Odd functions **/
7949 IWineD3DDeviceImpl_Init3D,
7950 IWineD3DDeviceImpl_Uninit3D,
7951 IWineD3DDeviceImpl_SetFullscreen,
7952 IWineD3DDeviceImpl_EnumDisplayModes,
7953 IWineD3DDeviceImpl_EvictManagedResources,
7954 IWineD3DDeviceImpl_GetAvailableTextureMem,
7955 IWineD3DDeviceImpl_GetBackBuffer,
7956 IWineD3DDeviceImpl_GetCreationParameters,
7957 IWineD3DDeviceImpl_GetDeviceCaps,
7958 IWineD3DDeviceImpl_GetDirect3D,
7959 IWineD3DDeviceImpl_GetDisplayMode,
7960 IWineD3DDeviceImpl_SetDisplayMode,
7961 IWineD3DDeviceImpl_GetHWND,
7962 IWineD3DDeviceImpl_SetHWND,
7963 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7964 IWineD3DDeviceImpl_GetRasterStatus,
7965 IWineD3DDeviceImpl_GetSwapChain,
7966 IWineD3DDeviceImpl_Reset,
7967 IWineD3DDeviceImpl_SetDialogBoxMode,
7968 IWineD3DDeviceImpl_SetCursorProperties,
7969 IWineD3DDeviceImpl_SetCursorPosition,
7970 IWineD3DDeviceImpl_ShowCursor,
7971 IWineD3DDeviceImpl_TestCooperativeLevel,
7972 /*** Getters and setters **/
7973 IWineD3DDeviceImpl_SetClipPlane,
7974 IWineD3DDeviceImpl_GetClipPlane,
7975 IWineD3DDeviceImpl_SetClipStatus,
7976 IWineD3DDeviceImpl_GetClipStatus,
7977 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7978 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7979 IWineD3DDeviceImpl_SetDepthStencilSurface,
7980 IWineD3DDeviceImpl_GetDepthStencilSurface,
7981 IWineD3DDeviceImpl_SetFVF,
7982 IWineD3DDeviceImpl_GetFVF,
7983 IWineD3DDeviceImpl_SetGammaRamp,
7984 IWineD3DDeviceImpl_GetGammaRamp,
7985 IWineD3DDeviceImpl_SetIndices,
7986 IWineD3DDeviceImpl_GetIndices,
7987 IWineD3DDeviceImpl_SetLight,
7988 IWineD3DDeviceImpl_GetLight,
7989 IWineD3DDeviceImpl_SetLightEnable,
7990 IWineD3DDeviceImpl_GetLightEnable,
7991 IWineD3DDeviceImpl_SetMaterial,
7992 IWineD3DDeviceImpl_GetMaterial,
7993 IWineD3DDeviceImpl_SetNPatchMode,
7994 IWineD3DDeviceImpl_GetNPatchMode,
7995 IWineD3DDeviceImpl_SetPaletteEntries,
7996 IWineD3DDeviceImpl_GetPaletteEntries,
7997 IWineD3DDeviceImpl_SetPixelShader,
7998 IWineD3DDeviceImpl_GetPixelShader,
7999 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8000 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8001 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8002 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8003 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8004 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8005 IWineD3DDeviceImpl_SetRenderState,
8006 IWineD3DDeviceImpl_GetRenderState,
8007 IWineD3DDeviceImpl_SetRenderTarget,
8008 IWineD3DDeviceImpl_GetRenderTarget,
8009 IWineD3DDeviceImpl_SetFrontBackBuffers,
8010 IWineD3DDeviceImpl_SetSamplerState,
8011 IWineD3DDeviceImpl_GetSamplerState,
8012 IWineD3DDeviceImpl_SetScissorRect,
8013 IWineD3DDeviceImpl_GetScissorRect,
8014 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8015 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8016 IWineD3DDeviceImpl_SetStreamSource,
8017 IWineD3DDeviceImpl_GetStreamSource,
8018 IWineD3DDeviceImpl_SetStreamSourceFreq,
8019 IWineD3DDeviceImpl_GetStreamSourceFreq,
8020 IWineD3DDeviceImpl_SetTexture,
8021 IWineD3DDeviceImpl_GetTexture,
8022 IWineD3DDeviceImpl_SetTextureStageState,
8023 IWineD3DDeviceImpl_GetTextureStageState,
8024 IWineD3DDeviceImpl_SetTransform,
8025 IWineD3DDeviceImpl_GetTransform,
8026 IWineD3DDeviceImpl_SetVertexDeclaration,
8027 IWineD3DDeviceImpl_GetVertexDeclaration,
8028 IWineD3DDeviceImpl_SetVertexShader,
8029 IWineD3DDeviceImpl_GetVertexShader,
8030 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8031 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8032 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8033 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8034 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8035 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8036 IWineD3DDeviceImpl_SetViewport,
8037 IWineD3DDeviceImpl_GetViewport,
8038 IWineD3DDeviceImpl_MultiplyTransform,
8039 IWineD3DDeviceImpl_ValidateDevice,
8040 IWineD3DDeviceImpl_ProcessVertices,
8041 /*** State block ***/
8042 IWineD3DDeviceImpl_BeginStateBlock,
8043 IWineD3DDeviceImpl_EndStateBlock,
8044 /*** Scene management ***/
8045 IWineD3DDeviceImpl_BeginScene,
8046 IWineD3DDeviceImpl_EndScene,
8047 IWineD3DDeviceImpl_Present,
8048 IWineD3DDeviceImpl_Clear,
8050 IWineD3DDeviceImpl_DrawPrimitive,
8051 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8052 IWineD3DDeviceImpl_DrawPrimitiveUP,
8053 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8054 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8055 IWineD3DDeviceImpl_DrawRectPatch,
8056 IWineD3DDeviceImpl_DrawTriPatch,
8057 IWineD3DDeviceImpl_DeletePatch,
8058 IWineD3DDeviceImpl_ColorFill,
8059 IWineD3DDeviceImpl_UpdateTexture,
8060 IWineD3DDeviceImpl_UpdateSurface,
8061 IWineD3DDeviceImpl_StretchRect,
8062 IWineD3DDeviceImpl_GetRenderTargetData,
8063 IWineD3DDeviceImpl_GetFrontBufferData,
8064 /*** Internal use IWineD3DDevice methods ***/
8065 IWineD3DDeviceImpl_SetupTextureStates,
8066 /*** object tracking ***/
8067 IWineD3DDeviceImpl_ResourceReleased
8071 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8072 WINED3DRS_ALPHABLENDENABLE ,
8073 WINED3DRS_ALPHAFUNC ,
8074 WINED3DRS_ALPHAREF ,
8075 WINED3DRS_ALPHATESTENABLE ,
8077 WINED3DRS_COLORWRITEENABLE ,
8078 WINED3DRS_DESTBLEND ,
8079 WINED3DRS_DITHERENABLE ,
8080 WINED3DRS_FILLMODE ,
8081 WINED3DRS_FOGDENSITY ,
8083 WINED3DRS_FOGSTART ,
8084 WINED3DRS_LASTPIXEL ,
8085 WINED3DRS_SHADEMODE ,
8086 WINED3DRS_SRCBLEND ,
8087 WINED3DRS_STENCILENABLE ,
8088 WINED3DRS_STENCILFAIL ,
8089 WINED3DRS_STENCILFUNC ,
8090 WINED3DRS_STENCILMASK ,
8091 WINED3DRS_STENCILPASS ,
8092 WINED3DRS_STENCILREF ,
8093 WINED3DRS_STENCILWRITEMASK ,
8094 WINED3DRS_STENCILZFAIL ,
8095 WINED3DRS_TEXTUREFACTOR ,
8106 WINED3DRS_ZWRITEENABLE
8109 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8110 WINED3DTSS_ADDRESSW ,
8111 WINED3DTSS_ALPHAARG0 ,
8112 WINED3DTSS_ALPHAARG1 ,
8113 WINED3DTSS_ALPHAARG2 ,
8114 WINED3DTSS_ALPHAOP ,
8115 WINED3DTSS_BUMPENVLOFFSET ,
8116 WINED3DTSS_BUMPENVLSCALE ,
8117 WINED3DTSS_BUMPENVMAT00 ,
8118 WINED3DTSS_BUMPENVMAT01 ,
8119 WINED3DTSS_BUMPENVMAT10 ,
8120 WINED3DTSS_BUMPENVMAT11 ,
8121 WINED3DTSS_COLORARG0 ,
8122 WINED3DTSS_COLORARG1 ,
8123 WINED3DTSS_COLORARG2 ,
8124 WINED3DTSS_COLOROP ,
8125 WINED3DTSS_RESULTARG ,
8126 WINED3DTSS_TEXCOORDINDEX ,
8127 WINED3DTSS_TEXTURETRANSFORMFLAGS
8130 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8131 WINED3DSAMP_ADDRESSU ,
8132 WINED3DSAMP_ADDRESSV ,
8133 WINED3DSAMP_ADDRESSW ,
8134 WINED3DSAMP_BORDERCOLOR ,
8135 WINED3DSAMP_MAGFILTER ,
8136 WINED3DSAMP_MINFILTER ,
8137 WINED3DSAMP_MIPFILTER ,
8138 WINED3DSAMP_MIPMAPLODBIAS ,
8139 WINED3DSAMP_MAXMIPLEVEL ,
8140 WINED3DSAMP_MAXANISOTROPY ,
8141 WINED3DSAMP_SRGBTEXTURE ,
8142 WINED3DSAMP_ELEMENTINDEX
8145 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8147 WINED3DRS_AMBIENTMATERIALSOURCE ,
8148 WINED3DRS_CLIPPING ,
8149 WINED3DRS_CLIPPLANEENABLE ,
8150 WINED3DRS_COLORVERTEX ,
8151 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8152 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8153 WINED3DRS_FOGDENSITY ,
8155 WINED3DRS_FOGSTART ,
8156 WINED3DRS_FOGTABLEMODE ,
8157 WINED3DRS_FOGVERTEXMODE ,
8158 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8159 WINED3DRS_LIGHTING ,
8160 WINED3DRS_LOCALVIEWER ,
8161 WINED3DRS_MULTISAMPLEANTIALIAS ,
8162 WINED3DRS_MULTISAMPLEMASK ,
8163 WINED3DRS_NORMALIZENORMALS ,
8164 WINED3DRS_PATCHEDGESTYLE ,
8165 WINED3DRS_POINTSCALE_A ,
8166 WINED3DRS_POINTSCALE_B ,
8167 WINED3DRS_POINTSCALE_C ,
8168 WINED3DRS_POINTSCALEENABLE ,
8169 WINED3DRS_POINTSIZE ,
8170 WINED3DRS_POINTSIZE_MAX ,
8171 WINED3DRS_POINTSIZE_MIN ,
8172 WINED3DRS_POINTSPRITEENABLE ,
8173 WINED3DRS_RANGEFOGENABLE ,
8174 WINED3DRS_SPECULARMATERIALSOURCE ,
8175 WINED3DRS_TWEENFACTOR ,
8176 WINED3DRS_VERTEXBLEND
8179 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8180 WINED3DTSS_TEXCOORDINDEX ,
8181 WINED3DTSS_TEXTURETRANSFORMFLAGS
8184 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8185 WINED3DSAMP_DMAPOFFSET