wined3d: Comparing BOOLs against FALSE is redundant.
[wine.git] / dlls / wined3d / device.c
blob9ac13aa7c21c6d481025a99fee638f42f90c1a01
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 D3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* TODO: setup some flags in the regestry to enable, disable pbuffer support */
75 /* enable pbuffer support for offscreen textures */
76 BOOL pbuffer_support = FALSE;
77 /* allocate one pbuffer per surface */
78 BOOL pbuffer_per_surface = FALSE;
80 /* static function declarations */
81 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
83 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type);
85 /* helper macros */
86 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
88 #define D3DCREATEOBJECTINSTANCE(object, type) { \
89 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
90 D3DMEMCHECK(object, pp##type); \
91 object->lpVtbl = &IWineD3D##type##_Vtbl; \
92 object->wineD3DDevice = This; \
93 object->parent = parent; \
94 object->ref = 1; \
95 *pp##type = (IWineD3D##type *) object; \
98 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
99 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
100 D3DMEMCHECK(object, pp##type); \
101 object->lpVtbl = &IWineD3D##type##_Vtbl; \
102 object->resource.wineD3DDevice = This; \
103 object->resource.parent = parent; \
104 object->resource.resourceType = d3dtype; \
105 object->resource.ref = 1; \
106 object->resource.pool = Pool; \
107 object->resource.format = Format; \
108 object->resource.usage = Usage; \
109 object->resource.size = _size; \
110 /* Check that we have enough video ram left */ \
111 if (Pool == WINED3DPOOL_DEFAULT) { \
112 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
113 WARN("Out of 'bogus' video memory\n"); \
114 HeapFree(GetProcessHeap(), 0, object); \
115 *pp##type = NULL; \
116 return WINED3DERR_OUTOFVIDEOMEMORY; \
118 globalChangeGlRam(_size); \
120 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
121 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
122 FIXME("Out of memory!\n"); \
123 HeapFree(GetProcessHeap(), 0, object); \
124 *pp##type = NULL; \
125 return WINED3DERR_OUTOFVIDEOMEMORY; \
127 *pp##type = (IWineD3D##type *) object; \
128 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
129 TRACE("(%p) : Created resource %p\n", This, object); \
132 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
133 _basetexture.levels = Levels; \
134 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
135 _basetexture.LOD = 0; \
136 _basetexture.dirty = TRUE; \
139 /**********************************************************
140 * Global variable / Constants follow
141 **********************************************************/
142 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
144 /**********************************************************
145 * Utility functions follow
146 **********************************************************/
147 /* Convert the D3DLIGHT properties into equivalent gl lights */
148 static void setup_light(IWineD3DDevice *iface, LONG Index, PLIGHTINFOEL *lightInfo) {
150 float quad_att;
151 float colRGBA[] = {0.0, 0.0, 0.0, 0.0};
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/
155 glMatrixMode(GL_MODELVIEW);
156 glPushMatrix();
157 glLoadMatrixf((float *)&This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
159 /* Diffuse: */
160 colRGBA[0] = lightInfo->OriginalParms.Diffuse.r;
161 colRGBA[1] = lightInfo->OriginalParms.Diffuse.g;
162 colRGBA[2] = lightInfo->OriginalParms.Diffuse.b;
163 colRGBA[3] = lightInfo->OriginalParms.Diffuse.a;
164 glLightfv(GL_LIGHT0+Index, GL_DIFFUSE, colRGBA);
165 checkGLcall("glLightfv");
167 /* Specular */
168 colRGBA[0] = lightInfo->OriginalParms.Specular.r;
169 colRGBA[1] = lightInfo->OriginalParms.Specular.g;
170 colRGBA[2] = lightInfo->OriginalParms.Specular.b;
171 colRGBA[3] = lightInfo->OriginalParms.Specular.a;
172 glLightfv(GL_LIGHT0+Index, GL_SPECULAR, colRGBA);
173 checkGLcall("glLightfv");
175 /* Ambient */
176 colRGBA[0] = lightInfo->OriginalParms.Ambient.r;
177 colRGBA[1] = lightInfo->OriginalParms.Ambient.g;
178 colRGBA[2] = lightInfo->OriginalParms.Ambient.b;
179 colRGBA[3] = lightInfo->OriginalParms.Ambient.a;
180 glLightfv(GL_LIGHT0+Index, GL_AMBIENT, colRGBA);
181 checkGLcall("glLightfv");
183 /* Attenuation - Are these right? guessing... */
184 glLightf(GL_LIGHT0+Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0);
185 checkGLcall("glLightf");
186 glLightf(GL_LIGHT0+Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1);
187 checkGLcall("glLightf");
189 if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
190 quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
191 } else {
192 quad_att = 0; /* 0 or MAX? (0 seems to be ok) */
195 if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
196 glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att);
197 checkGLcall("glLightf");
199 switch (lightInfo->OriginalParms.Type) {
200 case D3DLIGHT_POINT:
201 /* Position */
202 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
203 checkGLcall("glLightfv");
204 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
205 checkGLcall("glLightf");
206 /* FIXME: Range */
207 break;
209 case D3DLIGHT_SPOT:
210 /* Position */
211 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]);
212 checkGLcall("glLightfv");
213 /* Direction */
214 glLightfv(GL_LIGHT0+Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]);
215 checkGLcall("glLightfv");
216 glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent);
217 checkGLcall("glLightf");
218 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
219 checkGLcall("glLightf");
220 /* FIXME: Range */
221 break;
223 case D3DLIGHT_DIRECTIONAL:
224 /* Direction */
225 glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */
226 checkGLcall("glLightfv");
227 glLightf(GL_LIGHT0+Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
228 checkGLcall("glLightf");
229 glLightf(GL_LIGHT0+Index, GL_SPOT_EXPONENT, 0.0f);
230 checkGLcall("glLightf");
231 break;
233 default:
234 FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type);
237 /* Restore the modelview matrix */
238 glPopMatrix();
241 /**********************************************************
242 * GLSL helper functions follow
243 **********************************************************/
245 /** Attach a GLSL pixel or vertex shader object to the shader program */
246 static void attach_glsl_shader(IWineD3DDevice *iface, IWineD3DBaseShader* shader) {
248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
249 GLhandleARB shaderObj = ((IWineD3DBaseShaderImpl*)shader)->baseShader.prgId;
250 if (This->stateBlock->glsl_program && shaderObj != 0) {
251 TRACE_(d3d_shader)("Attaching GLSL shader object %u to program %u\n", shaderObj, This->stateBlock->glsl_program->programId);
252 GL_EXTCALL(glAttachObjectARB(This->stateBlock->glsl_program->programId, shaderObj));
253 checkGLcall("glAttachObjectARB");
257 /** Sets the GLSL program ID for the given pixel and vertex shader combination.
258 * It sets the programId on the current StateBlock (because it should be called
259 * inside of the DrawPrimitive() part of the render loop).
261 * If a program for the given combination does not exist, create one, and store
262 * the program in the list. If it creates a program, it will link the given
263 * objects, too.
265 * We keep the shader programs around on a list because linking
266 * shader objects together is an expensive operation. It's much
267 * faster to loop through a list of pre-compiled & linked programs
268 * each time that the application sets a new pixel or vertex shader
269 * than it is to re-link them together at that time.
271 * The list will be deleted in IWineD3DDevice::Release().
273 void set_glsl_shader_program(IWineD3DDevice *iface) {
275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
276 IWineD3DPixelShader *pshader = This->stateBlock->pixelShader;
277 IWineD3DVertexShader *vshader = This->stateBlock->vertexShader;
278 struct glsl_shader_prog_link *curLink = NULL;
279 struct glsl_shader_prog_link *newLink = NULL;
280 struct list *ptr = NULL;
281 GLhandleARB programId = 0;
282 int i;
283 char glsl_name[8];
285 ptr = list_head( &This->glsl_shader_progs );
286 while (ptr) {
287 /* At least one program exists - see if it matches our ps/vs combination */
288 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
289 if (vshader == curLink->vertexShader && pshader == curLink->pixelShader) {
290 /* Existing Program found, use it */
291 TRACE_(d3d_shader)("Found existing program (%u) for this vertex/pixel shader combination\n",
292 curLink->programId);
293 This->stateBlock->glsl_program = curLink;
294 return;
296 /* This isn't the entry we need - try the next one */
297 ptr = list_next( &This->glsl_shader_progs, ptr );
300 /* If we get to this point, then no matching program exists, so we create one */
301 programId = GL_EXTCALL(glCreateProgramObjectARB());
302 TRACE_(d3d_shader)("Created new GLSL shader program %u\n", programId);
304 /* Allocate a new link for the list of programs */
305 newLink = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link));
306 newLink->programId = programId;
307 This->stateBlock->glsl_program = newLink;
309 /* Attach GLSL vshader */
310 if (NULL != vshader && wined3d_settings.vs_selected_mode == SHADER_GLSL) {
311 int i;
312 int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */
313 char tmp_name[10];
315 TRACE("Attaching vertex shader to GLSL program\n");
316 attach_glsl_shader(iface, (IWineD3DBaseShader*)vshader);
318 /* Bind vertex attributes to a corresponding index number to match
319 * the same index numbers as ARB_vertex_programs (makes loading
320 * vertex attributes simpler). With this method, we can use the
321 * exact same code to load the attributes later for both ARB and
322 * GLSL shaders.
324 * We have to do this here because we need to know the Program ID
325 * in order to make the bindings work, and it has to be done prior
326 * to linking the GLSL program. */
327 for (i = 0; i < max_attribs; ++i) {
328 snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i);
329 GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name));
331 checkGLcall("glBindAttribLocationARB");
332 newLink->vertexShader = vshader;
335 /* Attach GLSL pshader */
336 if (NULL != pshader && wined3d_settings.ps_selected_mode == SHADER_GLSL) {
337 TRACE("Attaching pixel shader to GLSL program\n");
338 attach_glsl_shader(iface, (IWineD3DBaseShader*)pshader);
339 newLink->pixelShader = pshader;
342 /* Link the program */
343 TRACE_(d3d_shader)("Linking GLSL shader program %u\n", programId);
344 GL_EXTCALL(glLinkProgramARB(programId));
345 print_glsl_info_log(&GLINFO_LOCATION, programId);
346 list_add_head( &This->glsl_shader_progs, &newLink->entry);
348 newLink->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF));
349 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
350 snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i);
351 newLink->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
353 newLink->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF));
354 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
355 snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i);
356 newLink->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name));
359 return;
362 /** Detach the GLSL pixel or vertex shader object from the shader program */
363 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
367 if (shaderObj != 0 && programId != 0) {
368 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
369 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
370 checkGLcall("glDetachObjectARB");
374 /** Delete a GLSL shader program */
375 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379 if (obj != 0) {
380 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
381 GL_EXTCALL(glDeleteObjectARB(obj));
382 checkGLcall("glDeleteObjectARB");
386 /** Delete the list of linked programs this shader is associated with.
387 * Also at this point, check to see if there are any objects left attached
388 * to each GLSL program. If not, delete the GLSL program object.
389 * This will be run when a device is released. */
390 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
392 struct list *ptr = NULL;
393 struct glsl_shader_prog_link *curLink = NULL;
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
396 int numAttached = 0;
397 int i;
398 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
399 (one pixel shader and one vertex shader at most) */
401 ptr = list_head( &This->glsl_shader_progs );
402 while (ptr) {
403 /* First, get the current item,
404 * save the link to the next pointer,
405 * detach and delete shader objects,
406 * then de-allocate the list item's memory */
407 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
408 ptr = list_next( &This->glsl_shader_progs, ptr );
410 /* See if this object is still attached to the program - it may have been detached already */
411 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
412 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
413 for (i = 0; i < numAttached; i++) {
414 detach_glsl_shader(iface, objList[i], curLink->programId);
417 delete_glsl_shader_program(iface, curLink->programId);
419 /* Free the uniform locations */
420 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
421 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
423 /* Free the memory for this list item */
424 HeapFree(GetProcessHeap(), 0, curLink);
429 /* Apply the current values to the specified texture stage */
430 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 float col[4];
434 union {
435 float f;
436 DWORD d;
437 } tmpvalue;
439 /* In addition, IDirect3DDevice9::SetSamplerState will now be used for filtering, tiling,
440 clamping, MIPLOD, etc. This will work for up to 16 samplers.
443 if (Sampler >= GL_LIMITS(sampler_stages)) {
444 FIXME("Trying to set the state of more samplers %ld than are supported %d by this openGL implementation\n", Sampler, GL_LIMITS(sampler_stages));
445 return;
447 VTRACE(("Activating appropriate texture state %ld\n", Sampler));
448 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
449 ENTER_GL();
450 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
451 checkGLcall("glActiveTextureARB");
452 LEAVE_GL();
453 /* Could we use bindTexture and then apply the states instead of GLACTIVETEXTURE */
454 } else if (Sampler > 0) {
455 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
456 return;
459 /* TODO: change this to a lookup table
460 LOOKUP_TEXTURE_STATES lists all texture states that should be applied.
461 LOOKUP_CONTEXT_SATES list all context applicable states that can be applied
462 etc.... it's a lot cleaner, quicker and possibly easier to maintain than running a switch and setting a skip flag...
463 especially when there are a number of groups of states. */
465 TRACE("-----------------------> Updating the texture at Sampler %ld to have new texture state information\n", Sampler);
467 /* 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 */
468 #define APPLY_STATE(_state) IWineD3DDeviceImpl_ApplyTextureUnitState(iface, Sampler, _state)
469 /* these are the only two supported states that need to be applied */
470 APPLY_STATE(WINED3DTSS_TEXCOORDINDEX);
471 APPLY_STATE(WINED3DTSS_TEXTURETRANSFORMFLAGS);
472 #if 0 /* not supported at the moment */
473 APPLY_STATE(WINED3DTSS_BUMPENVMAT00);
474 APPLY_STATE(WINED3DTSS_BUMPENVMAT01);
475 APPLY_STATE(WINED3DTSS_BUMPENVMAT10);
476 APPLY_STATE(WINED3DTSS_BUMPENVMAT11);
477 APPLY_STATE(WINED3DTSS_BUMPENVLSCALE);
478 APPLY_STATE(WINED3DTSS_BUMPENVLOFFSET);
479 APPLY_STATE(WINED3DTSS_RESULTARG);
480 APPLY_STATE(WINED3DTSS_CONSTANT);
481 #endif
482 /* a quick sanity check in case someone forgot to update this function */
483 if (WINED3D_HIGHEST_TEXTURE_STATE > WINED3DTSS_CONSTANT) {
484 FIXME("(%p) : There are more texture states than expected, update device.c to match\n", This);
486 #undef APPLY_STATE
488 /* apply any sampler states that always need applying */
489 if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) {
490 tmpvalue.d = This->stateBlock->samplerState[Sampler][WINED3DSAMP_MIPMAPLODBIAS];
491 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
492 GL_TEXTURE_LOD_BIAS_EXT,
493 tmpvalue.f);
494 checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ...");
497 D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], col);
498 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
499 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
501 /* TODO: NV_POINT_SPRITE */
502 if (GL_SUPPORT(ARB_POINT_SPRITE)) {
503 if (This->stateBlock->renderState[WINED3DRS_POINTSPRITEENABLE]) {
504 /* Doesn't work with GL_POINT_SMOOTH on on my ATI 9600, but then ATI drivers are buggered! */
505 glDisable(GL_POINT_SMOOTH);
507 /* Centre the texture on the vertex */
508 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
509 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
511 VTRACE(("glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"));
512 glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
513 checkGLcall("glTexEnvf(...)");
514 VTRACE(("glEnable( GL_POINT_SPRITE_ARB )\n"));
515 glEnable( GL_POINT_SPRITE_ARB );
516 checkGLcall("glEnable(...)");
517 } else {
518 VTRACE(("glDisable( GL_POINT_SPRITE_ARB )\n"));
519 glDisable( GL_POINT_SPRITE_ARB );
520 checkGLcall("glEnable(...)");
524 TRACE("-----------------------> Updated the texture at Sampler %ld to have new texture state information\n", Sampler);
527 /**********************************************************
528 * IUnknown parts follows
529 **********************************************************/
531 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
535 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
536 if (IsEqualGUID(riid, &IID_IUnknown)
537 || IsEqualGUID(riid, &IID_IWineD3DBase)
538 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
539 IUnknown_AddRef(iface);
540 *ppobj = This;
541 return S_OK;
543 *ppobj = NULL;
544 return E_NOINTERFACE;
547 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
549 ULONG refCount = InterlockedIncrement(&This->ref);
551 TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
552 return refCount;
555 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 ULONG refCount = InterlockedDecrement(&This->ref);
559 TRACE("(%p) : Releasing from %ld\n", This, refCount + 1);
561 if (!refCount) {
562 /* TODO: Clean up all the surfaces and textures! */
563 /* NOTE: You must release the parent if the object was created via a callback
564 ** ***************************/
566 /* Delete any GLSL shader programs that may exist */
567 if (wined3d_settings.vs_selected_mode == SHADER_GLSL ||
568 wined3d_settings.ps_selected_mode == SHADER_GLSL)
569 delete_glsl_shader_list(iface);
571 /* Release the update stateblock */
572 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
573 if(This->updateStateBlock != This->stateBlock)
574 FIXME("(%p) Something's still holding the Update stateblock\n",This);
576 This->updateStateBlock = NULL;
577 { /* because were not doing proper internal refcounts releasing the primary state block
578 causes recursion with the extra checks in ResourceReleased, to avoid this we have
579 to set this->stateBlock = NULL; first */
580 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
581 This->stateBlock = NULL;
583 /* Release the stateblock */
584 if(IWineD3DStateBlock_Release(stateBlock) > 0){
585 FIXME("(%p) Something's still holding the Update stateblock\n",This);
589 if (This->resources != NULL ) {
590 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
591 dumpResources(This->resources);
595 IWineD3D_Release(This->wineD3D);
596 This->wineD3D = NULL;
597 HeapFree(GetProcessHeap(), 0, This);
598 TRACE("Freed device %p\n", This);
599 This = NULL;
601 return refCount;
604 /**********************************************************
605 * IWineD3DDevice implementation follows
606 **********************************************************/
607 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
609 *pParent = This->parent;
610 IUnknown_AddRef(This->parent);
611 return WINED3D_OK;
614 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
615 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
616 GLenum error, glUsage;
617 DWORD vboUsage = object->resource.usage;
618 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
619 WARN("Creating a vbo failed once, not trying again\n");
620 return;
623 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
625 ENTER_GL();
626 /* Make sure that the gl error is cleared. Do not use checkGLcall
627 * here because checkGLcall just prints a fixme and continues. However,
628 * if an error during VBO creation occurs we can fall back to non-vbo operation
629 * with full functionality(but performance loss)
631 while(glGetError() != GL_NO_ERROR);
633 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
634 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
635 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
636 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
637 * to check if the rhw and color values are in the correct format.
640 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
641 error = glGetError();
642 if(object->vbo == 0 || error != GL_NO_ERROR) {
643 WARN("Failed to create a VBO with error %d\n", error);
644 goto error;
647 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
648 error = glGetError();
649 if(error != GL_NO_ERROR) {
650 WARN("Failed to bind the VBO, error %d\n", error);
651 goto error;
654 /* Transformed vertices are horribly inflexible. If the app specifies an
655 * vertex buffer with transformed vertices in default pool without DYNAMIC
656 * usage assume DYNAMIC usage and print a warning. The app will have to update
657 * the vertices regularily for them to be useful
659 if(((object->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) &&
660 !(vboUsage & WINED3DUSAGE_DYNAMIC)) {
661 WARN("Application creates a vertex buffer holding transformed vertices which doesn't specify dynamic usage\n");
662 vboUsage |= WINED3DUSAGE_DYNAMIC;
665 /* Don't use static, because dx apps tend to update the buffer
666 * quite often even if they specify 0 usage
668 switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
669 case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
670 TRACE("Gl usage = GL_STREAM_DRAW\n");
671 glUsage = GL_STREAM_DRAW_ARB;
672 break;
673 case D3DUSAGE_WRITEONLY:
674 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
675 glUsage = GL_DYNAMIC_DRAW_ARB;
676 break;
677 case D3DUSAGE_DYNAMIC:
678 TRACE("Gl usage = GL_STREAM_COPY\n");
679 glUsage = GL_STREAM_COPY_ARB;
680 break;
681 default:
682 TRACE("Gl usage = GL_DYNAMIC_COPY\n");
683 glUsage = GL_DYNAMIC_COPY_ARB;
684 break;
687 /* Reserve memory for the buffer. The amount of data won't change
688 * so we are safe with calling glBufferData once with a NULL ptr and
689 * calling glBufferSubData on updates
691 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
692 error = glGetError();
693 if(error != GL_NO_ERROR) {
694 WARN("glBufferDataARB failed with error %d\n", error);
695 goto error;
698 LEAVE_GL();
700 return;
701 error:
702 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
703 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
704 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
705 object->vbo = 0;
706 object->Flags |= VBFLAG_VBOCREATEFAIL;
707 LEAVE_GL();
708 return;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
712 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
713 IUnknown *parent) {
714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
715 IWineD3DVertexBufferImpl *object;
716 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
717 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
718 BOOL conv;
719 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
721 TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
722 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
724 if(Size == 0) return WINED3DERR_INVALIDCALL;
726 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
727 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
729 object->fvf = FVF;
731 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
732 * drawStridedFast (half-life 2).
734 * Basically converting the vertices in the buffer is quite expensive, and observations
735 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
736 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
738 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
739 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
740 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
741 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
742 * dx7 apps.
743 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
744 * more. In this call we can convert dx7 buffers too.
746 conv = ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) || (FVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
747 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
748 (dxVersion > 7 || !conv) ) {
749 CreateVBO(object);
751 /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
752 if(dxVersion == 7 && object->vbo) {
753 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
754 object->resource.allocatedMemory = NULL;
758 return WINED3D_OK;
761 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
762 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
763 HANDLE *sharedHandle, IUnknown *parent) {
764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
765 IWineD3DIndexBufferImpl *object;
766 TRACE("(%p) Creating index buffer\n", This);
768 /* Allocate the storage for the device */
769 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
771 /*TODO: use VBO's */
772 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
773 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
776 TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
777 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
778 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
780 return WINED3D_OK;
783 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
786 IWineD3DStateBlockImpl *object;
787 int i, j;
788 HRESULT temp_result;
790 D3DCREATEOBJECTINSTANCE(object, StateBlock)
791 object->blockType = Type;
793 /* Special case - Used during initialization to produce a placeholder stateblock
794 so other functions called can update a state block */
795 if (Type == WINED3DSBT_INIT) {
796 /* Don't bother increasing the reference count otherwise a device will never
797 be freed due to circular dependencies */
798 return WINED3D_OK;
801 temp_result = allocate_shader_constants(object);
802 if (WINED3D_OK != temp_result)
803 return temp_result;
805 /* Otherwise, might as well set the whole state block to the appropriate values */
806 if (This->stateBlock != NULL)
807 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
808 else
809 memset(object->streamFreq, 1, sizeof(object->streamFreq));
811 /* Reset the ref and type after kludging it */
812 object->wineD3DDevice = This;
813 object->ref = 1;
814 object->blockType = Type;
816 TRACE("Updating changed flags appropriate for type %d\n", Type);
818 if (Type == WINED3DSBT_ALL) {
820 TRACE("ALL => Pretend everything has changed\n");
821 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
823 } else if (Type == WINED3DSBT_PIXELSTATE) {
825 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
826 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
828 object->changed.pixelShader = TRUE;
830 /* Pixel Shader Constants */
831 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
832 object->changed.pixelShaderConstantsF[i] = TRUE;
833 for (i = 0; i < MAX_CONST_B; ++i)
834 object->changed.pixelShaderConstantsB[i] = TRUE;
835 for (i = 0; i < MAX_CONST_I; ++i)
836 object->changed.pixelShaderConstantsI[i] = TRUE;
838 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
839 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
841 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
842 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
843 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
846 for (j = 0 ; j < 16; j++) {
847 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
849 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
853 } else if (Type == WINED3DSBT_VERTEXSTATE) {
855 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
856 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
858 object->changed.vertexShader = TRUE;
860 /* Vertex Shader Constants */
861 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
862 object->changed.vertexShaderConstantsF[i] = TRUE;
863 for (i = 0; i < MAX_CONST_B; ++i)
864 object->changed.vertexShaderConstantsB[i] = TRUE;
865 for (i = 0; i < MAX_CONST_I; ++i)
866 object->changed.vertexShaderConstantsI[i] = TRUE;
868 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
869 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
871 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
872 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
873 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
876 for (j = 0 ; j < 16; j++){
877 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
878 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
882 /* Duplicate light chain */
884 PLIGHTINFOEL *src = NULL;
885 PLIGHTINFOEL *dst = NULL;
886 PLIGHTINFOEL *newEl = NULL;
887 src = This->stateBlock->lights;
888 object->lights = NULL;
891 while (src) {
892 newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
893 if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
894 memcpy(newEl, src, sizeof(PLIGHTINFOEL));
895 newEl->prev = dst;
896 newEl->changed = TRUE;
897 newEl->enabledChanged = TRUE;
898 if (dst == NULL) {
899 object->lights = newEl;
900 } else {
901 dst->next = newEl;
903 dst = newEl;
904 src = src->next;
909 } else {
910 FIXME("Unrecognized state block type %d\n", Type);
913 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
914 return WINED3D_OK;
918 /* ************************************
919 MSDN:
920 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
922 Discard
923 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
925 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.
927 ******************************** */
929 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) {
930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
931 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
932 unsigned int pow2Width, pow2Height;
933 unsigned int Size = 1;
934 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
935 TRACE("(%p) Create surface\n",This);
937 /** FIXME: Check ranges on the inputs are valid
938 * MSDN
939 * MultisampleQuality
940 * [in] Quality level. The valid range is between zero and one less than the level
941 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
942 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
943 * values of paired render targets, depth stencil surfaces, and the MultiSample type
944 * must all match.
945 *******************************/
949 * TODO: Discard MSDN
950 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
952 * If this flag is set, the contents of the depth stencil buffer will be
953 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
954 * with a different depth surface.
956 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
957 ***************************/
959 if(MultisampleQuality < 0) {
960 FIXME("Invalid multisample level %ld\n", MultisampleQuality);
961 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
964 if(MultisampleQuality > 0) {
965 FIXME("MultisampleQuality set to %ld, substituting 0\n", MultisampleQuality);
966 MultisampleQuality=0;
969 /** FIXME: Check that the format is supported
970 * by the device.
971 *******************************/
973 /* Non-power2 support */
974 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
975 pow2Width = Width;
976 pow2Height = Height;
977 } else {
978 /* Find the nearest pow2 match */
979 pow2Width = pow2Height = 1;
980 while (pow2Width < Width) pow2Width <<= 1;
981 while (pow2Height < Height) pow2Height <<= 1;
984 if (pow2Width > Width || pow2Height > Height) {
985 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
986 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
987 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
988 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
989 This, Width, Height);
990 return WINED3DERR_NOTAVAILABLE;
994 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
995 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
996 * space!
997 *********************************/
998 if (WINED3DFMT_UNKNOWN == Format) {
999 Size = 0;
1000 } else if (Format == WINED3DFMT_DXT1) {
1001 /* DXT1 is half byte per pixel */
1002 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4)) >> 1;
1004 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1005 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
1006 Size = ((max(pow2Width,4) * tableEntry->bpp) * max(pow2Height,4));
1007 } else {
1008 /* The pitch is a multiple of 4 bytes */
1009 Size = ((pow2Width * tableEntry->bpp) + 3) & ~3;
1010 Size *= pow2Height;
1013 /** Create and initialise the surface resource **/
1014 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
1015 /* "Standalone" surface */
1016 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1018 object->currentDesc.Width = Width;
1019 object->currentDesc.Height = Height;
1020 object->currentDesc.MultiSampleType = MultiSample;
1021 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1023 /* Setup some glformat defaults */
1024 object->glDescription.glFormat = tableEntry->glFormat;
1025 object->glDescription.glFormatInternal = tableEntry->glInternal;
1026 object->glDescription.glType = tableEntry->glType;
1028 object->glDescription.textureName = 0;
1029 object->glDescription.level = Level;
1030 object->glDescription.target = GL_TEXTURE_2D;
1032 /* Internal data */
1033 object->pow2Width = pow2Width;
1034 object->pow2Height = pow2Height;
1036 /* Flags */
1037 object->Flags = 0; /* We start without flags set */
1038 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
1039 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1040 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1041 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1044 if (WINED3DFMT_UNKNOWN != Format) {
1045 object->bytesPerPixel = tableEntry->bpp;
1046 object->pow2Size = (pow2Width * object->bytesPerPixel) * pow2Height;
1047 } else {
1048 object->bytesPerPixel = 0;
1049 object->pow2Size = 0;
1052 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
1054 TRACE("Pool %d %d %d %d",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1056 /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly
1057 * this function is too deap to need to care about things like this.
1058 * Levels need to be checked too, and possibly Type wince they all affect what can be done.
1059 * ****************************************/
1060 switch(Pool) {
1061 case WINED3DPOOL_SCRATCH:
1062 if(!Lockable)
1063 FIXME("Create suface called with a pool of SCRATCH and a Lockable of FALSE \
1064 which are mutually exclusive, setting lockable to true\n");
1065 Lockable = TRUE;
1066 break;
1067 case WINED3DPOOL_SYSTEMMEM:
1068 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, \
1069 this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1070 case WINED3DPOOL_MANAGED:
1071 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a \
1072 Usage of DYNAMIC which are mutually exclusive, not doing \
1073 anything just telling you.\n");
1074 break;
1075 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1076 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1077 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1078 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1079 break;
1080 default:
1081 FIXME("(%p) Unknown pool %d\n", This, Pool);
1082 break;
1085 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1086 FIXME("Trying to create a render target that isn't in the default pool\n");
1089 /* mark the texture as dirty so that it get's loaded first time around*/
1090 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
1091 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1092 This, Width, Height, Format, debug_d3dformat(Format),
1093 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1095 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
1096 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
1097 This->ddraw_primary = (IWineD3DSurface *) object;
1099 /* Look at the implementation and set the correct Vtable */
1100 switch(Impl) {
1101 case SURFACE_OPENGL:
1102 /* Nothing to do, it's set already */
1103 break;
1105 case SURFACE_GDI:
1106 object->lpVtbl = &IWineGDISurface_Vtbl;
1107 break;
1109 default:
1110 /* To be sure to catch this */
1111 ERR("Unknown requested surface implementation %d!\n", Impl);
1112 IWineD3DSurface_Release((IWineD3DSurface *) object);
1113 return WINED3DERR_INVALIDCALL;
1116 /* Call the private setup routine */
1117 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
1121 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
1122 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1123 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
1124 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1127 IWineD3DTextureImpl *object;
1128 unsigned int i;
1129 UINT tmpW;
1130 UINT tmpH;
1131 HRESULT hr;
1132 unsigned int pow2Width;
1133 unsigned int pow2Height;
1136 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#lx\n", This, Width, Height, Levels, Usage);
1137 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1138 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1140 /* TODO: It should only be possible to create textures for formats
1141 that are reported as supported */
1142 if (WINED3DFMT_UNKNOWN >= Format) {
1143 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1144 return WINED3DERR_INVALIDCALL;
1147 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
1148 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1149 object->width = Width;
1150 object->height = Height;
1152 /** Non-power2 support **/
1153 if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
1154 pow2Width = Width;
1155 pow2Height = Height;
1156 } else {
1157 /* Find the nearest pow2 match */
1158 pow2Width = pow2Height = 1;
1159 while (pow2Width < Width) pow2Width <<= 1;
1160 while (pow2Height < Height) pow2Height <<= 1;
1163 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1164 /* Precalculated scaling for 'faked' non power of two texture coords */
1165 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
1166 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
1167 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
1169 /* Calculate levels for mip mapping */
1170 if (Levels == 0) {
1171 TRACE("calculating levels %d\n", object->baseTexture.levels);
1172 object->baseTexture.levels++;
1173 tmpW = Width;
1174 tmpH = Height;
1175 while (tmpW > 1 || tmpH > 1) {
1176 tmpW = max(1, tmpW >> 1);
1177 tmpH = max(1, tmpH >> 1);
1178 object->baseTexture.levels++;
1180 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1183 /* Generate all the surfaces */
1184 tmpW = Width;
1185 tmpH = Height;
1186 for (i = 0; i < object->baseTexture.levels; i++)
1188 /* use the callback to create the texture surface */
1189 hr = D3DCB_CreateSurface(This->parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
1190 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1191 FIXME("Failed to create surface %p\n", object);
1192 /* clean up */
1193 object->surfaces[i] = NULL;
1194 IWineD3DTexture_Release((IWineD3DTexture *)object);
1196 *ppTexture = NULL;
1197 return hr;
1200 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1201 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1202 /* calculate the next mipmap level */
1203 tmpW = max(1, tmpW >> 1);
1204 tmpH = max(1, tmpH >> 1);
1207 TRACE("(%p) : Created texture %p\n", This, object);
1208 return WINED3D_OK;
1211 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1212 UINT Width, UINT Height, UINT Depth,
1213 UINT Levels, DWORD Usage,
1214 WINED3DFORMAT Format, WINED3DPOOL Pool,
1215 IWineD3DVolumeTexture **ppVolumeTexture,
1216 HANDLE *pSharedHandle, IUnknown *parent,
1217 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
1219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1220 IWineD3DVolumeTextureImpl *object;
1221 unsigned int i;
1222 UINT tmpW;
1223 UINT tmpH;
1224 UINT tmpD;
1226 /* TODO: It should only be possible to create textures for formats
1227 that are reported as supported */
1228 if (WINED3DFMT_UNKNOWN >= Format) {
1229 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1230 return WINED3DERR_INVALIDCALL;
1233 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1234 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1236 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1237 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1239 object->width = Width;
1240 object->height = Height;
1241 object->depth = Depth;
1243 /* Calculate levels for mip mapping */
1244 if (Levels == 0) {
1245 object->baseTexture.levels++;
1246 tmpW = Width;
1247 tmpH = Height;
1248 tmpD = Depth;
1249 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1250 tmpW = max(1, tmpW >> 1);
1251 tmpH = max(1, tmpH >> 1);
1252 tmpD = max(1, tmpD >> 1);
1253 object->baseTexture.levels++;
1255 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1258 /* Generate all the surfaces */
1259 tmpW = Width;
1260 tmpH = Height;
1261 tmpD = Depth;
1263 for (i = 0; i < object->baseTexture.levels; i++)
1265 /* Create the volume */
1266 D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage,
1267 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1269 /* Set it's container to this object */
1270 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1272 /* calcualte the next mipmap level */
1273 tmpW = max(1, tmpW >> 1);
1274 tmpH = max(1, tmpH >> 1);
1275 tmpD = max(1, tmpD >> 1);
1278 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1279 TRACE("(%p) : Created volume texture %p\n", This, object);
1280 return WINED3D_OK;
1283 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1284 UINT Width, UINT Height, UINT Depth,
1285 DWORD Usage,
1286 WINED3DFORMAT Format, WINED3DPOOL Pool,
1287 IWineD3DVolume** ppVolume,
1288 HANDLE* pSharedHandle, IUnknown *parent) {
1290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1291 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1292 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
1294 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1296 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1297 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1299 object->currentDesc.Width = Width;
1300 object->currentDesc.Height = Height;
1301 object->currentDesc.Depth = Depth;
1302 object->bytesPerPixel = formatDesc->bpp;
1304 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1305 object->lockable = TRUE;
1306 object->locked = FALSE;
1307 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1308 object->dirty = TRUE;
1310 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1313 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1314 UINT Levels, DWORD Usage,
1315 WINED3DFORMAT Format, WINED3DPOOL Pool,
1316 IWineD3DCubeTexture **ppCubeTexture,
1317 HANDLE *pSharedHandle, IUnknown *parent,
1318 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1321 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1322 unsigned int i, j;
1323 UINT tmpW;
1324 HRESULT hr;
1325 unsigned int pow2EdgeLength = EdgeLength;
1327 /* TODO: It should only be possible to create textures for formats
1328 that are reported as supported */
1329 if (WINED3DFMT_UNKNOWN >= Format) {
1330 WARN("(%p) : Texture cannot be created with a format of D3DFMT_UNKNOWN\n", This);
1331 return WINED3DERR_INVALIDCALL;
1334 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1335 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1337 TRACE("(%p) Create Cube Texture\n", This);
1339 /** Non-power2 support **/
1341 /* Find the nearest pow2 match */
1342 pow2EdgeLength = 1;
1343 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1345 object->edgeLength = EdgeLength;
1346 /* TODO: support for native non-power 2 */
1347 /* Precalculated scaling for 'faked' non power of two texture coords */
1348 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1350 /* Calculate levels for mip mapping */
1351 if (Levels == 0) {
1352 object->baseTexture.levels++;
1353 tmpW = EdgeLength;
1354 while (tmpW > 1) {
1355 tmpW = max(1, tmpW >> 1);
1356 object->baseTexture.levels++;
1358 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1361 /* Generate all the surfaces */
1362 tmpW = EdgeLength;
1363 for (i = 0; i < object->baseTexture.levels; i++) {
1365 /* Create the 6 faces */
1366 for (j = 0; j < 6; j++) {
1368 hr=D3DCB_CreateSurface(This->parent, tmpW, tmpW, Format, Usage, Pool,
1369 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1371 if(hr!= WINED3D_OK) {
1372 /* clean up */
1373 int k;
1374 int l;
1375 for (l = 0; l < j; l++) {
1376 IWineD3DSurface_Release(object->surfaces[j][i]);
1378 for (k = 0; k < i; k++) {
1379 for (l = 0; l < 6; l++) {
1380 IWineD3DSurface_Release(object->surfaces[l][j]);
1384 FIXME("(%p) Failed to create surface\n",object);
1385 HeapFree(GetProcessHeap(),0,object);
1386 *ppCubeTexture = NULL;
1387 return hr;
1389 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1390 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1392 tmpW = max(1, tmpW >> 1);
1395 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1396 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1397 return WINED3D_OK;
1400 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1404 if (NULL == ppQuery) {
1405 /* Just a check to see if we support this type of query */
1406 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1407 switch(Type) {
1408 case WINED3DQUERYTYPE_OCCLUSION:
1409 TRACE("(%p) occlusion query\n", This);
1410 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1411 hr = WINED3D_OK;
1412 else
1413 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1414 break;
1415 case WINED3DQUERYTYPE_VCACHE:
1416 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1417 case WINED3DQUERYTYPE_VERTEXSTATS:
1418 case WINED3DQUERYTYPE_EVENT:
1419 case WINED3DQUERYTYPE_TIMESTAMP:
1420 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1421 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1422 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1423 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1424 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1425 case WINED3DQUERYTYPE_PIXELTIMINGS:
1426 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1427 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1428 default:
1429 FIXME("(%p) Unhandled query type %d\n", This, Type);
1431 return hr;
1434 D3DCREATEOBJECTINSTANCE(object, Query)
1435 object->type = Type;
1436 /* allocated the 'extended' data based on the type of query requested */
1437 switch(Type){
1438 case D3DQUERYTYPE_OCCLUSION:
1439 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1440 TRACE("(%p) Allocating data for an occlusion query\n", This);
1441 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1442 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1443 break;
1445 case D3DQUERYTYPE_VCACHE:
1446 case D3DQUERYTYPE_RESOURCEMANAGER:
1447 case D3DQUERYTYPE_VERTEXSTATS:
1448 case D3DQUERYTYPE_EVENT:
1449 case D3DQUERYTYPE_TIMESTAMP:
1450 case D3DQUERYTYPE_TIMESTAMPDISJOINT:
1451 case D3DQUERYTYPE_TIMESTAMPFREQ:
1452 case D3DQUERYTYPE_PIPELINETIMINGS:
1453 case D3DQUERYTYPE_INTERFACETIMINGS:
1454 case D3DQUERYTYPE_VERTEXTIMINGS:
1455 case D3DQUERYTYPE_PIXELTIMINGS:
1456 case D3DQUERYTYPE_BANDWIDTHTIMINGS:
1457 case D3DQUERYTYPE_CACHEUTILIZATION:
1458 default:
1459 object->extendedData = 0;
1460 FIXME("(%p) Unhandled query type %d\n",This , Type);
1462 TRACE("(%p) : Created Query %p\n", This, object);
1463 return WINED3D_OK;
1466 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1467 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1468 IUnknown* parent,
1469 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1470 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1473 HDC hDc;
1474 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1475 int num;
1476 XVisualInfo template;
1477 GLXContext oldContext;
1478 Drawable oldDrawable;
1479 HRESULT hr = WINED3D_OK;
1481 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1483 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1484 * does a device hold a reference to a swap chain giving them a lifetime of the device
1485 * or does the swap chain notify the device of its destruction.
1486 *******************************/
1488 /* Check the params */
1489 if(*pPresentationParameters->BackBufferCount > D3DPRESENT_BACK_BUFFER_MAX) {
1490 ERR("App requested %d back buffers, this is not supported for now\n", *pPresentationParameters->BackBufferCount);
1491 return WINED3DERR_INVALIDCALL;
1492 } else if (*pPresentationParameters->BackBufferCount > 1) {
1493 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");
1496 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1498 /*********************
1499 * Lookup the window Handle and the relating X window handle
1500 ********************/
1502 /* Setup hwnd we are using, plus which display this equates to */
1503 object->win_handle = *(pPresentationParameters->hDeviceWindow);
1504 if (!object->win_handle) {
1505 object->win_handle = This->createParms.hFocusWindow;
1508 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1509 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1510 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1511 return WINED3DERR_NOTAVAILABLE;
1513 hDc = GetDC(object->win_handle);
1514 object->display = get_display(hDc);
1515 ReleaseDC(object->win_handle, hDc);
1516 TRACE("Using a display of %p %p\n", object->display, hDc);
1518 if (NULL == object->display || NULL == hDc) {
1519 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1520 return WINED3DERR_NOTAVAILABLE;
1523 if (object->win == 0) {
1524 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1525 return WINED3DERR_NOTAVAILABLE;
1528 * Create an opengl context for the display visual
1529 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1530 * use different properties after that point in time. FIXME: How to handle when requested format
1531 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1532 * it chooses is identical to the one already being used!
1533 **********************************/
1535 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1536 ENTER_GL();
1538 /* Create a new context for this swapchain */
1539 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
1540 /* TODO: change this to find a similar visual, but one with a stencil/zbuffer buffer that matches the request
1541 (or the best possible if none is requested) */
1542 TRACE("Found x visual ID : %ld\n", template.visualid);
1544 object->visInfo = XGetVisualInfo(object->display, VisualIDMask, &template, &num);
1545 if (NULL == object->visInfo) {
1546 ERR("cannot really get XVisual\n");
1547 LEAVE_GL();
1548 return WINED3DERR_NOTAVAILABLE;
1549 } else {
1550 int n, value;
1551 /* Write out some debug info about the visual/s */
1552 TRACE("Using x visual ID : %ld\n", template.visualid);
1553 TRACE(" visual info: %p\n", object->visInfo);
1554 TRACE(" num items : %d\n", num);
1555 for (n = 0;n < num; n++) {
1556 TRACE("=====item=====: %d\n", n + 1);
1557 TRACE(" visualid : %ld\n", object->visInfo[n].visualid);
1558 TRACE(" screen : %d\n", object->visInfo[n].screen);
1559 TRACE(" depth : %u\n", object->visInfo[n].depth);
1560 TRACE(" class : %d\n", object->visInfo[n].class);
1561 TRACE(" red_mask : %ld\n", object->visInfo[n].red_mask);
1562 TRACE(" green_mask : %ld\n", object->visInfo[n].green_mask);
1563 TRACE(" blue_mask : %ld\n", object->visInfo[n].blue_mask);
1564 TRACE(" colormap_size : %d\n", object->visInfo[n].colormap_size);
1565 TRACE(" bits_per_rgb : %d\n", object->visInfo[n].bits_per_rgb);
1566 /* log some extra glx info */
1567 glXGetConfig(object->display, object->visInfo, GLX_AUX_BUFFERS, &value);
1568 TRACE(" gl_aux_buffers : %d\n", value);
1569 glXGetConfig(object->display, object->visInfo, GLX_BUFFER_SIZE ,&value);
1570 TRACE(" gl_buffer_size : %d\n", value);
1571 glXGetConfig(object->display, object->visInfo, GLX_RED_SIZE, &value);
1572 TRACE(" gl_red_size : %d\n", value);
1573 glXGetConfig(object->display, object->visInfo, GLX_GREEN_SIZE, &value);
1574 TRACE(" gl_green_size : %d\n", value);
1575 glXGetConfig(object->display, object->visInfo, GLX_BLUE_SIZE, &value);
1576 TRACE(" gl_blue_size : %d\n", value);
1577 glXGetConfig(object->display, object->visInfo, GLX_ALPHA_SIZE, &value);
1578 TRACE(" gl_alpha_size : %d\n", value);
1579 glXGetConfig(object->display, object->visInfo, GLX_DEPTH_SIZE ,&value);
1580 TRACE(" gl_depth_size : %d\n", value);
1581 glXGetConfig(object->display, object->visInfo, GLX_STENCIL_SIZE, &value);
1582 TRACE(" gl_stencil_size : %d\n", value);
1584 /* Now choose a simila visual ID*/
1586 #ifdef USE_CONTEXT_MANAGER
1588 /** TODO: use a context mamager **/
1589 #endif
1592 IWineD3DSwapChain *implSwapChain;
1593 if (WINED3D_OK != IWineD3DDevice_GetSwapChain(iface, 0, &implSwapChain)) {
1594 /* The first time around we create the context that is shared with all other swapchains and render targets */
1595 object->glCtx = glXCreateContext(object->display, object->visInfo, NULL, GL_TRUE);
1596 TRACE("Creating implicit context for vis %p, hwnd %p\n", object->display, object->visInfo);
1597 } else {
1599 TRACE("Creating context for vis %p, hwnd %p\n", object->display, object->visInfo);
1600 /* TODO: don't use Impl structures outside of create functions! (a context manager will replace the ->glCtx) */
1601 /* and create a new context with the implicit swapchains context as the shared context */
1602 object->glCtx = glXCreateContext(object->display, object->visInfo, ((IWineD3DSwapChainImpl *)implSwapChain)->glCtx, GL_TRUE);
1603 IWineD3DSwapChain_Release(implSwapChain);
1607 /* Cleanup */
1608 XFree(object->visInfo);
1609 object->visInfo = NULL;
1611 LEAVE_GL();
1613 if (!object->glCtx) {
1614 ERR("Failed to create GLX context\n");
1615 return WINED3DERR_NOTAVAILABLE;
1616 } else {
1617 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld, VisInfo=%p)\n",
1618 object->win_handle, object->glCtx, object->win, object->visInfo);
1621 /*********************
1622 * Windowed / Fullscreen
1623 *******************/
1626 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1627 * so we should really check to see if there is a fullscreen swapchain already
1628 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1629 **************************************/
1631 if (!*(pPresentationParameters->Windowed)) {
1633 DEVMODEW devmode;
1634 HDC hdc;
1635 int bpp = 0;
1637 /* Get info on the current display setup */
1638 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1639 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1640 DeleteDC(hdc);
1642 /* Change the display settings */
1643 memset(&devmode, 0, sizeof(DEVMODEW));
1644 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1645 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1646 devmode.dmPelsWidth = *(pPresentationParameters->BackBufferWidth);
1647 devmode.dmPelsHeight = *(pPresentationParameters->BackBufferHeight);
1648 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1649 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1651 /* Make popup window */
1652 SetWindowLongA(object->win_handle, GWL_STYLE, WS_POPUP);
1653 SetWindowPos(object->win_handle, HWND_TOP, 0, 0,
1654 *(pPresentationParameters->BackBufferWidth),
1655 *(pPresentationParameters->BackBufferHeight), SWP_SHOWWINDOW | SWP_FRAMECHANGED);
1657 /* For GetDisplayMode */
1658 This->ddraw_width = devmode.dmPelsWidth;
1659 This->ddraw_height = devmode.dmPelsHeight;
1660 This->ddraw_format = *(pPresentationParameters->BackBufferFormat);
1664 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1665 * then the corresponding dimension of the client area of the hDeviceWindow
1666 * (or the focus window, if hDeviceWindow is NULL) is taken.
1667 **********************/
1669 if (*(pPresentationParameters->Windowed) &&
1670 ((*(pPresentationParameters->BackBufferWidth) == 0) ||
1671 (*(pPresentationParameters->BackBufferHeight) == 0))) {
1673 RECT Rect;
1674 GetClientRect(object->win_handle, &Rect);
1676 if (*(pPresentationParameters->BackBufferWidth) == 0) {
1677 *(pPresentationParameters->BackBufferWidth) = Rect.right;
1678 TRACE("Updating width to %d\n", *(pPresentationParameters->BackBufferWidth));
1680 if (*(pPresentationParameters->BackBufferHeight) == 0) {
1681 *(pPresentationParameters->BackBufferHeight) = Rect.bottom;
1682 TRACE("Updating height to %d\n", *(pPresentationParameters->BackBufferHeight));
1686 /*********************
1687 * finish off parameter initialization
1688 *******************/
1690 /* Put the correct figures in the presentation parameters */
1691 TRACE("Coppying accross presentaion paraneters\n");
1692 object->presentParms.BackBufferWidth = *(pPresentationParameters->BackBufferWidth);
1693 object->presentParms.BackBufferHeight = *(pPresentationParameters->BackBufferHeight);
1694 object->presentParms.BackBufferFormat = *(pPresentationParameters->BackBufferFormat);
1695 object->presentParms.BackBufferCount = *(pPresentationParameters->BackBufferCount);
1696 object->presentParms.MultiSampleType = *(pPresentationParameters->MultiSampleType);
1697 object->presentParms.MultiSampleQuality = NULL == pPresentationParameters->MultiSampleQuality ? 0 : *(pPresentationParameters->MultiSampleQuality);
1698 object->presentParms.SwapEffect = *(pPresentationParameters->SwapEffect);
1699 object->presentParms.hDeviceWindow = *(pPresentationParameters->hDeviceWindow);
1700 object->presentParms.Windowed = *(pPresentationParameters->Windowed);
1701 object->presentParms.EnableAutoDepthStencil = *(pPresentationParameters->EnableAutoDepthStencil);
1702 object->presentParms.AutoDepthStencilFormat = *(pPresentationParameters->AutoDepthStencilFormat);
1703 object->presentParms.Flags = *(pPresentationParameters->Flags);
1704 object->presentParms.FullScreen_RefreshRateInHz = *(pPresentationParameters->FullScreen_RefreshRateInHz);
1705 object->presentParms.PresentationInterval = *(pPresentationParameters->PresentationInterval);
1708 /*********************
1709 * Create the back, front and stencil buffers
1710 *******************/
1712 TRACE("calling rendertarget CB\n");
1713 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1714 object->presentParms.BackBufferWidth,
1715 object->presentParms.BackBufferHeight,
1716 object->presentParms.BackBufferFormat,
1717 object->presentParms.MultiSampleType,
1718 object->presentParms.MultiSampleQuality,
1719 TRUE /* Lockable */,
1720 &object->frontBuffer,
1721 NULL /* pShared (always null)*/);
1722 if (object->frontBuffer != NULL)
1723 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1725 if(object->presentParms.BackBufferCount > 0) {
1726 int i;
1728 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1729 if(!object->backBuffer) {
1730 ERR("Out of memory\n");
1732 if (object->frontBuffer) {
1733 IUnknown *bufferParent;
1734 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1735 IUnknown_Release(bufferParent); /* once for the get parent */
1736 if (IUnknown_Release(bufferParent) > 0) {
1737 FIXME("(%p) Something's still holding the front buffer\n",This);
1740 HeapFree(GetProcessHeap(), 0, object);
1741 return E_OUTOFMEMORY;
1744 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1745 TRACE("calling rendertarget CB\n");
1746 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1747 object->presentParms.BackBufferWidth,
1748 object->presentParms.BackBufferHeight,
1749 object->presentParms.BackBufferFormat,
1750 object->presentParms.MultiSampleType,
1751 object->presentParms.MultiSampleQuality,
1752 TRUE /* Lockable */,
1753 &object->backBuffer[i],
1754 NULL /* pShared (always null)*/);
1755 if(hr == WINED3D_OK && object->backBuffer[i]) {
1756 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1757 } else {
1758 break;
1761 } else {
1762 object->backBuffer = NULL;
1765 if (object->backBuffer != NULL) {
1766 ENTER_GL();
1767 glDrawBuffer(GL_BACK);
1768 checkGLcall("glDrawBuffer(GL_BACK)");
1769 LEAVE_GL();
1770 } else {
1771 /* Single buffering - draw to front buffer */
1772 ENTER_GL();
1773 glDrawBuffer(GL_FRONT);
1774 checkGLcall("glDrawBuffer(GL_FRONT)");
1775 LEAVE_GL();
1778 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1779 if (*(pPresentationParameters->EnableAutoDepthStencil) && hr == WINED3D_OK) {
1780 TRACE("Creating depth stencil buffer\n");
1781 if (This->depthStencilBuffer == NULL ) {
1782 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1783 object->presentParms.BackBufferWidth,
1784 object->presentParms.BackBufferHeight,
1785 object->presentParms.AutoDepthStencilFormat,
1786 object->presentParms.MultiSampleType,
1787 object->presentParms.MultiSampleQuality,
1788 FALSE /* FIXME: Discard */,
1789 &This->depthStencilBuffer,
1790 NULL /* pShared (always null)*/ );
1791 if (This->depthStencilBuffer != NULL)
1792 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1795 /** TODO: A check on width, height and multisample types
1796 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1797 ****************************/
1798 object->wantsDepthStencilBuffer = TRUE;
1799 } else {
1800 object->wantsDepthStencilBuffer = FALSE;
1803 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1806 /*********************
1807 * init the default renderTarget management
1808 *******************/
1809 object->drawable = object->win;
1810 object->render_ctx = object->glCtx;
1812 if (hr == WINED3D_OK) {
1813 /*********************
1814 * Setup some defaults and clear down the buffers
1815 *******************/
1816 ENTER_GL();
1817 /** save current context and drawable **/
1818 oldContext = glXGetCurrentContext();
1819 oldDrawable = glXGetCurrentDrawable();
1821 TRACE("Activating context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1822 if (glXMakeCurrent(object->display, object->win, object->glCtx) == False) {
1823 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", object->display, object->glCtx, object->win);
1825 checkGLcall("glXMakeCurrent");
1827 TRACE("Setting up the screen\n");
1828 /* Clear the screen */
1829 glClearColor(1.0, 0.0, 0.0, 0.0);
1830 checkGLcall("glClearColor");
1831 glClearIndex(0);
1832 glClearDepth(1);
1833 glClearStencil(0xffff);
1835 checkGLcall("glClear");
1837 glColor3f(1.0, 1.0, 1.0);
1838 checkGLcall("glColor3f");
1840 glEnable(GL_LIGHTING);
1841 checkGLcall("glEnable");
1843 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1844 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1846 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1847 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1849 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1850 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1852 /* switch back to the original context (if there was one)*/
1853 if (This->swapchains) {
1854 /** TODO: restore the context and drawable **/
1855 glXMakeCurrent(object->display, oldDrawable, oldContext);
1858 LEAVE_GL();
1860 TRACE("Set swapchain to %p\n", object);
1861 } else { /* something went wrong so clean up */
1862 IUnknown* bufferParent;
1863 if (object->frontBuffer) {
1865 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1866 IUnknown_Release(bufferParent); /* once for the get parent */
1867 if (IUnknown_Release(bufferParent) > 0) {
1868 FIXME("(%p) Something's still holding the front buffer\n",This);
1871 if (object->backBuffer) {
1872 int i;
1873 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1874 if(object->backBuffer[i]) {
1875 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1876 IUnknown_Release(bufferParent); /* once for the get parent */
1877 if (IUnknown_Release(bufferParent) > 0) {
1878 FIXME("(%p) Something's still holding the back buffer\n",This);
1882 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1883 object->backBuffer = NULL;
1885 /* NOTE: don't clean up the depthstencil buffer because it belongs to the device */
1886 /* Clean up the context */
1887 /* check that we are the current context first (we shouldn't be though!) */
1888 if (object->glCtx != 0) {
1889 if(glXGetCurrentContext() == object->glCtx) {
1890 glXMakeCurrent(object->display, None, NULL);
1892 glXDestroyContext(object->display, object->glCtx);
1894 HeapFree(GetProcessHeap(), 0, object);
1898 return hr;
1901 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1902 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1904 TRACE("(%p)\n", This);
1906 return This->NumberOfSwapChains;
1909 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1911 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1913 if(iSwapChain < This->NumberOfSwapChains) {
1914 *pSwapChain = This->swapchains[iSwapChain];
1915 IWineD3DSwapChain_AddRef(*pSwapChain);
1916 TRACE("(%p) returning %p\n", This, *pSwapChain);
1917 return WINED3D_OK;
1918 } else {
1919 TRACE("Swapchain out of range\n");
1920 *pSwapChain = NULL;
1921 return WINED3DERR_INVALIDCALL;
1925 /*****
1926 * Vertex Declaration
1927 *****/
1928 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, CONST VOID* pDeclaration, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *parent) {
1929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1930 IWineD3DVertexDeclarationImpl *object = NULL;
1931 HRESULT hr = WINED3D_OK;
1932 TRACE("(%p) : directXVersion=%u, pFunction=%p, ppDecl=%p\n", This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, pDeclaration, ppVertexDeclaration);
1933 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1934 object->allFVF = 0;
1936 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, (void *)pDeclaration);
1938 return hr;
1941 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1942 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, CONST DWORD *pDeclaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1944 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1945 HRESULT hr = WINED3D_OK;
1946 D3DCREATEOBJECTINSTANCE(object, VertexShader)
1947 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1949 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1951 /* If a vertex declaration has been passed, save it to the vertex shader, this affects d3d8 only. */
1952 /* Further it needs to be set before calling SetFunction as SetFunction needs the declaration. */
1953 if (pDeclaration != NULL) {
1954 IWineD3DVertexDeclaration *vertexDeclaration;
1955 hr = IWineD3DDevice_CreateVertexDeclaration(iface, pDeclaration, &vertexDeclaration ,NULL);
1956 if (WINED3D_OK == hr) {
1957 TRACE("(%p) : Setting vertex declaration to %p\n", This, vertexDeclaration);
1958 object->vertexDeclaration = vertexDeclaration;
1959 } else {
1960 FIXME("(%p) : Failed to set the declaration, returning WINED3DERR_INVALIDCALL\n", iface);
1961 IWineD3DVertexShader_Release(*ppVertexShader);
1962 return WINED3DERR_INVALIDCALL;
1966 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1968 if (WINED3D_OK != hr) {
1969 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1970 IWineD3DVertexShader_Release(*ppVertexShader);
1971 return WINED3DERR_INVALIDCALL;
1974 #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. */
1975 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1976 /* Foo */
1977 } else {
1978 /* Bar */
1981 #endif
1983 return WINED3D_OK;
1986 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1988 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1989 HRESULT hr = WINED3D_OK;
1991 D3DCREATEOBJECTINSTANCE(object, PixelShader)
1992 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1993 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1994 if (WINED3D_OK == hr) {
1995 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1996 } else {
1997 WARN("(%p) : Failed to create pixel shader\n", This);
2000 return hr;
2003 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
2004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2005 IWineD3DPaletteImpl *object;
2006 HRESULT hr;
2007 TRACE("(%p)->(%lx, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2009 /* Create the new object */
2010 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2011 if(!object) {
2012 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2013 return E_OUTOFMEMORY;
2016 object->lpVtbl = &IWineD3DPalette_Vtbl;
2017 object->ref = 1;
2018 object->Flags = Flags;
2019 object->parent = Parent;
2020 object->wineD3DDevice = This;
2021 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2023 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2025 if(!object->hpal) {
2026 HeapFree( GetProcessHeap(), 0, object);
2027 return E_OUTOFMEMORY;
2030 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2031 if(FAILED(hr)) {
2032 IWineD3DPalette_Release((IWineD3DPalette *) object);
2033 return hr;
2036 *Palette = (IWineD3DPalette *) object;
2038 return WINED3D_OK;
2041 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2043 IWineD3DSwapChainImpl *swapchain;
2045 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2046 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2048 /* TODO: Test if OpenGL is compiled in and loaded */
2050 /* Setup the implicit swapchain */
2051 TRACE("Creating implicit swapchain\n");
2052 if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
2053 WARN("Failed to create implicit swapchain\n");
2054 return WINED3DERR_INVALIDCALL;
2057 This->NumberOfSwapChains = 1;
2058 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2059 if(!This->swapchains) {
2060 ERR("Out of memory!\n");
2061 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2062 return E_OUTOFMEMORY;
2064 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2066 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2067 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2068 This->renderTarget = swapchain->backBuffer[0];
2070 else {
2071 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2072 This->renderTarget = swapchain->frontBuffer;
2074 IWineD3DSurface_AddRef(This->renderTarget);
2075 /* Depth Stencil support */
2076 This->stencilBufferTarget = This->depthStencilBuffer;
2077 if (NULL != This->stencilBufferTarget) {
2078 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2081 /* Set up some starting GL setup */
2082 ENTER_GL();
2084 * Initialize openGL extension related variables
2085 * with Default values
2088 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->display);
2089 /* Setup all the devices defaults */
2090 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2091 #if 0
2092 IWineD3DImpl_CheckGraphicsMemory();
2093 #endif
2094 LEAVE_GL();
2096 /* Initialize our list of GLSL programs */
2097 list_init(&This->glsl_shader_progs);
2099 { /* Set a default viewport */
2100 D3DVIEWPORT9 vp;
2101 vp.X = 0;
2102 vp.Y = 0;
2103 vp.Width = *(pPresentationParameters->BackBufferWidth);
2104 vp.Height = *(pPresentationParameters->BackBufferHeight);
2105 vp.MinZ = 0.0f;
2106 vp.MaxZ = 1.0f;
2107 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2110 /* Initialize the current view state */
2111 This->modelview_valid = 1;
2112 This->proj_valid = 0;
2113 This->view_ident = 1;
2114 This->last_was_rhw = 0;
2115 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2116 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2118 /* Clear the screen */
2119 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
2121 This->d3d_initialized = TRUE;
2122 return WINED3D_OK;
2125 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2127 int sampler;
2128 IUnknown* stencilBufferParent;
2129 IUnknown* swapChainParent;
2130 uint i;
2131 TRACE("(%p)\n", This);
2133 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2135 /* Delete the mouse cursor texture */
2136 if(This->cursorTexture) {
2137 ENTER_GL();
2138 glDeleteTextures(1, &This->cursorTexture);
2139 LEAVE_GL();
2140 This->cursorTexture = 0;
2143 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
2144 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2147 /* Release the buffers (with sanity checks)*/
2148 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2149 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2150 if(This->depthStencilBuffer != This->stencilBufferTarget)
2151 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2153 This->stencilBufferTarget = NULL;
2155 TRACE("Releasing the render target at %p\n", This->renderTarget);
2156 if(IWineD3DSurface_Release(This->renderTarget) >0){
2157 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2159 TRACE("Setting rendertarget to NULL\n");
2160 This->renderTarget = NULL;
2162 if (This->depthStencilBuffer) {
2163 IWineD3DSurface_GetParent(This->depthStencilBuffer, &stencilBufferParent);
2164 IUnknown_Release(stencilBufferParent); /* once for the get parent */
2165 if(IUnknown_Release(stencilBufferParent) >0){ /* the second time for when it was created */
2166 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2168 This->depthStencilBuffer = NULL;
2171 for(i=0; i < This->NumberOfSwapChains; i++) {
2172 TRACE("Releasing the implicit swapchain %d\n", i);
2173 /* Swapchain 0 is special because it's created in startup with a hanging parent, so we have to release its parent now */
2174 IWineD3DSwapChain_GetParent(This->swapchains[i], &swapChainParent);
2175 IUnknown_Release(swapChainParent); /* once for the get parent */
2176 if (IUnknown_Release(swapChainParent) > 0) { /* the second time for when it was created */
2177 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2181 HeapFree(GetProcessHeap(), 0, This->swapchains);
2182 This->swapchains = NULL;
2183 This->NumberOfSwapChains = 0;
2185 This->d3d_initialized = FALSE;
2186 return WINED3D_OK;
2189 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2191 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2193 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2194 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2195 * DDraw doesn't necessarilly have a swapchain, so we have to store the fullscreen flag
2196 * seperately.
2198 This->ddraw_fullscreen = fullscreen;
2201 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
2202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2204 DEVMODEW DevModeW;
2205 int i;
2206 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
2208 TRACE("(%p)->(%lx,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
2210 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
2211 /* Ignore some modes if a description was passed */
2212 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
2213 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
2214 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
2216 TRACE("Enumerating %ldx%ld@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
2218 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
2219 return D3D_OK;
2222 return D3D_OK;
2225 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2226 DEVMODEW devmode;
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2228 LONG ret;
2229 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2231 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2233 /* Resize the screen even without a window:
2234 * The app could have unset it with SetCooperativeLevel, but not called
2235 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2236 * but we don't have any hwnd
2239 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2240 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2241 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2242 devmode.dmPelsWidth = pMode->Width;
2243 devmode.dmPelsHeight = pMode->Height;
2245 devmode.dmDisplayFrequency = pMode->RefreshRate;
2246 if (pMode->RefreshRate != 0) {
2247 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2250 /* Only change the mode if necessary */
2251 if( (This->ddraw_width == pMode->Width) &&
2252 (This->ddraw_height == pMode->Height) &&
2253 (This->ddraw_format == pMode->Format) &&
2254 (pMode->RefreshRate == 0) ) {
2255 return D3D_OK;
2258 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2259 if (ret != DISP_CHANGE_SUCCESSFUL) {
2260 if(devmode.dmDisplayFrequency != 0) {
2261 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2262 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2263 devmode.dmDisplayFrequency = 0;
2264 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2266 if(ret != DISP_CHANGE_SUCCESSFUL) {
2267 return DDERR_INVALIDMODE;
2271 /* Store the new values */
2272 This->ddraw_width = pMode->Width;
2273 This->ddraw_height = pMode->Height;
2274 This->ddraw_format = pMode->Format;
2276 /* Only do this with a window of course */
2277 if(This->ddraw_window)
2278 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2280 return WINED3D_OK;
2283 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2285 *ppD3D= This->wineD3D;
2286 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2287 IWineD3D_AddRef(*ppD3D);
2288 return WINED3D_OK;
2291 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2292 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBO's (or whatever)
2293 * Into the video ram as possible and seeing how many fit
2294 * you can also get the correct initial value from nvidia and ATI's driver via X
2295 * texture memory is video memory + AGP memory
2296 *******************/
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2298 static BOOL showfixmes = TRUE;
2299 if (showfixmes) {
2300 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2301 (wined3d_settings.emulated_textureram/(1024*1024)),
2302 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2303 showfixmes = FALSE;
2305 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2306 (wined3d_settings.emulated_textureram/(1024*1024)),
2307 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2308 /* return simulated texture memory left */
2309 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2314 /*****
2315 * Get / Set FVF
2316 *****/
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2319 HRESULT hr = WINED3D_OK;
2321 /* Update the current state block */
2322 This->updateStateBlock->fvf = fvf;
2323 This->updateStateBlock->changed.fvf = TRUE;
2324 This->updateStateBlock->set.fvf = TRUE;
2326 TRACE("(%p) : FVF Shader FVF set to %lx\n", This, fvf);
2327 return hr;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 TRACE("(%p) : GetFVF returning %lx\n", This, This->stateBlock->fvf);
2334 *pfvf = This->stateBlock->fvf;
2335 return WINED3D_OK;
2338 /*****
2339 * Get / Set Stream Source
2340 *****/
2341 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2343 IWineD3DVertexBuffer *oldSrc;
2345 /**TODO: instance and index data, see
2346 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2348 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/SetStreamSourceFreq.asp
2349 **************/
2351 /* D3d9 only, but shouldn't hurt d3d8 */
2352 UINT streamFlags;
2354 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2355 if (streamFlags) {
2356 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2357 FIXME("stream index data not supported\n");
2359 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2360 FIXME("stream instance data not supported\n");
2364 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2366 if (StreamNumber >= MAX_STREAMS) {
2367 WARN("Stream out of range %d\n", StreamNumber);
2368 return WINED3DERR_INVALIDCALL;
2371 oldSrc = This->stateBlock->streamSource[StreamNumber];
2372 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2374 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2375 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2376 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2377 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2378 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2379 This->updateStateBlock->streamFlags[StreamNumber] = streamFlags;
2381 /* Handle recording of state blocks */
2382 if (This->isRecordingState) {
2383 TRACE("Recording... not performing anything\n");
2384 return WINED3D_OK;
2387 /* Same stream object: no action */
2388 if (oldSrc == pStreamData)
2389 return WINED3D_OK;
2391 /* Need to do a getParent and pass the reffs up */
2392 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2393 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2394 so for now, just count internally */
2395 if (pStreamData != NULL) {
2396 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2397 if( (vbImpl->Flags & VBFLAG_STREAM) && vbImpl->stream != StreamNumber) {
2398 WARN("Assigning a Vertex Buffer to stream %d which is already assigned to stream %d\n", StreamNumber, vbImpl->stream);
2400 vbImpl->stream = StreamNumber;
2401 vbImpl->Flags |= VBFLAG_STREAM;
2402 IWineD3DVertexBuffer_AddRef(pStreamData);
2404 if (oldSrc != NULL) {
2405 ((IWineD3DVertexBufferImpl *) oldSrc)->Flags &= ~VBFLAG_STREAM;
2406 IWineD3DVertexBuffer_Release(oldSrc);
2409 return WINED3D_OK;
2412 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2414 UINT streamFlags;
2416 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2417 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2420 streamFlags = StreamNumber &(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2421 if (streamFlags) {
2422 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2423 FIXME("stream index data not supported\n");
2425 if (streamFlags & D3DSTREAMSOURCE_INDEXEDDATA) {
2426 FIXME("stream instance data not supported\n");
2430 StreamNumber&= ~(D3DSTREAMSOURCE_INDEXEDDATA | D3DSTREAMSOURCE_INSTANCEDATA);
2432 if (StreamNumber >= MAX_STREAMS) {
2433 WARN("Stream out of range %d\n", StreamNumber);
2434 return WINED3DERR_INVALIDCALL;
2436 *pStream = This->stateBlock->streamSource[StreamNumber];
2437 *pStride = This->stateBlock->streamStride[StreamNumber];
2438 if (pOffset) {
2439 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2442 if (*pStream == NULL) {
2443 FIXME("Attempting to get an empty stream %d, returning WINED3DERR_INVALIDCALL\n", StreamNumber);
2444 return WINED3DERR_INVALIDCALL;
2447 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2448 return WINED3D_OK;
2451 /*Should be quite easy, just an extension of vertexdata
2452 ref...
2453 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2455 The divider is a bit odd though
2457 VertexOffset = StartVertex / Divider * StreamStride +
2458 VertexIndex / Divider * StreamStride + StreamOffset
2461 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2464 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2465 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (D3DSTREAMSOURCE_INSTANCEDATA | D3DSTREAMSOURCE_INDEXEDDATA );
2467 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2468 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2469 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2471 if (This->updateStateBlock->streamFlags[StreamNumber] || This->updateStateBlock->streamFreq[StreamNumber] != 1) {
2472 FIXME("Stream indexing not fully supported\n");
2475 return WINED3D_OK;
2478 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2482 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2484 TRACE("(%p) : returning %d\n", This, *Divider);
2486 return WINED3D_OK;
2489 /*****
2490 * Get / Set & Multiply Transform
2491 *****/
2492 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) {
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 /* Most of this routine, comments included copied from ddraw tree initially: */
2496 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2498 /* Handle recording of state blocks */
2499 if (This->isRecordingState) {
2500 TRACE("Recording... not performing anything\n");
2501 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2502 This->updateStateBlock->set.transform[d3dts] = TRUE;
2503 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX));
2504 return WINED3D_OK;
2508 * If the new matrix is the same as the current one,
2509 * we cut off any further processing. this seems to be a reasonable
2510 * optimization because as was noticed, some apps (warcraft3 for example)
2511 * tend towards setting the same matrix repeatedly for some reason.
2513 * From here on we assume that the new matrix is different, wherever it matters.
2515 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) {
2516 TRACE("The app is setting the same matrix over again\n");
2517 return WINED3D_OK;
2518 } else {
2519 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2523 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2524 where ViewMat = Camera space, WorldMat = world space.
2526 In OpenGL, camera and world space is combined into GL_MODELVIEW
2527 matrix. The Projection matrix stay projection matrix.
2530 /* Capture the times we can just ignore the change for now */
2531 if (d3dts == WINED3DTS_WORLDMATRIX(0)) {
2532 This->modelview_valid = FALSE;
2533 return WINED3D_OK;
2535 } else if (d3dts == WINED3DTS_PROJECTION) {
2536 This->proj_valid = FALSE;
2537 return WINED3D_OK;
2539 } else if (d3dts >= WINED3DTS_WORLDMATRIX(1) && d3dts <= WINED3DTS_WORLDMATRIX(255)) {
2540 /* Indexed Vertex Blending Matrices 256 -> 511 */
2541 /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */
2542 FIXME("WINED3DTS_WORLDMATRIX(1..255) not handled\n");
2543 return WINED3D_OK;
2546 /* Now we really are going to have to change a matrix */
2547 ENTER_GL();
2549 if (d3dts >= WINED3DTS_TEXTURE0 && d3dts <= WINED3DTS_TEXTURE7) { /* handle texture matrices */
2550 /* This is now set with the texture unit states, it may be a good idea to flag the change though! */
2551 } else if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2552 unsigned int k;
2554 /* If we are changing the View matrix, reset the light and clipping planes to the new view
2555 * NOTE: We have to reset the positions even if the light/plane is not currently
2556 * enabled, since the call to enable it will not reset the position.
2557 * NOTE2: Apparently texture transforms do NOT need reapplying
2560 PLIGHTINFOEL *lightChain = NULL;
2561 This->modelview_valid = FALSE;
2562 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2564 glMatrixMode(GL_MODELVIEW);
2565 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2566 glPushMatrix();
2567 glLoadMatrixf((float *)lpmatrix);
2568 checkGLcall("glLoadMatrixf(...)");
2570 /* Reset lights */
2571 lightChain = This->stateBlock->lights;
2572 while (lightChain && lightChain->glIndex != -1) {
2573 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
2574 checkGLcall("glLightfv posn");
2575 glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
2576 checkGLcall("glLightfv dirn");
2577 lightChain = lightChain->next;
2580 /* Reset Clipping Planes if clipping is enabled */
2581 for (k = 0; k < GL_LIMITS(clipplanes); k++) {
2582 glClipPlane(GL_CLIP_PLANE0 + k, This->stateBlock->clipplane[k]);
2583 checkGLcall("glClipPlane");
2585 glPopMatrix();
2587 } else { /* What was requested!?? */
2588 WARN("invalid matrix specified: %i\n", d3dts);
2591 /* Release lock, all done */
2592 LEAVE_GL();
2593 return WINED3D_OK;
2596 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2599 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(D3DMATRIX));
2600 return WINED3D_OK;
2603 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) {
2604 D3DMATRIX *mat = NULL;
2605 D3DMATRIX temp;
2607 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2608 * below means it will be recorded in a state block change, but it
2609 * works regardless where it is recorded.
2610 * If this is found to be wrong, change to StateBlock.
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2615 if (State < HIGHEST_TRANSFORMSTATE)
2617 mat = &This->updateStateBlock->transforms[State];
2618 } else {
2619 FIXME("Unhandled transform state!!\n");
2622 multiply_matrix(&temp, mat, (D3DMATRIX *) pMatrix);
2624 /* Apply change via set transform - will reapply to eg. lights this way */
2625 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2628 /*****
2629 * Get / Set Light
2630 * WARNING: This code relies on the fact that D3DLIGHT8 == D3DLIGHT9
2631 *****/
2632 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2633 you can reference any indexes you want as long as that number max are enabled at any
2634 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2635 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2636 but when recording, just build a chain pretty much of commands to be replayed. */
2638 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2639 float rho;
2640 PLIGHTINFOEL *object, *temp;
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2645 /* If recording state block, just add to end of lights chain */
2646 if (This->isRecordingState) {
2647 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2648 if (NULL == object) {
2649 return WINED3DERR_OUTOFVIDEOMEMORY;
2651 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2652 object->OriginalIndex = Index;
2653 object->glIndex = -1;
2654 object->changed = TRUE;
2656 /* Add to the END of the chain of lights changes to be replayed */
2657 if (This->updateStateBlock->lights == NULL) {
2658 This->updateStateBlock->lights = object;
2659 } else {
2660 temp = This->updateStateBlock->lights;
2661 while (temp->next != NULL) temp=temp->next;
2662 temp->next = object;
2664 TRACE("Recording... not performing anything more\n");
2665 return WINED3D_OK;
2668 /* Ok, not recording any longer so do real work */
2669 object = This->stateBlock->lights;
2670 while (object != NULL && object->OriginalIndex != Index) object = object->next;
2672 /* If we didn't find it in the list of lights, time to add it */
2673 if (object == NULL) {
2674 PLIGHTINFOEL *insertAt,*prevPos;
2676 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2677 if (NULL == object) {
2678 return WINED3DERR_OUTOFVIDEOMEMORY;
2680 object->OriginalIndex = Index;
2681 object->glIndex = -1;
2683 /* Add it to the front of list with the idea that lights will be changed as needed
2684 BUT after any lights currently assigned GL indexes */
2685 insertAt = This->stateBlock->lights;
2686 prevPos = NULL;
2687 while (insertAt != NULL && insertAt->glIndex != -1) {
2688 prevPos = insertAt;
2689 insertAt = insertAt->next;
2692 if (insertAt == NULL && prevPos == NULL) { /* Start of list */
2693 This->stateBlock->lights = object;
2694 } else if (insertAt == NULL) { /* End of list */
2695 prevPos->next = object;
2696 object->prev = prevPos;
2697 } else { /* Middle of chain */
2698 if (prevPos == NULL) {
2699 This->stateBlock->lights = object;
2700 } else {
2701 prevPos->next = object;
2703 object->prev = prevPos;
2704 object->next = insertAt;
2705 insertAt->prev = object;
2709 /* Initialize the object */
2710 TRACE("Light %ld setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2711 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2712 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2713 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2714 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2715 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2716 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2718 /* Save away the information */
2719 memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT9));
2721 switch (pLight->Type) {
2722 case D3DLIGHT_POINT:
2723 /* Position */
2724 object->lightPosn[0] = pLight->Position.x;
2725 object->lightPosn[1] = pLight->Position.y;
2726 object->lightPosn[2] = pLight->Position.z;
2727 object->lightPosn[3] = 1.0f;
2728 object->cutoff = 180.0f;
2729 /* FIXME: Range */
2730 break;
2732 case D3DLIGHT_DIRECTIONAL:
2733 /* Direction */
2734 object->lightPosn[0] = -pLight->Direction.x;
2735 object->lightPosn[1] = -pLight->Direction.y;
2736 object->lightPosn[2] = -pLight->Direction.z;
2737 object->lightPosn[3] = 0.0;
2738 object->exponent = 0.0f;
2739 object->cutoff = 180.0f;
2740 break;
2742 case D3DLIGHT_SPOT:
2743 /* Position */
2744 object->lightPosn[0] = pLight->Position.x;
2745 object->lightPosn[1] = pLight->Position.y;
2746 object->lightPosn[2] = pLight->Position.z;
2747 object->lightPosn[3] = 1.0;
2749 /* Direction */
2750 object->lightDirn[0] = pLight->Direction.x;
2751 object->lightDirn[1] = pLight->Direction.y;
2752 object->lightDirn[2] = pLight->Direction.z;
2753 object->lightDirn[3] = 1.0;
2756 * opengl-ish and d3d-ish spot lights use too different models for the
2757 * light "intensity" as a function of the angle towards the main light direction,
2758 * so we only can approximate very roughly.
2759 * however spot lights are rather rarely used in games (if ever used at all).
2760 * furthermore if still used, probably nobody pays attention to such details.
2762 if (pLight->Falloff == 0) {
2763 rho = 6.28f;
2764 } else {
2765 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2767 if (rho < 0.0001) rho = 0.0001f;
2768 object->exponent = -0.3/log(cos(rho/2));
2769 if (object->exponent > 128.0) {
2770 object->exponent = 128.0;
2772 object->cutoff = pLight->Phi*90/M_PI;
2774 /* FIXME: Range */
2775 break;
2777 default:
2778 FIXME("Unrecognized light type %d\n", pLight->Type);
2781 /* Update the live definitions if the light is currently assigned a glIndex */
2782 if (object->glIndex != -1) {
2783 setup_light(iface, object->glIndex, object);
2785 return WINED3D_OK;
2788 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2789 PLIGHTINFOEL *lightInfo = NULL;
2790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight);
2793 /* Locate the light in the live lights */
2794 lightInfo = This->stateBlock->lights;
2795 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2797 if (lightInfo == NULL) {
2798 TRACE("Light information requested but light not defined\n");
2799 return WINED3DERR_INVALIDCALL;
2802 memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT9));
2803 return WINED3D_OK;
2806 /*****
2807 * Get / Set Light Enable
2808 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2809 *****/
2810 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2811 PLIGHTINFOEL *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable);
2815 /* Tests show true = 128...not clear why */
2817 Enable = Enable? 128: 0;
2819 /* If recording state block, just add to end of lights chain with changedEnable set to true */
2820 if (This->isRecordingState) {
2821 lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
2822 if (NULL == lightInfo) {
2823 return WINED3DERR_OUTOFVIDEOMEMORY;
2825 lightInfo->OriginalIndex = Index;
2826 lightInfo->glIndex = -1;
2827 lightInfo->enabledChanged = TRUE;
2828 lightInfo->lightEnabled = Enable;
2830 /* Add to the END of the chain of lights changes to be replayed */
2831 if (This->updateStateBlock->lights == NULL) {
2832 This->updateStateBlock->lights = lightInfo;
2833 } else {
2834 PLIGHTINFOEL *temp = This->updateStateBlock->lights;
2835 while (temp->next != NULL) temp=temp->next;
2836 temp->next = lightInfo;
2838 TRACE("Recording... not performing anything more\n");
2839 return WINED3D_OK;
2842 /* Not recording... So, locate the light in the live lights */
2843 lightInfo = This->stateBlock->lights;
2844 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2846 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2847 if (lightInfo == NULL) {
2849 TRACE("Light enabled requested but light not defined, so defining one!\n");
2850 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2852 /* Search for it again! Should be fairly quick as near head of list */
2853 lightInfo = This->stateBlock->lights;
2854 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
2855 if (lightInfo == NULL) {
2856 FIXME("Adding default lights has failed dismally\n");
2857 return WINED3DERR_INVALIDCALL;
2861 /* OK, we now have a light... */
2862 if (!Enable) {
2864 /* If we are disabling it, check it was enabled, and
2865 still only do something if it has assigned a glIndex (which it should have!) */
2866 if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
2867 TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex);
2868 ENTER_GL();
2869 glDisable(GL_LIGHT0 + lightInfo->glIndex);
2870 checkGLcall("glDisable GL_LIGHT0+Index");
2871 LEAVE_GL();
2872 } else {
2873 TRACE("Nothing to do as light was not enabled\n");
2875 lightInfo->lightEnabled = Enable;
2876 } else {
2878 /* We are enabling it. If it is enabled, it's really simple */
2879 if (lightInfo->lightEnabled) {
2880 /* nop */
2881 TRACE("Nothing to do as light was enabled\n");
2883 /* If it already has a glIndex, it's still simple */
2884 } else if (lightInfo->glIndex != -1) {
2885 TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex);
2886 lightInfo->lightEnabled = Enable;
2887 ENTER_GL();
2888 glEnable(GL_LIGHT0 + lightInfo->glIndex);
2889 checkGLcall("glEnable GL_LIGHT0+Index already setup");
2890 LEAVE_GL();
2892 /* Otherwise got to find space - lights are ordered gl indexes first */
2893 } else {
2894 PLIGHTINFOEL *bsf = NULL;
2895 PLIGHTINFOEL *pos = This->stateBlock->lights;
2896 PLIGHTINFOEL *prev = NULL;
2897 int Index= 0;
2898 int glIndex = -1;
2900 /* Try to minimize changes as much as possible */
2901 while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
2903 /* Try to remember which index can be replaced if necessary */
2904 if (bsf==NULL && !pos->lightEnabled) {
2905 /* Found a light we can replace, save as best replacement */
2906 bsf = pos;
2909 /* Step to next space */
2910 prev = pos;
2911 pos = pos->next;
2912 Index ++;
2915 /* If we have too many active lights, fail the call */
2916 if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
2917 FIXME("Program requests too many concurrent lights\n");
2918 return WINED3DERR_INVALIDCALL;
2920 /* If we have allocated all lights, but not all are enabled,
2921 reuse one which is not enabled */
2922 } else if (Index == This->maxConcurrentLights) {
2923 /* use bsf - Simply swap the new light and the BSF one */
2924 PLIGHTINFOEL *bsfNext = bsf->next;
2925 PLIGHTINFOEL *bsfPrev = bsf->prev;
2927 /* Sort out ends */
2928 if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
2929 if (bsf->prev != NULL) {
2930 bsf->prev->next = lightInfo;
2931 } else {
2932 This->stateBlock->lights = lightInfo;
2935 /* If not side by side, lots of chains to update */
2936 if (bsf->next != lightInfo) {
2937 lightInfo->prev->next = bsf;
2938 bsf->next->prev = lightInfo;
2939 bsf->next = lightInfo->next;
2940 bsf->prev = lightInfo->prev;
2941 lightInfo->next = bsfNext;
2942 lightInfo->prev = bsfPrev;
2944 } else {
2945 /* Simple swaps */
2946 bsf->prev = lightInfo;
2947 bsf->next = lightInfo->next;
2948 lightInfo->next = bsf;
2949 lightInfo->prev = bsfPrev;
2953 /* Update states */
2954 glIndex = bsf->glIndex;
2955 bsf->glIndex = -1;
2956 lightInfo->glIndex = glIndex;
2957 lightInfo->lightEnabled = Enable;
2959 /* Finally set up the light in gl itself */
2960 TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex);
2961 ENTER_GL();
2962 setup_light(iface, glIndex, lightInfo);
2963 glEnable(GL_LIGHT0 + glIndex);
2964 checkGLcall("glEnable GL_LIGHT0 new setup");
2965 LEAVE_GL();
2967 /* If we reached the end of the allocated lights, with space in the
2968 gl lights, setup a new light */
2969 } else if (pos->glIndex == -1) {
2971 /* We reached the end of the allocated gl lights, so already
2972 know the index of the next one! */
2973 glIndex = Index;
2974 lightInfo->glIndex = glIndex;
2975 lightInfo->lightEnabled = Enable;
2977 /* In an ideal world, it's already in the right place */
2978 if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
2979 /* No need to move it */
2980 } else {
2981 /* Remove this light from the list */
2982 lightInfo->prev->next = lightInfo->next;
2983 if (lightInfo->next != NULL) {
2984 lightInfo->next->prev = lightInfo->prev;
2987 /* Add in at appropriate place (inbetween prev and pos) */
2988 lightInfo->prev = prev;
2989 lightInfo->next = pos;
2990 if (prev == NULL) {
2991 This->stateBlock->lights = lightInfo;
2992 } else {
2993 prev->next = lightInfo;
2995 if (pos != NULL) {
2996 pos->prev = lightInfo;
3000 /* Finally set up the light in gl itself */
3001 TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex);
3002 ENTER_GL();
3003 setup_light(iface, glIndex, lightInfo);
3004 glEnable(GL_LIGHT0 + glIndex);
3005 checkGLcall("glEnable GL_LIGHT0 new setup");
3006 LEAVE_GL();
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3016 PLIGHTINFOEL *lightInfo = NULL;
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p) : for idx(%ld)\n", This, Index);
3020 /* Locate the light in the live lights */
3021 lightInfo = This->stateBlock->lights;
3022 while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
3024 if (lightInfo == NULL) {
3025 TRACE("Light enabled state requested but light not defined\n");
3026 return WINED3DERR_INVALIDCALL;
3028 *pEnable = lightInfo->lightEnabled;
3029 return WINED3D_OK;
3032 /*****
3033 * Get / Set Clip Planes
3034 *****/
3035 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane);
3039 /* Validate Index */
3040 if (Index >= GL_LIMITS(clipplanes)) {
3041 TRACE("Application has requested clipplane this device doesn't support\n");
3042 return WINED3DERR_INVALIDCALL;
3045 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3046 This->updateStateBlock->set.clipplane[Index] = TRUE;
3047 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3048 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3049 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3050 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3052 /* Handle recording of state blocks */
3053 if (This->isRecordingState) {
3054 TRACE("Recording... not performing anything\n");
3055 return WINED3D_OK;
3058 /* Apply it */
3060 ENTER_GL();
3062 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
3063 glMatrixMode(GL_MODELVIEW);
3064 glPushMatrix();
3065 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
3067 TRACE("Clipplane [%f,%f,%f,%f]\n",
3068 This->updateStateBlock->clipplane[Index][0],
3069 This->updateStateBlock->clipplane[Index][1],
3070 This->updateStateBlock->clipplane[Index][2],
3071 This->updateStateBlock->clipplane[Index][3]);
3072 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
3073 checkGLcall("glClipPlane");
3075 glPopMatrix();
3076 LEAVE_GL();
3078 return WINED3D_OK;
3081 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 TRACE("(%p) : for idx %ld\n", This, Index);
3085 /* Validate Index */
3086 if (Index >= GL_LIMITS(clipplanes)) {
3087 TRACE("Application has requested clipplane this device doesn't support\n");
3088 return WINED3DERR_INVALIDCALL;
3091 pPlane[0] = This->stateBlock->clipplane[Index][0];
3092 pPlane[1] = This->stateBlock->clipplane[Index][1];
3093 pPlane[2] = This->stateBlock->clipplane[Index][2];
3094 pPlane[3] = This->stateBlock->clipplane[Index][3];
3095 return WINED3D_OK;
3098 /*****
3099 * Get / Set Clip Plane Status
3100 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3101 *****/
3102 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 FIXME("(%p) : stub\n", This);
3105 if (NULL == pClipStatus) {
3106 return WINED3DERR_INVALIDCALL;
3108 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3109 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3110 return WINED3D_OK;
3113 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3115 FIXME("(%p) : stub\n", This);
3116 if (NULL == pClipStatus) {
3117 return WINED3DERR_INVALIDCALL;
3119 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3120 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3121 return WINED3D_OK;
3124 /*****
3125 * Get / Set Material
3126 * WARNING: This code relies on the fact that D3DMATERIAL8 == D3DMATERIAL9
3127 *****/
3128 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 This->updateStateBlock->changed.material = TRUE;
3132 This->updateStateBlock->set.material = TRUE;
3133 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3135 /* Handle recording of state blocks */
3136 if (This->isRecordingState) {
3137 TRACE("Recording... not performing anything\n");
3138 return WINED3D_OK;
3141 ENTER_GL();
3142 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3143 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3144 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3145 pMaterial->Ambient.b, pMaterial->Ambient.a);
3146 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3147 pMaterial->Specular.b, pMaterial->Specular.a);
3148 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3149 pMaterial->Emissive.b, pMaterial->Emissive.a);
3150 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3152 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
3153 checkGLcall("glMaterialfv(GL_AMBIENT)");
3154 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
3155 checkGLcall("glMaterialfv(GL_DIFFUSE)");
3157 /* Only change material color if specular is enabled, otherwise it is set to black */
3158 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
3159 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3160 checkGLcall("glMaterialfv(GL_SPECULAR");
3161 } else {
3162 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3163 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3164 checkGLcall("glMaterialfv(GL_SPECULAR");
3166 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
3167 checkGLcall("glMaterialfv(GL_EMISSION)");
3168 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
3169 checkGLcall("glMaterialf(GL_SHININESS");
3171 LEAVE_GL();
3172 return WINED3D_OK;
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3178 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3179 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3180 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3181 pMaterial->Ambient.b, pMaterial->Ambient.a);
3182 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3183 pMaterial->Specular.b, pMaterial->Specular.a);
3184 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3185 pMaterial->Emissive.b, pMaterial->Emissive.a);
3186 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3188 return WINED3D_OK;
3191 /*****
3192 * Get / Set Indices
3193 *****/
3194 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
3195 UINT BaseVertexIndex) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 IWineD3DIndexBuffer *oldIdxs;
3199 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
3200 oldIdxs = This->updateStateBlock->pIndexData;
3202 This->updateStateBlock->changed.indices = TRUE;
3203 This->updateStateBlock->set.indices = TRUE;
3204 This->updateStateBlock->pIndexData = pIndexData;
3205 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
3207 /* Handle recording of state blocks */
3208 if (This->isRecordingState) {
3209 TRACE("Recording... not performing anything\n");
3210 return WINED3D_OK;
3213 if (NULL != pIndexData) {
3214 IWineD3DIndexBuffer_AddRef(pIndexData);
3216 if (NULL != oldIdxs) {
3217 IWineD3DIndexBuffer_Release(oldIdxs);
3219 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 *ppIndexData = This->stateBlock->pIndexData;
3227 /* up ref count on ppindexdata */
3228 if (*ppIndexData) {
3229 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3230 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
3231 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
3232 }else{
3233 TRACE("(%p) No index data set\n", This);
3235 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
3237 return WINED3D_OK;
3240 /*****
3241 * Get / Set Viewports
3242 *****/
3243 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3246 TRACE("(%p)\n", This);
3247 This->updateStateBlock->changed.viewport = TRUE;
3248 This->updateStateBlock->set.viewport = TRUE;
3249 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3251 /* Handle recording of state blocks */
3252 if (This->isRecordingState) {
3253 TRACE("Recording... not performing anything\n");
3254 return WINED3D_OK;
3256 This->viewport_changed = TRUE;
3258 ENTER_GL();
3260 TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This,
3261 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3263 glDepthRange(pViewport->MinZ, pViewport->MaxZ);
3264 checkGLcall("glDepthRange");
3265 /* Note: GL requires lower left, DirectX supplies upper left */
3266 /* TODO: replace usage of renderTarget with context management */
3267 glViewport(pViewport->X,
3268 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - (pViewport->Y + pViewport->Height)),
3269 pViewport->Width, pViewport->Height);
3271 checkGLcall("glViewport");
3273 LEAVE_GL();
3275 return WINED3D_OK;
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 TRACE("(%p)\n", This);
3282 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3283 return WINED3D_OK;
3286 static void renderstate_stencil_twosided(
3287 IWineD3DDeviceImpl *This,
3288 GLint face,
3289 GLint func,
3290 GLint ref,
3291 GLuint mask,
3292 GLint stencilFail,
3293 GLint depthFail,
3294 GLint stencilPass ) {
3295 #if 0 /* Don't use OpenGL 2.0 calls for now */
3296 if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) {
3297 GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask));
3298 checkGLcall("glStencilFuncSeparate(...)");
3299 GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass));
3300 checkGLcall("glStencilOpSeparate(...)");
3302 else
3303 #endif
3304 if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) {
3305 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
3306 checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)");
3307 GL_EXTCALL(glActiveStencilFaceEXT(face));
3308 checkGLcall("glActiveStencilFaceEXT(...)");
3309 glStencilFunc(func, ref, mask);
3310 checkGLcall("glStencilFunc(...)");
3311 glStencilOp(stencilFail, depthFail, stencilPass);
3312 checkGLcall("glStencilOp(...)");
3313 } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) {
3314 GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask));
3315 checkGLcall("glStencilFuncSeparateATI(...)");
3316 GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass));
3317 checkGLcall("glStencilOpSeparateATI(...)");
3318 } else {
3319 ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n");
3323 static void renderstate_stencil(IWineD3DDeviceImpl *This, D3DRENDERSTATETYPE State, DWORD Value) {
3324 DWORD onesided_enable = FALSE;
3325 DWORD twosided_enable = FALSE;
3326 GLint func = GL_ALWAYS;
3327 GLint func_ccw = GL_ALWAYS;
3328 GLint ref = 0;
3329 GLuint mask = 0;
3330 GLint stencilFail = GL_KEEP;
3331 GLint depthFail = GL_KEEP;
3332 GLint stencilPass = GL_KEEP;
3333 GLint stencilFail_ccw = GL_KEEP;
3334 GLint depthFail_ccw = GL_KEEP;
3335 GLint stencilPass_ccw = GL_KEEP;
3337 if( This->stateBlock->set.renderState[WINED3DRS_STENCILENABLE] )
3338 onesided_enable = This->stateBlock->renderState[WINED3DRS_STENCILENABLE];
3339 if( This->stateBlock->set.renderState[WINED3DRS_TWOSIDEDSTENCILMODE] )
3340 twosided_enable = This->stateBlock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE];
3341 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFUNC] )
3342 if( !( func = CompareFunc(This->stateBlock->renderState[WINED3DRS_STENCILFUNC]) ) )
3343 func = GL_ALWAYS;
3344 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFUNC] )
3345 if( !( func_ccw = CompareFunc(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) )
3346 func = GL_ALWAYS;
3347 if( This->stateBlock->set.renderState[WINED3DRS_STENCILREF] )
3348 ref = This->stateBlock->renderState[WINED3DRS_STENCILREF];
3349 if( This->stateBlock->set.renderState[WINED3DRS_STENCILMASK] )
3350 mask = This->stateBlock->renderState[WINED3DRS_STENCILMASK];
3351 if( This->stateBlock->set.renderState[WINED3DRS_STENCILFAIL] )
3352 stencilFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILFAIL]);
3353 if( This->stateBlock->set.renderState[WINED3DRS_STENCILZFAIL] )
3354 depthFail = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILZFAIL]);
3355 if( This->stateBlock->set.renderState[WINED3DRS_STENCILPASS] )
3356 stencilPass = StencilOp(This->stateBlock->renderState[WINED3DRS_STENCILPASS]);
3357 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILFAIL] )
3358 stencilFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILFAIL]);
3359 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILZFAIL] )
3360 depthFail_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILZFAIL]);
3361 if( This->stateBlock->set.renderState[WINED3DRS_CCW_STENCILPASS] )
3362 stencilPass_ccw = StencilOp(This->stateBlock->renderState[WINED3DRS_CCW_STENCILPASS]);
3364 TRACE("(onesided %ld, twosided %ld, ref %x, mask %x, \
3365 GL_FRONT: func: %x, fail %x, zfail %x, zpass %x \
3366 GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n",
3367 onesided_enable, twosided_enable, ref, mask,
3368 func, stencilFail, depthFail, stencilPass,
3369 func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3371 if (twosided_enable) {
3372 renderstate_stencil_twosided(This, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass);
3373 renderstate_stencil_twosided(This, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw);
3374 } else {
3375 if (onesided_enable) {
3376 glEnable(GL_STENCIL_TEST);
3377 checkGLcall("glEnable GL_STENCIL_TEST");
3378 glStencilFunc(func, ref, mask);
3379 checkGLcall("glStencilFunc(...)");
3380 glStencilOp(stencilFail, depthFail, stencilPass);
3381 checkGLcall("glStencilOp(...)");
3382 } else {
3383 glDisable(GL_STENCIL_TEST);
3384 checkGLcall("glDisable GL_STENCIL_TEST");
3389 /*****
3390 * Get / Set Render States
3391 * TODO: Verify against dx9 definitions
3392 *****/
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD Value) {
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3396 DWORD OldValue = This->stateBlock->renderState[State];
3398 /* Simple way of referring to either a DWORD or a 4 byte float */
3399 union {
3400 DWORD d;
3401 float f;
3402 } tmpvalue;
3404 TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value);
3405 This->updateStateBlock->changed.renderState[State] = TRUE;
3406 This->updateStateBlock->set.renderState[State] = TRUE;
3407 This->updateStateBlock->renderState[State] = Value;
3409 /* Handle recording of state blocks */
3410 if (This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3412 return WINED3D_OK;
3415 ENTER_GL();
3417 switch (State) {
3418 case WINED3DRS_FILLMODE :
3419 switch ((D3DFILLMODE) Value) {
3420 case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
3421 case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
3422 case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
3423 default:
3424 FIXME("Unrecognized WINED3DRS_FILLMODE value %ld\n", Value);
3426 checkGLcall("glPolygonMode (fillmode)");
3427 break;
3429 case WINED3DRS_LIGHTING :
3430 if (Value) {
3431 glEnable(GL_LIGHTING);
3432 checkGLcall("glEnable GL_LIGHTING");
3433 } else {
3434 glDisable(GL_LIGHTING);
3435 checkGLcall("glDisable GL_LIGHTING");
3437 break;
3439 case WINED3DRS_ZENABLE :
3440 switch ((D3DZBUFFERTYPE) Value) {
3441 case D3DZB_FALSE:
3442 glDisable(GL_DEPTH_TEST);
3443 checkGLcall("glDisable GL_DEPTH_TEST");
3444 break;
3445 case D3DZB_TRUE:
3446 glEnable(GL_DEPTH_TEST);
3447 checkGLcall("glEnable GL_DEPTH_TEST");
3448 break;
3449 case D3DZB_USEW:
3450 glEnable(GL_DEPTH_TEST);
3451 checkGLcall("glEnable GL_DEPTH_TEST");
3452 FIXME("W buffer is not well handled\n");
3453 break;
3454 default:
3455 FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value);
3457 break;
3459 case WINED3DRS_CULLMODE :
3461 /* If we are culling "back faces with clockwise vertices" then
3462 set front faces to be counter clockwise and enable culling
3463 of back faces */
3464 switch ((D3DCULL) Value) {
3465 case D3DCULL_NONE:
3466 glDisable(GL_CULL_FACE);
3467 checkGLcall("glDisable GL_CULL_FACE");
3468 break;
3469 case D3DCULL_CW:
3470 glEnable(GL_CULL_FACE);
3471 checkGLcall("glEnable GL_CULL_FACE");
3472 if (This->renderUpsideDown) {
3473 glFrontFace(GL_CW);
3474 checkGLcall("glFrontFace GL_CW");
3475 } else {
3476 glFrontFace(GL_CCW);
3477 checkGLcall("glFrontFace GL_CCW");
3479 glCullFace(GL_BACK);
3480 break;
3481 case D3DCULL_CCW:
3482 glEnable(GL_CULL_FACE);
3483 checkGLcall("glEnable GL_CULL_FACE");
3484 if (This->renderUpsideDown) {
3485 glFrontFace(GL_CCW);
3486 checkGLcall("glFrontFace GL_CCW");
3487 } else {
3488 glFrontFace(GL_CW);
3489 checkGLcall("glFrontFace GL_CW");
3491 glCullFace(GL_BACK);
3492 break;
3493 default:
3494 FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value);
3496 break;
3498 case WINED3DRS_SHADEMODE :
3499 switch ((D3DSHADEMODE) Value) {
3500 case D3DSHADE_FLAT:
3501 glShadeModel(GL_FLAT);
3502 checkGLcall("glShadeModel");
3503 break;
3504 case D3DSHADE_GOURAUD:
3505 glShadeModel(GL_SMOOTH);
3506 checkGLcall("glShadeModel");
3507 break;
3508 case D3DSHADE_PHONG:
3509 FIXME("D3DSHADE_PHONG isn't supported\n");
3510 break;
3511 default:
3512 FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value);
3514 break;
3516 case WINED3DRS_DITHERENABLE :
3517 if (Value) {
3518 glEnable(GL_DITHER);
3519 checkGLcall("glEnable GL_DITHER");
3520 } else {
3521 glDisable(GL_DITHER);
3522 checkGLcall("glDisable GL_DITHER");
3524 break;
3526 case WINED3DRS_ZWRITEENABLE :
3527 if (Value) {
3528 glDepthMask(1);
3529 checkGLcall("glDepthMask");
3530 } else {
3531 glDepthMask(0);
3532 checkGLcall("glDepthMask");
3534 break;
3536 case WINED3DRS_ZFUNC :
3538 int glParm = CompareFunc(Value);
3540 if(glParm) {
3541 glDepthFunc(glParm);
3542 checkGLcall("glDepthFunc");
3545 break;
3547 case WINED3DRS_AMBIENT :
3549 float col[4];
3550 D3DCOLORTOGLFLOAT4(Value, col);
3551 TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]);
3552 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
3553 checkGLcall("glLightModel for MODEL_AMBIENT");
3556 break;
3558 case WINED3DRS_ALPHABLENDENABLE :
3559 if (Value) {
3560 glEnable(GL_BLEND);
3561 checkGLcall("glEnable GL_BLEND");
3562 } else {
3563 glDisable(GL_BLEND);
3564 checkGLcall("glDisable GL_BLEND");
3566 break;
3568 case WINED3DRS_SRCBLEND :
3569 case WINED3DRS_DESTBLEND :
3571 int newVal = GL_ZERO;
3572 switch (Value) {
3573 case D3DBLEND_ZERO : newVal = GL_ZERO; break;
3574 case D3DBLEND_ONE : newVal = GL_ONE; break;
3575 case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break;
3576 case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break;
3577 case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break;
3578 case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break;
3579 case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break;
3580 case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break;
3581 case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break;
3582 case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break;
3583 case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break;
3585 case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA;
3586 This->srcBlend = newVal;
3587 This->dstBlend = newVal;
3588 break;
3590 case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA;
3591 This->srcBlend = newVal;
3592 This->dstBlend = newVal;
3593 break;
3594 case D3DBLEND_BLENDFACTOR : newVal = GL_CONSTANT_COLOR; break;
3595 case D3DBLEND_INVBLENDFACTOR : newVal = GL_ONE_MINUS_CONSTANT_COLOR; break;
3596 default:
3597 FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State);
3600 if (State == WINED3DRS_SRCBLEND) This->srcBlend = newVal;
3601 if (State == WINED3DRS_DESTBLEND) This->dstBlend = newVal;
3602 TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend);
3603 glBlendFunc(This->srcBlend, This->dstBlend);
3605 checkGLcall("glBlendFunc");
3607 break;
3609 case WINED3DRS_ALPHATESTENABLE :
3610 case WINED3DRS_ALPHAFUNC :
3611 case WINED3DRS_ALPHAREF :
3612 case WINED3DRS_COLORKEYENABLE :
3614 int glParm = 0;
3615 float ref;
3616 BOOL enable_ckey = FALSE;
3618 IWineD3DSurfaceImpl *surf;
3620 /* Find out if the texture on the first stage has a ckey set */
3621 if(This->stateBlock->textures[0]) {
3622 surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[0])->surfaces[0];
3623 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
3626 if (This->stateBlock->renderState[WINED3DRS_ALPHATESTENABLE] ||
3627 (This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) {
3628 glEnable(GL_ALPHA_TEST);
3629 checkGLcall("glEnable GL_ALPHA_TEST");
3630 } else {
3631 glDisable(GL_ALPHA_TEST);
3632 checkGLcall("glDisable GL_ALPHA_TEST");
3633 /* Alpha test is disabled, don't bother setting the params - it will happen on the next
3634 * enable call
3636 break;
3639 if(This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) {
3640 glParm = GL_NOTEQUAL;
3641 ref = 0.0;
3642 } else {
3643 ref = ((float) This->stateBlock->renderState[WINED3DRS_ALPHAREF]) / 255.0f;
3644 glParm = CompareFunc(This->stateBlock->renderState[WINED3DRS_ALPHAFUNC]);
3646 if(glParm) {
3647 This->alphafunc = glParm;
3648 glAlphaFunc(glParm, ref);
3649 checkGLcall("glAlphaFunc");
3652 break;
3654 case WINED3DRS_CLIPPLANEENABLE :
3655 case WINED3DRS_CLIPPING :
3657 /* Ensure we only do the changed clip planes */
3658 DWORD enable = 0xFFFFFFFF;
3659 DWORD disable = 0x00000000;
3661 /* If enabling / disabling all */
3662 if (State == WINED3DRS_CLIPPING) {
3663 if (Value) {
3664 enable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3665 disable = 0x00;
3666 } else {
3667 disable = This->stateBlock->renderState[WINED3DRS_CLIPPLANEENABLE];
3668 enable = 0x00;
3670 } else {
3671 enable = Value & ~OldValue;
3672 disable = ~Value & OldValue;
3675 if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); }
3676 if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); }
3677 if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); }
3678 if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); }
3679 if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); }
3680 if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); }
3682 if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); }
3683 if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); }
3684 if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); }
3685 if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); }
3686 if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); }
3687 if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); }
3689 /** update clipping status */
3690 if (enable) {
3691 This->stateBlock->clip_status.ClipUnion = 0;
3692 This->stateBlock->clip_status.ClipIntersection = 0xFFFFFFFF;
3693 } else {
3694 This->stateBlock->clip_status.ClipUnion = 0;
3695 This->stateBlock->clip_status.ClipIntersection = 0;
3698 break;
3700 case WINED3DRS_BLENDOP :
3702 int glParm = GL_FUNC_ADD;
3704 switch ((D3DBLENDOP) Value) {
3705 case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break;
3706 case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break;
3707 case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break;
3708 case D3DBLENDOP_MIN : glParm = GL_MIN; break;
3709 case D3DBLENDOP_MAX : glParm = GL_MAX; break;
3710 default:
3711 FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value);
3714 if(GL_SUPPORT(EXT_BLEND_MINMAX)) {
3715 TRACE("glBlendEquation(%x)\n", glParm);
3716 GL_EXTCALL(glBlendEquation(glParm));
3717 checkGLcall("glBlendEquation");
3718 } else {
3719 WARN("Unsupported in local OpenGL implementation: glBlendEquation\n");
3722 break;
3724 case WINED3DRS_TEXTUREFACTOR :
3726 unsigned int i;
3728 /* Note the texture color applies to all textures whereas
3729 GL_TEXTURE_ENV_COLOR applies to active only */
3730 float col[4];
3731 D3DCOLORTOGLFLOAT4(Value, col);
3733 if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3734 /* And now the default texture color as well */
3735 for (i = 0; i < GL_LIMITS(texture_stages); i++) {
3736 /* Note the D3DRS value applies to all textures, but GL has one
3737 per texture, so apply it now ready to be used! */
3738 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
3739 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
3740 checkGLcall("glActiveTextureARB");
3741 } else if (i>0) {
3742 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
3745 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]);
3746 checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);");
3750 break;
3752 case WINED3DRS_SPECULARENABLE :
3754 /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
3755 and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled
3756 specular color. This is wrong:
3757 Separate specular color means the specular colour is maintained separately, whereas
3758 single color means it is merged in. However in both cases they are being used to
3759 some extent.
3760 To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT
3761 NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are
3762 running 1.4 yet!
3765 * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect.
3766 * Instead, we need to setup the FinalCombiner properly.
3768 * The default setup for the FinalCombiner is:
3770 * <variable> <input> <mapping> <usage>
3771 * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3772 * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB
3773 * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB
3774 * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3775 * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3776 * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB
3777 * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA
3779 * That's pretty much fine as it is, except for variable B, which needs to take
3780 * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on
3781 * whether WINED3DRS_SPECULARENABLE is enabled or not.
3784 if (Value) {
3785 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
3786 checkGLcall("glMaterialfv");
3787 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3788 glEnable(GL_COLOR_SUM_EXT);
3789 } else {
3790 TRACE("Specular colors cannot be enabled in this version of opengl\n");
3792 checkGLcall("glEnable(GL_COLOR_SUM)");
3794 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3795 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3796 checkGLcall("glFinalCombinerInputNV()");
3798 } else {
3799 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
3801 /* for the case of enabled lighting: */
3802 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
3803 checkGLcall("glMaterialfv");
3805 /* for the case of disabled lighting: */
3806 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
3807 glDisable(GL_COLOR_SUM_EXT);
3808 } else {
3809 TRACE("Specular colors cannot be disabled in this version of opengl\n");
3811 checkGLcall("glDisable(GL_COLOR_SUM)");
3813 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3814 GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB));
3815 checkGLcall("glFinalCombinerInputNV()");
3819 break;
3821 case WINED3DRS_STENCILENABLE :
3822 case WINED3DRS_TWOSIDEDSTENCILMODE :
3823 case WINED3DRS_STENCILFUNC :
3824 case WINED3DRS_CCW_STENCILFUNC :
3825 case WINED3DRS_STENCILREF :
3826 case WINED3DRS_STENCILMASK :
3827 case WINED3DRS_STENCILFAIL :
3828 case WINED3DRS_STENCILZFAIL :
3829 case WINED3DRS_STENCILPASS :
3830 case WINED3DRS_CCW_STENCILFAIL :
3831 case WINED3DRS_CCW_STENCILZFAIL :
3832 case WINED3DRS_CCW_STENCILPASS :
3833 renderstate_stencil(This, State, Value);
3834 break;
3835 case WINED3DRS_STENCILWRITEMASK :
3837 glStencilMask(Value);
3838 TRACE("glStencilMask(%lu)\n", Value);
3839 checkGLcall("glStencilMask");
3841 break;
3843 case WINED3DRS_FOGENABLE :
3845 if (Value) {
3846 glEnable(GL_FOG);
3847 checkGLcall("glEnable GL_FOG");
3848 } else {
3849 glDisable(GL_FOG);
3850 checkGLcall("glDisable GL_FOG");
3853 break;
3855 case WINED3DRS_RANGEFOGENABLE :
3857 if (Value) {
3858 TRACE("Enabled RANGEFOG\n");
3859 } else {
3860 TRACE("Disabled RANGEFOG\n");
3863 break;
3865 case WINED3DRS_FOGCOLOR :
3867 float col[4];
3868 D3DCOLORTOGLFLOAT4(Value, col);
3869 /* Set the default alpha blend color */
3870 glFogfv(GL_FOG_COLOR, &col[0]);
3871 checkGLcall("glFog GL_FOG_COLOR");
3873 break;
3875 case WINED3DRS_FOGTABLEMODE :
3876 case WINED3DRS_FOGVERTEXMODE :
3878 /* 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." */
3879 if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
3880 glHint(GL_FOG_HINT, GL_FASTEST);
3881 checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)");
3882 switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) {
3883 /* Processed vertices have their fog factor stored in the specular value. Fall too the none case.
3884 * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog
3886 case D3DFOG_EXP: {
3887 if(!This->last_was_rhw) {
3888 glFogi(GL_FOG_MODE, GL_EXP);
3889 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3890 if(GL_SUPPORT(EXT_FOG_COORD)) {
3891 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3892 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3893 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3894 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3896 break;
3899 case D3DFOG_EXP2: {
3900 if(!This->last_was_rhw) {
3901 glFogi(GL_FOG_MODE, GL_EXP2);
3902 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3903 if(GL_SUPPORT(EXT_FOG_COORD)) {
3904 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3905 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3906 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3907 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3909 break;
3912 case D3DFOG_LINEAR: {
3913 if(!This->last_was_rhw) {
3914 glFogi(GL_FOG_MODE, GL_LINEAR);
3915 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3916 if(GL_SUPPORT(EXT_FOG_COORD)) {
3917 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3918 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3919 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3920 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3922 break;
3925 case D3DFOG_NONE: {
3926 /* Both are none? According to msdn the alpha channel of the specular
3927 * color contains a fog factor. Set it in drawStridedSlow.
3928 * Same happens with Vertexfog on transformed vertices
3930 if(GL_SUPPORT(EXT_FOG_COORD)) {
3931 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
3932 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n");
3933 glFogi(GL_FOG_MODE, GL_LINEAR);
3934 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
3935 glFogf(GL_FOG_START, (float) 0xff);
3936 checkGLcall("glFogfv GL_FOG_START");
3937 glFogf(GL_FOG_END, 0.0);
3938 checkGLcall("glFogfv GL_FOG_END");
3939 } else {
3940 /* Disable GL fog, handle this in software in drawStridedSlow */
3941 glDisable(GL_FOG);
3942 checkGLcall("glDisable(GL_FOG)");
3944 break;
3946 default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]);
3948 } else {
3949 glHint(GL_FOG_HINT, GL_NICEST);
3950 checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)");
3951 switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) {
3952 case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP);
3953 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP");
3954 if(GL_SUPPORT(EXT_FOG_COORD)) {
3955 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3956 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3957 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3958 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3960 break;
3961 case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2);
3962 checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2");
3963 if(GL_SUPPORT(EXT_FOG_COORD)) {
3964 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3965 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3966 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3967 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3969 break;
3970 case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR);
3971 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR");
3972 if(GL_SUPPORT(EXT_FOG_COORD)) {
3973 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
3974 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT");
3975 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
3976 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
3978 break;
3979 case D3DFOG_NONE: /* Won't happen */
3980 default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
3983 if (GL_SUPPORT(NV_FOG_DISTANCE)) {
3984 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
3987 break;
3989 case WINED3DRS_FOGSTART :
3991 tmpvalue.d = Value;
3992 glFogfv(GL_FOG_START, &tmpvalue.f);
3993 checkGLcall("glFogf(GL_FOG_START, (float) Value)");
3994 TRACE("Fog Start == %f\n", tmpvalue.f);
3996 break;
3998 case WINED3DRS_FOGEND :
4000 tmpvalue.d = Value;
4001 glFogfv(GL_FOG_END, &tmpvalue.f);
4002 checkGLcall("glFogf(GL_FOG_END, (float) Value)");
4003 TRACE("Fog End == %f\n", tmpvalue.f);
4005 break;
4007 case WINED3DRS_FOGDENSITY :
4009 tmpvalue.d = Value;
4010 glFogfv(GL_FOG_DENSITY, &tmpvalue.f);
4011 checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)");
4013 break;
4015 case WINED3DRS_VERTEXBLEND :
4017 This->updateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value;
4018 TRACE("Vertex Blending state to %ld\n", Value);
4020 break;
4022 case WINED3DRS_TWEENFACTOR :
4024 tmpvalue.d = Value;
4025 This->updateStateBlock->tween_factor = tmpvalue.f;
4026 TRACE("Vertex Blending Tween Factor to %f\n", This->updateStateBlock->tween_factor);
4028 break;
4030 case WINED3DRS_INDEXEDVERTEXBLENDENABLE :
4032 TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value);
4034 break;
4036 case WINED3DRS_COLORVERTEX :
4037 case WINED3DRS_DIFFUSEMATERIALSOURCE :
4038 case WINED3DRS_SPECULARMATERIALSOURCE :
4039 case WINED3DRS_AMBIENTMATERIALSOURCE :
4040 case WINED3DRS_EMISSIVEMATERIALSOURCE :
4042 GLenum Parm = GL_AMBIENT_AND_DIFFUSE;
4044 if (This->stateBlock->renderState[WINED3DRS_COLORVERTEX]) {
4045 TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n",
4046 This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE],
4047 This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE],
4048 This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE],
4049 This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]);
4051 if (This->stateBlock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) {
4052 if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4053 Parm = GL_AMBIENT_AND_DIFFUSE;
4054 } else {
4055 Parm = GL_DIFFUSE;
4057 } else if (This->stateBlock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) {
4058 Parm = GL_AMBIENT;
4059 } else if (This->stateBlock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) {
4060 Parm = GL_EMISSION;
4061 } else if (This->stateBlock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) {
4062 Parm = GL_SPECULAR;
4063 } else {
4064 Parm = -1;
4067 if (Parm == -1) {
4068 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4069 } else {
4070 This->tracking_color = NEEDS_TRACKING;
4071 This->tracking_parm = Parm;
4074 } else {
4075 if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE;
4078 break;
4080 case WINED3DRS_LINEPATTERN :
4082 union {
4083 DWORD d;
4084 D3DLINEPATTERN lp;
4085 } tmppattern;
4086 tmppattern.d = Value;
4088 TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4090 if (tmppattern.lp.wRepeatFactor) {
4091 glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern);
4092 checkGLcall("glLineStipple(repeat, linepattern)");
4093 glEnable(GL_LINE_STIPPLE);
4094 checkGLcall("glEnable(GL_LINE_STIPPLE);");
4095 } else {
4096 glDisable(GL_LINE_STIPPLE);
4097 checkGLcall("glDisable(GL_LINE_STIPPLE);");
4100 break;
4102 case WINED3DRS_ZBIAS : /* D3D8 only */
4104 if (Value) {
4105 tmpvalue.d = Value;
4106 TRACE("ZBias value %f\n", tmpvalue.f);
4107 glPolygonOffset(0, -tmpvalue.f);
4108 checkGLcall("glPolygonOffset(0, -Value)");
4109 glEnable(GL_POLYGON_OFFSET_FILL);
4110 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);");
4111 glEnable(GL_POLYGON_OFFSET_LINE);
4112 checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);");
4113 glEnable(GL_POLYGON_OFFSET_POINT);
4114 checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);");
4115 } else {
4116 glDisable(GL_POLYGON_OFFSET_FILL);
4117 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);");
4118 glDisable(GL_POLYGON_OFFSET_LINE);
4119 checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);");
4120 glDisable(GL_POLYGON_OFFSET_POINT);
4121 checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);");
4124 break;
4126 case WINED3DRS_NORMALIZENORMALS :
4127 if (Value) {
4128 glEnable(GL_NORMALIZE);
4129 checkGLcall("glEnable(GL_NORMALIZE);");
4130 } else {
4131 glDisable(GL_NORMALIZE);
4132 checkGLcall("glDisable(GL_NORMALIZE);");
4134 break;
4136 case WINED3DRS_POINTSIZE :
4137 /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */
4138 tmpvalue.d = Value;
4139 TRACE("Set point size to %f\n", tmpvalue.f);
4140 glPointSize(tmpvalue.f);
4141 checkGLcall("glPointSize(...);");
4142 break;
4144 case WINED3DRS_POINTSIZE_MIN :
4145 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4146 tmpvalue.d = Value;
4147 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f);
4148 checkGLcall("glPointParameterfEXT(...);");
4149 } else {
4150 FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl\n");
4152 break;
4154 case WINED3DRS_POINTSIZE_MAX :
4155 if (GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4156 tmpvalue.d = Value;
4157 GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f);
4158 checkGLcall("glPointParameterfEXT(...);");
4159 } else {
4160 FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl\n");
4162 break;
4164 case WINED3DRS_POINTSCALE_A :
4165 case WINED3DRS_POINTSCALE_B :
4166 case WINED3DRS_POINTSCALE_C :
4167 case WINED3DRS_POINTSCALEENABLE :
4170 * POINTSCALEENABLE controls how point size value is treated. If set to
4171 * true, the point size is scaled with respect to height of viewport.
4172 * When set to false point size is in pixels.
4174 * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp
4177 /* Default values */
4178 GLfloat att[3] = {1.0f, 0.0f, 0.0f};
4181 * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f.
4182 * This means that OpenGL will clamp really small point sizes to 1.0f.
4183 * To correct for this we need to multiply by the scale factor when sizes
4184 * are less than 1.0f. scale_factor = 1.0f / point_size.
4186 GLfloat pointSize = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSIZE]);
4187 if(pointSize > 0.0f) {
4188 GLfloat scaleFactor;
4190 if(pointSize < 1.0f) {
4191 scaleFactor = pointSize * pointSize;
4192 } else {
4193 scaleFactor = 1.0f;
4196 if(This->stateBlock->renderState[WINED3DRS_POINTSCALEENABLE]) {
4197 att[0] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_A]) /
4198 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4199 att[1] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_B]) /
4200 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4201 att[2] = *((float*)&This->stateBlock->renderState[WINED3DRS_POINTSCALE_C]) /
4202 (This->stateBlock->viewport.Height * This->stateBlock->viewport.Height * scaleFactor);
4206 if(GL_SUPPORT(ARB_POINT_PARAMETERS)) {
4207 GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
4208 checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ...");
4210 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) {
4211 GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att);
4212 checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...");
4213 } else {
4214 TRACE("POINT_PARAMETERS not supported in this version of opengl\n");
4216 break;
4218 case WINED3DRS_COLORWRITEENABLE :
4220 TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n",
4221 Value & D3DCOLORWRITEENABLE_RED ? 1 : 0,
4222 Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0,
4223 Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0,
4224 Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0);
4225 glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4226 Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4227 Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4228 Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4229 checkGLcall("glColorMask(...)");
4231 break;
4233 case WINED3DRS_LOCALVIEWER :
4235 GLint state = (Value) ? 1 : 0;
4236 TRACE("Local Viewer Enable to %ul\n", (BOOL) Value);
4237 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state);
4239 break;
4241 case WINED3DRS_LASTPIXEL :
4243 if (Value) {
4244 TRACE("Last Pixel Drawing Enabled\n");
4245 } else {
4246 FIXME("Last Pixel Drawing Disabled, not handled yet\n");
4249 break;
4251 case WINED3DRS_SOFTWAREVERTEXPROCESSING :
4253 if (Value) {
4254 TRACE("Software Processing Enabled\n");
4255 } else {
4256 TRACE("Software Processing Disabled\n");
4259 break;
4261 /** not supported */
4262 case WINED3DRS_ZVISIBLE :
4264 LEAVE_GL();
4265 return WINED3DERR_INVALIDCALL;
4267 case WINED3DRS_POINTSPRITEENABLE :
4269 /* TODO: NV_POINT_SPRITE */
4270 if (!GL_SUPPORT(ARB_POINT_SPRITE)) {
4271 TRACE("Point sprites not supported\n");
4272 break;
4276 * Point sprites are always enabled. Value controls texture coordinate
4277 * replacement mode. Must be set true for point sprites to use
4278 * textures.
4280 glEnable(GL_POINT_SPRITE_ARB);
4281 checkGLcall("glEnable(GL_POINT_SPRITE_ARB)");
4283 if (Value) {
4284 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, TRUE);
4285 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, TRUE)");
4286 } else {
4287 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, FALSE);
4288 checkGLcall("glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, FALSE)");
4290 break;
4292 case WINED3DRS_EDGEANTIALIAS :
4294 if(Value) {
4295 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4296 glEnable(GL_BLEND);
4297 checkGLcall("glEnable(GL_BLEND)");
4298 glEnable(GL_LINE_SMOOTH);
4299 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4300 } else {
4301 if(!This->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) {
4302 glDisable(GL_BLEND);
4303 checkGLcall("glDisable(GL_BLEND)");
4305 glDisable(GL_LINE_SMOOTH);
4306 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4308 break;
4310 case WINED3DRS_WRAP0 :
4311 case WINED3DRS_WRAP1 :
4312 case WINED3DRS_WRAP2 :
4313 case WINED3DRS_WRAP3 :
4314 case WINED3DRS_WRAP4 :
4315 case WINED3DRS_WRAP5 :
4316 case WINED3DRS_WRAP6 :
4317 case WINED3DRS_WRAP7 :
4318 case WINED3DRS_WRAP8 :
4319 case WINED3DRS_WRAP9 :
4320 case WINED3DRS_WRAP10 :
4321 case WINED3DRS_WRAP11 :
4322 case WINED3DRS_WRAP12 :
4323 case WINED3DRS_WRAP13 :
4324 case WINED3DRS_WRAP14 :
4325 case WINED3DRS_WRAP15 :
4327 http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/
4328 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp
4329 http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp
4330 Descussion that ways to turn on WRAPing to solve an opengl conversion problem.
4331 http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248
4333 so far as I can tell, wrapping and texture-coordinate generate go hand in hand,
4336 if(Value) {
4337 ERR("(%p)->(%s,%ld) Texture wraping not yet supported\n",This, debug_d3drenderstate(State), Value);
4339 break;
4342 case WINED3DRS_MULTISAMPLEANTIALIAS :
4344 if( GL_SUPPORT(ARB_MULTISAMPLE) ) {
4345 if(Value) {
4346 glEnable(GL_MULTISAMPLE_ARB);
4347 checkGLcall("glEnable(GL_MULTISAMPLE_ARB)");
4348 } else {
4349 glDisable(GL_MULTISAMPLE_ARB);
4350 checkGLcall("glDisable(GL_MULTISAMPLE_ARB)");
4352 } else {
4353 if(Value) {
4354 ERR("Multisample antialiasing not supported by gl\n");
4357 break;
4360 case WINED3DRS_SCISSORTESTENABLE :
4362 if(Value) {
4363 glEnable(GL_SCISSOR_TEST);
4364 checkGLcall("glEnable(GL_SCISSOR_TEST)");
4365 } else {
4366 glDisable(GL_SCISSOR_TEST);
4367 checkGLcall("glDisable(GL_SCISSOR_TEST)");
4369 break;
4371 case WINED3DRS_SLOPESCALEDEPTHBIAS :
4373 if(Value) {
4374 tmpvalue.d = Value;
4375 glEnable(GL_POLYGON_OFFSET_FILL);
4376 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4377 glPolygonOffset(tmpvalue.f, *((float*)&This->stateBlock->renderState[WINED3DRS_DEPTHBIAS]));
4378 checkGLcall("glPolygonOffset(...)");
4379 } else {
4380 glDisable(GL_POLYGON_OFFSET_FILL);
4381 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4383 break;
4385 case WINED3DRS_ANTIALIASEDLINEENABLE :
4387 if(Value) {
4388 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4389 glEnable(GL_BLEND);
4390 checkGLcall("glEnable(GL_BLEND)");
4391 glEnable(GL_LINE_SMOOTH);
4392 checkGLcall("glEnable(GL_LINE_SMOOTH)");
4393 } else {
4394 glDisable(GL_BLEND);
4395 checkGLcall("glDisable(GL_BLEND)");
4396 glDisable(GL_LINE_SMOOTH);
4397 checkGLcall("glDisable(GL_LINE_SMOOTH)");
4399 break;
4401 case WINED3DRS_DEPTHBIAS :
4403 if(Value) {
4404 tmpvalue.d = Value;
4405 glEnable(GL_POLYGON_OFFSET_FILL);
4406 checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)");
4407 glPolygonOffset(*((float*)&This->stateBlock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]), tmpvalue.f);
4408 checkGLcall("glPolygonOffset(...)");
4409 } else {
4410 glDisable(GL_POLYGON_OFFSET_FILL);
4411 checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)");
4413 break;
4416 case WINED3DRS_TEXTUREPERSPECTIVE :
4418 if (Value)
4419 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4420 else
4421 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
4422 break;
4425 case WINED3DRS_STIPPLEDALPHA :
4427 if (Value)
4428 ERR(" Stippled Alpha not supported yet.\n");
4429 break;
4431 case WINED3DRS_ANTIALIAS :
4433 if (Value)
4434 ERR(" Antialias not supported yet.\n");
4435 break;
4438 case WINED3DRS_MULTISAMPLEMASK :
4440 if(0xFFFFFFFF != Value)
4441 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4442 break;
4445 case WINED3DRS_PATCHEDGESTYLE :
4447 if(D3DPATCHEDGE_DISCRETE != Value)
4448 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4449 break;
4452 case WINED3DRS_PATCHSEGMENTS :
4454 /* available in d3d8 but in d3d9 it was replaced by IDirect3DDevice9::SetNPatchMode */
4455 tmpvalue.f = 1.0f;
4456 if(tmpvalue.d != Value)
4457 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4458 break;
4461 case WINED3DRS_DEBUGMONITORTOKEN :
4463 /* Only useful for "debug builds". */
4464 if(0xbaadcafe != Value) {
4465 /* MSDN says the default is D3DDMT_ENABLE but our tests confirm 0xbaadcafe is the default. */
4466 /* MSDN says anything other than D3DDMT_ENABLE or DISABLE does not change the state,
4467 * but our tests disagree.
4468 * We do not claim to implement a debugging lib, so do not write an ERR
4470 WARN("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4472 break;
4475 case WINED3DRS_POSITIONDEGREE :
4477 if(D3DDEGREE_CUBIC != Value)
4478 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4479 break;
4482 case WINED3DRS_NORMALDEGREE :
4484 if(D3DDEGREE_LINEAR != Value)
4485 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4486 break;
4489 case WINED3DRS_MINTESSELLATIONLEVEL :
4490 case WINED3DRS_MAXTESSELLATIONLEVEL :
4491 case WINED3DRS_ADAPTIVETESS_X :
4492 case WINED3DRS_ADAPTIVETESS_Y :
4493 case WINED3DRS_ADAPTIVETESS_Z :
4494 case WINED3DRS_ADAPTIVETESS_W :
4496 if(This->stateBlock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION])
4497 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4498 else
4499 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_ENABLEADAPTIVETESSELLATION is not enabled\n", This, debug_d3drenderstate(State), Value);
4500 break;
4503 case WINED3DRS_ENABLEADAPTIVETESSELLATION:
4505 if(Value)
4506 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4507 break;
4510 case WINED3DRS_COLORWRITEENABLE1 :
4511 case WINED3DRS_COLORWRITEENABLE2 :
4512 case WINED3DRS_COLORWRITEENABLE3 :
4514 /* depends on WINED3DRS_COLORWRITEENABLE. */
4515 if(0x0000000F != Value)
4516 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4517 break;
4520 case WINED3DRS_BLENDFACTOR :
4522 float col[4];
4524 TRACE("Setting BlendFactor to %ld\n", Value);
4526 D3DCOLORTOGLFLOAT4(Value, col);
4527 if (0xFFFFFFFF != Value) {
4528 glEnable(GL_BLEND);
4529 checkGLcall("glEnable(GL_BLEND)");
4531 else {
4532 glDisable(GL_BLEND);
4533 checkGLcall("glDisable(GL_BLEND)");
4535 glBlendColor (col[0],col[1],col[2],col[3]);
4536 break;
4539 case WINED3DRS_SRGBWRITEENABLE :
4541 if(Value)
4542 ERR("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4543 break;
4546 case WINED3DRS_SEPARATEALPHABLENDENABLE :
4548 if(Value)
4549 ERR("(%p)->(%s,%ld) not yet implemented. Missing of cap D3DPMISCCAPS_SEPARATEALPHABLEND wasn't honored?\n", This, debug_d3drenderstate(State), Value);
4550 break;
4553 case WINED3DRS_SRCBLENDALPHA :
4554 case WINED3DRS_DESTBLENDALPHA :
4555 case WINED3DRS_BLENDOPALPHA :
4557 if(This->stateBlock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
4558 FIXME("(%p)->(%s,%ld) not yet implemented\n", This, debug_d3drenderstate(State), Value);
4559 else
4560 TRACE("(%p)->(%s,%ld): recording state but WINED3DRS_SEPARATEALPHABLENDENABLE is not enabled\n", This, debug_d3drenderstate(State), Value);
4561 break;
4564 default:
4565 FIXME("(%p)->(%s,%ld) unknown state\n", This, debug_d3drenderstate(State), Value);
4568 LEAVE_GL();
4570 return WINED3D_OK;
4573 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, D3DRENDERSTATETYPE State, DWORD *pValue) {
4574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 TRACE("(%p) for State %d = %ld\n", This, State, This->stateBlock->renderState[State]);
4576 *pValue = This->stateBlock->renderState[State];
4577 return WINED3D_OK;
4580 /*****
4581 * Get / Set Sampler States
4582 * TODO: Verify against dx9 definitions
4583 *****/
4585 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
4586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 * SetSampler is designed to allow for more than the standard up to 8 textures
4589 * and Geforce has stopped supporting more than 6 standard textures in openGL.
4590 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
4592 * http://developer.nvidia.com/object/General_FAQ.html#t6
4594 * There are two new settings for GForce
4595 * the sampler one:
4596 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
4597 * and the texture one:
4598 * GL_MAX_TEXTURE_COORDS_ARB.
4599 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
4600 ******************/
4601 /** NOTE: States are appled in IWineD3DBaseTextre ApplyStateChanges and IWineD3DDevice SetupTextureStates**/
4602 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
4603 FIXME("sampler %ld type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
4604 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
4605 return WINED3DERR_INVALIDCALL;
4608 TRACE("(%p) : Sampler=%ld, Type=%s(%d), Value=%ld\n", This, Sampler,
4609 debug_d3dsamplerstate(Type), Type, Value);
4610 This->updateStateBlock->samplerState[Sampler][Type] = Value;
4611 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
4612 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
4614 /* Handle recording of state blocks */
4615 if (This->isRecordingState) {
4616 TRACE("Recording... not performing anything\n");
4617 return WINED3D_OK;
4620 return WINED3D_OK;
4623 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 /** TODO: check that sampler is in range **/
4626 *Value = This->updateStateBlock->samplerState[Sampler][Type];
4627 TRACE("(%p) : Sampler %ld Type %u Returning %ld\n", This, Sampler, Type, *Value);
4629 return WINED3D_OK;
4632 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
4633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4634 ENTER_GL();
4636 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4637 TRACE("(%p)Setting new Scissor Rect to %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4638 glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top);
4639 LEAVE_GL();
4641 return WINED3D_OK;
4644 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
4645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4646 GLint scissorBox[4];
4648 ENTER_GL();
4649 /** FIXME: Windows uses a top,left origin openGL uses a bottom Right? **/
4650 glGetIntegerv(GL_SCISSOR_BOX, scissorBox);
4651 pRect->left = scissorBox[0];
4652 pRect->top = scissorBox[1];
4653 pRect->right = scissorBox[0] + scissorBox[2];
4654 pRect->bottom = scissorBox[1] + scissorBox[3];
4655 TRACE("(%p)Returning a Scissor Rect of %ld:%ld-%ld:%ld\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
4656 LEAVE_GL();
4657 return WINED3D_OK;
4660 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4662 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
4664 TRACE("(%p) : pDecl=%p\n", This, pDecl);
4666 This->updateStateBlock->vertexDecl = pDecl;
4667 This->updateStateBlock->changed.vertexDecl = TRUE;
4668 This->updateStateBlock->set.vertexDecl = TRUE;
4670 if (This->isRecordingState) {
4671 TRACE("Recording... not performing anything\n");
4674 if (NULL != pDecl) {
4675 IWineD3DVertexDeclaration_AddRef(pDecl);
4677 if (NULL != oldDecl) {
4678 IWineD3DVertexDeclaration_Release(oldDecl);
4680 return WINED3D_OK;
4683 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
4688 *ppDecl = This->stateBlock->vertexDecl;
4689 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
4690 return WINED3D_OK;
4693 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
4697 This->updateStateBlock->vertexShader = pShader;
4698 This->updateStateBlock->changed.vertexShader = TRUE;
4699 This->updateStateBlock->set.vertexShader = TRUE;
4701 if (This->isRecordingState) {
4702 TRACE("Recording... not performing anything\n");
4705 if (NULL != pShader) {
4706 IWineD3DVertexShader_AddRef(pShader);
4708 if (NULL != oldShader) {
4709 IWineD3DVertexShader_Release(oldShader);
4712 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4714 * TODO: merge HAL shaders context switching from prototype
4716 return WINED3D_OK;
4719 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
4720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 if (NULL == ppShader) {
4723 return WINED3DERR_INVALIDCALL;
4725 *ppShader = This->stateBlock->vertexShader;
4726 if( NULL != *ppShader)
4727 IWineD3DVertexShader_AddRef(*ppShader);
4729 TRACE("(%p) : returning %p\n", This, *ppShader);
4730 return WINED3D_OK;
4733 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
4734 IWineD3DDevice *iface,
4735 UINT start,
4736 CONST BOOL *srcData,
4737 UINT count) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 int i, cnt = min(count, MAX_CONST_B - start);
4742 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4743 iface, srcData, start, count);
4745 if (srcData == NULL || cnt < 0)
4746 return WINED3DERR_INVALIDCALL;
4748 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4749 for (i = 0; i < cnt; i++)
4750 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4752 for (i = start; i < cnt + start; ++i) {
4753 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
4754 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
4757 return WINED3D_OK;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4761 IWineD3DDevice *iface,
4762 UINT start,
4763 BOOL *dstData,
4764 UINT count) {
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 int cnt = min(count, MAX_CONST_B - start);
4769 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4770 iface, dstData, start, count);
4772 if (dstData == NULL || cnt < 0)
4773 return WINED3DERR_INVALIDCALL;
4775 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4776 return WINED3D_OK;
4779 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4780 IWineD3DDevice *iface,
4781 UINT start,
4782 CONST int *srcData,
4783 UINT count) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 int i, cnt = min(count, MAX_CONST_I - start);
4788 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4789 iface, srcData, start, count);
4791 if (srcData == NULL || cnt < 0)
4792 return WINED3DERR_INVALIDCALL;
4794 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4795 for (i = 0; i < cnt; i++)
4796 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4797 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4799 for (i = start; i < cnt + start; ++i) {
4800 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
4801 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
4804 return WINED3D_OK;
4807 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4808 IWineD3DDevice *iface,
4809 UINT start,
4810 int *dstData,
4811 UINT count) {
4813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4814 int cnt = min(count, MAX_CONST_I - start);
4816 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4817 iface, dstData, start, count);
4819 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4820 return WINED3DERR_INVALIDCALL;
4822 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4823 return WINED3D_OK;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4827 IWineD3DDevice *iface,
4828 UINT start,
4829 CONST float *srcData,
4830 UINT count) {
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4835 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4836 iface, srcData, start, count);
4838 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
4839 return WINED3DERR_INVALIDCALL;
4841 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
4842 for (i = 0; i < cnt; i++)
4843 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4844 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4846 for (i = start; i < cnt + start; ++i) {
4847 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
4848 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
4849 ptr->idx = i;
4850 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
4851 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
4853 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
4856 return WINED3D_OK;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4860 IWineD3DDevice *iface,
4861 UINT start,
4862 float *dstData,
4863 UINT count) {
4865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4866 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4868 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4869 iface, dstData, start, count);
4871 if (dstData == NULL || cnt < 0)
4872 return WINED3DERR_INVALIDCALL;
4874 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4875 return WINED3D_OK;
4878 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4881 This->updateStateBlock->pixelShader = pShader;
4882 This->updateStateBlock->changed.pixelShader = TRUE;
4883 This->updateStateBlock->set.pixelShader = TRUE;
4885 /* Handle recording of state blocks */
4886 if (This->isRecordingState) {
4887 TRACE("Recording... not performing anything\n");
4890 if (NULL != pShader) {
4891 IWineD3DPixelShader_AddRef(pShader);
4893 if (NULL != oldShader) {
4894 IWineD3DPixelShader_Release(oldShader);
4897 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4899 * TODO: merge HAL shaders context switching from prototype
4901 return WINED3D_OK;
4904 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 if (NULL == ppShader) {
4908 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4909 return WINED3DERR_INVALIDCALL;
4912 *ppShader = This->stateBlock->pixelShader;
4913 if (NULL != *ppShader) {
4914 IWineD3DPixelShader_AddRef(*ppShader);
4916 TRACE("(%p) : returning %p\n", This, *ppShader);
4917 return WINED3D_OK;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4921 IWineD3DDevice *iface,
4922 UINT start,
4923 CONST BOOL *srcData,
4924 UINT count) {
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 int i, cnt = min(count, MAX_CONST_B - start);
4929 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4930 iface, srcData, start, count);
4932 if (srcData == NULL || cnt < 0)
4933 return WINED3DERR_INVALIDCALL;
4935 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4936 for (i = 0; i < cnt; i++)
4937 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4939 for (i = start; i < cnt + start; ++i) {
4940 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
4941 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
4944 return WINED3D_OK;
4947 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4948 IWineD3DDevice *iface,
4949 UINT start,
4950 BOOL *dstData,
4951 UINT count) {
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 int cnt = min(count, MAX_CONST_B - start);
4956 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4957 iface, dstData, start, count);
4959 if (dstData == NULL || cnt < 0)
4960 return WINED3DERR_INVALIDCALL;
4962 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4963 return WINED3D_OK;
4966 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4967 IWineD3DDevice *iface,
4968 UINT start,
4969 CONST int *srcData,
4970 UINT count) {
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 int i, cnt = min(count, MAX_CONST_I - start);
4975 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4976 iface, srcData, start, count);
4978 if (srcData == NULL || cnt < 0)
4979 return WINED3DERR_INVALIDCALL;
4981 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4982 for (i = 0; i < cnt; i++)
4983 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4984 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4986 for (i = start; i < cnt + start; ++i) {
4987 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4988 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
4991 return WINED3D_OK;
4994 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4995 IWineD3DDevice *iface,
4996 UINT start,
4997 int *dstData,
4998 UINT count) {
5000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5001 int cnt = min(count, MAX_CONST_I - start);
5003 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5004 iface, dstData, start, count);
5006 if (dstData == NULL || cnt < 0)
5007 return WINED3DERR_INVALIDCALL;
5009 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
5010 return WINED3D_OK;
5013 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
5014 IWineD3DDevice *iface,
5015 UINT start,
5016 CONST float *srcData,
5017 UINT count) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5022 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
5023 iface, srcData, start, count);
5025 if (srcData == NULL || cnt < 0)
5026 return WINED3DERR_INVALIDCALL;
5028 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
5029 for (i = 0; i < cnt; i++)
5030 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
5031 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
5033 for (i = start; i < cnt + start; ++i) {
5034 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
5035 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
5036 ptr->idx = i;
5037 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
5038 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
5040 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
5043 return WINED3D_OK;
5046 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
5047 IWineD3DDevice *iface,
5048 UINT start,
5049 float *dstData,
5050 UINT count) {
5052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
5055 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
5056 iface, dstData, start, count);
5058 if (dstData == NULL || cnt < 0)
5059 return WINED3DERR_INVALIDCALL;
5061 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
5062 return WINED3D_OK;
5065 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
5066 static HRESULT
5067 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
5068 char *dest_ptr, *dest_conv = NULL;
5069 unsigned int i;
5070 DWORD DestFVF = dest->fvf;
5071 D3DVIEWPORT9 vp;
5072 D3DMATRIX mat, proj_mat, view_mat, world_mat;
5073 BOOL doClip;
5074 int numTextures;
5076 if (SrcFVF & D3DFVF_NORMAL) {
5077 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
5080 if ( (SrcFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
5081 ERR("Source has no position mask\n");
5082 return WINED3DERR_INVALIDCALL;
5085 /* We might access VBOs from this code, so hold the lock */
5086 ENTER_GL();
5088 if (dest->resource.allocatedMemory == NULL) {
5089 /* This may happen if we do direct locking into a vbo. Unlikely,
5090 * but theoretically possible(ddraw processvertices test)
5092 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
5093 if(!dest->resource.allocatedMemory) {
5094 LEAVE_GL();
5095 ERR("Out of memory\n");
5096 return E_OUTOFMEMORY;
5098 if(dest->vbo) {
5099 void *src;
5100 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5101 checkGLcall("glBindBufferARB");
5102 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5103 if(src) {
5104 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
5106 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5107 checkGLcall("glUnmapBufferARB");
5111 /* Get a pointer into the destination vbo(create one if none exists) and
5112 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
5114 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
5115 CreateVBO(dest);
5118 if(dest->vbo) {
5119 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
5120 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
5121 if(!dest_conv) {
5122 ERR("glMapBuffer failed\n");
5123 /* Continue without storing converted vertices */
5127 /* Should I clip?
5128 * a) D3DRS_CLIPPING is enabled
5129 * b) WINED3DVOP_CLIP is passed
5131 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
5132 static BOOL warned = FALSE;
5134 * The clipping code is not quite correct. Some things need
5135 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
5136 * so disable clipping for now.
5137 * (The graphics in Half-Life are broken, and my processvertices
5138 * test crashes with IDirect3DDevice3)
5139 doClip = TRUE;
5141 doClip = FALSE;
5142 if(!warned) {
5143 warned = TRUE;
5144 FIXME("Clipping is broken and disabled for now\n");
5146 } else doClip = FALSE;
5147 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5148 if(dest_conv) {
5149 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
5152 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5153 WINED3DTS_VIEW,
5154 &view_mat);
5155 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5156 WINED3DTS_PROJECTION,
5157 &proj_mat);
5158 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
5159 WINED3DTS_WORLDMATRIX(0),
5160 &world_mat);
5162 TRACE("View mat:\n");
5163 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); \
5164 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); \
5165 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); \
5166 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); \
5168 TRACE("Proj mat:\n");
5169 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); \
5170 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); \
5171 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); \
5172 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); \
5174 TRACE("World mat:\n");
5175 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); \
5176 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); \
5177 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); \
5178 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); \
5180 /* Get the viewport */
5181 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
5182 TRACE("Viewport: X=%ld, Y=%ld, Width=%ld, Height=%ld, MinZ=%f, MaxZ=%f\n",
5183 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
5185 multiply_matrix(&mat,&view_mat,&world_mat);
5186 multiply_matrix(&mat,&proj_mat,&mat);
5188 numTextures = (DestFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
5190 for (i = 0; i < dwCount; i+= 1) {
5191 unsigned int tex_index;
5193 if ( ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ ) ||
5194 ((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW ) ) {
5195 /* The position first */
5196 float *p =
5197 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
5198 float x, y, z, rhw;
5199 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
5201 /* Multiplication with world, view and projection matrix */
5202 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);
5203 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);
5204 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);
5205 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);
5207 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
5209 /* WARNING: The following things are taken from d3d7 and were not yet checked
5210 * against d3d8 or d3d9!
5213 /* Clipping conditions: From
5214 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
5216 * A vertex is clipped if it does not match the following requirements
5217 * -rhw < x <= rhw
5218 * -rhw < y <= rhw
5219 * 0 < z <= rhw
5220 * 0 < rhw ( Not in d3d7, but tested in d3d7)
5222 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
5223 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
5227 if( !doClip ||
5228 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
5229 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
5230 ( rhw > eps ) ) ) {
5232 /* "Normal" viewport transformation (not clipped)
5233 * 1) The values are divided by rhw
5234 * 2) The y axis is negative, so multiply it with -1
5235 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
5236 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
5237 * 4) Multiply x with Width/2 and add Width/2
5238 * 5) The same for the height
5239 * 6) Add the viewpoint X and Y to the 2D coordinates and
5240 * The minimum Z value to z
5241 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
5243 * Well, basically it's simply a linear transformation into viewport
5244 * coordinates
5247 x /= rhw;
5248 y /= rhw;
5249 z /= rhw;
5251 y *= -1;
5253 x *= vp.Width / 2;
5254 y *= vp.Height / 2;
5255 z *= vp.MaxZ - vp.MinZ;
5257 x += vp.Width / 2 + vp.X;
5258 y += vp.Height / 2 + vp.Y;
5259 z += vp.MinZ;
5261 rhw = 1 / rhw;
5262 } else {
5263 /* That vertex got clipped
5264 * Contrary to OpenGL it is not dropped completely, it just
5265 * undergoes a different calculation.
5267 TRACE("Vertex got clipped\n");
5268 x += rhw;
5269 y += rhw;
5271 x /= 2;
5272 y /= 2;
5274 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
5275 * outside of the main vertex buffer memory. That needs some more
5276 * investigation...
5280 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
5283 ( (float *) dest_ptr)[0] = x;
5284 ( (float *) dest_ptr)[1] = y;
5285 ( (float *) dest_ptr)[2] = z;
5286 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
5288 dest_ptr += 3 * sizeof(float);
5290 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5291 dest_ptr += sizeof(float);
5294 if(dest_conv) {
5295 float w = 1 / rhw;
5296 ( (float *) dest_conv)[0] = x * w;
5297 ( (float *) dest_conv)[1] = y * w;
5298 ( (float *) dest_conv)[2] = z * w;
5299 ( (float *) dest_conv)[3] = w;
5301 dest_conv += 3 * sizeof(float);
5303 if((DestFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
5304 dest_conv += sizeof(float);
5308 if (DestFVF & D3DFVF_PSIZE) {
5309 dest_ptr += sizeof(DWORD);
5310 if(dest_conv) dest_conv += sizeof(DWORD);
5312 if (DestFVF & D3DFVF_NORMAL) {
5313 float *normal =
5314 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
5315 /* AFAIK this should go into the lighting information */
5316 FIXME("Didn't expect the destination to have a normal\n");
5317 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
5318 if(dest_conv) {
5319 copy_and_next(dest_conv, normal, 3 * sizeof(float));
5323 if (DestFVF & D3DFVF_DIFFUSE) {
5324 DWORD *color_d =
5325 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
5326 if(!color_d) {
5327 static BOOL warned = FALSE;
5329 if(!warned) {
5330 ERR("No diffuse color in source, but destination has one\n");
5331 warned = TRUE;
5334 *( (DWORD *) dest_ptr) = 0xffffffff;
5335 dest_ptr += sizeof(DWORD);
5337 if(dest_conv) {
5338 *( (DWORD *) dest_conv) = 0xffffffff;
5339 dest_conv += sizeof(DWORD);
5342 else {
5343 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
5344 if(dest_conv) {
5345 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
5346 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
5347 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
5348 dest_conv += sizeof(DWORD);
5353 if (DestFVF & D3DFVF_SPECULAR) {
5354 /* What's the color value in the feedback buffer? */
5355 DWORD *color_s =
5356 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
5357 if(!color_s) {
5358 static BOOL warned = FALSE;
5360 if(!warned) {
5361 ERR("No specular color in source, but destination has one\n");
5362 warned = TRUE;
5365 *( (DWORD *) dest_ptr) = 0xFF000000;
5366 dest_ptr += sizeof(DWORD);
5368 if(dest_conv) {
5369 *( (DWORD *) dest_conv) = 0xFF000000;
5370 dest_conv += sizeof(DWORD);
5373 else {
5374 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
5375 if(dest_conv) {
5376 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
5377 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
5378 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
5379 dest_conv += sizeof(DWORD);
5384 for (tex_index = 0; tex_index < numTextures; tex_index++) {
5385 float *tex_coord =
5386 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
5387 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
5388 if(!tex_coord) {
5389 ERR("No source texture, but destination requests one\n");
5390 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5391 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
5393 else {
5394 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5395 if(dest_conv) {
5396 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
5402 if(dest_conv) {
5403 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5404 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
5407 LEAVE_GL();
5409 return WINED3D_OK;
5411 #undef copy_and_next
5413 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5415 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
5416 WineDirect3DVertexStridedData strided;
5417 TRACE("(%p)->(%d,%d,%d,%p,%p,%ld\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
5419 if (!SrcImpl) {
5420 WARN("NULL source vertex buffer\n");
5421 return WINED3DERR_INVALIDCALL;
5423 /* We don't need the source vbo because this buffer is only used as
5424 * a source for ProcessVertices. Avoid wasting resources by converting the
5425 * buffer and loading the VBO
5427 if(SrcImpl->vbo) {
5428 TRACE("Releaseing the source vbo, it won't be needed\n");
5430 if(!SrcImpl->resource.allocatedMemory) {
5431 /* Rescue the data from the buffer */
5432 void *src;
5433 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
5434 if(!SrcImpl->resource.allocatedMemory) {
5435 ERR("Out of memory\n");
5436 return E_OUTOFMEMORY;
5439 ENTER_GL();
5440 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
5441 checkGLcall("glBindBufferARB");
5443 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
5444 if(src) {
5445 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
5448 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
5449 checkGLcall("glUnmapBufferARB");
5450 } else {
5451 ENTER_GL();
5454 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
5455 checkGLcall("glBindBufferARB");
5456 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
5457 checkGLcall("glDeleteBuffersARB");
5458 LEAVE_GL();
5460 SrcImpl->vbo = 0;
5463 memset(&strided, 0, sizeof(strided));
5464 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0);
5466 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
5469 /*****
5470 * Apply / Get / Set Texture Stage States
5471 * TODO: Verify against dx9 definitions
5472 *****/
5474 /* 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 */
5475 static void WINAPI IWineD3DDeviceImpl_ApplyTextureUnitState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type) {
5476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5477 DWORD Value = This->updateStateBlock->textureState[Stage][Type];
5478 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5480 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5482 /* Check that the stage is within limits */
5483 if (Stage >= GL_LIMITS(texture_stages) || Stage < 0) {
5484 TRACE("Attempt to access invalid texture rejected\n");
5485 return;
5488 ENTER_GL();
5490 switch (Type) {
5491 case WINED3DTSS_ALPHAOP :
5492 case WINED3DTSS_COLOROP :
5493 /* nothing to do as moved to drawprim for now */
5494 break;
5495 case WINED3DTSS_ADDRESSW :
5496 #if 0 /* I'm not sure what D3D does about ADDRESSW appearing twice */
5497 if (Value < minLookup[WINELOOKUP_WARPPARAM] || Value > maxLookup[WINELOOKUP_WARPPARAM]) {
5498 FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type);
5500 } else {
5501 GLint wrapParm = stateLookup[WINELOOKUP_WARPPARAM][Value - minLookup[WINELOOKUP_WARPPARAM]];
5502 TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->stateBlock->textureDimensions[Stage]);
5503 glTexParameteri(This->stateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm);
5504 checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)");
5506 #endif
5507 case WINED3DTSS_TEXCOORDINDEX :
5509 /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */
5511 /* FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include
5512 one flag, you can still specify an index value, which the system uses to
5513 determine the texture wrapping mode.
5514 eg. SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1 );
5515 means use the vertex position (camera-space) as the input texture coordinates
5516 for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render
5517 state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up
5518 to the TEXCOORDINDEX value */
5521 * Be careful the value of the mask 0xF0000 come from d3d8types.h infos
5523 switch (Value & 0xFFFF0000) {
5524 case D3DTSS_TCI_PASSTHRU:
5525 /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/
5526 glDisable(GL_TEXTURE_GEN_S);
5527 glDisable(GL_TEXTURE_GEN_T);
5528 glDisable(GL_TEXTURE_GEN_R);
5529 glDisable(GL_TEXTURE_GEN_Q);
5530 checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)");
5531 break;
5533 case D3DTSS_TCI_CAMERASPACEPOSITION:
5534 /* CameraSpacePosition means use the vertex position, transformed to camera space,
5535 as the input texture coordinates for this stage's texture transformation. This
5536 equates roughly to EYE_LINEAR */
5538 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5539 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5540 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5541 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5542 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n");
5544 glMatrixMode(GL_MODELVIEW);
5545 glPushMatrix();
5546 glLoadIdentity();
5547 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5548 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5549 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5550 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5551 glPopMatrix();
5553 TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n");
5554 glEnable(GL_TEXTURE_GEN_S);
5555 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5556 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5557 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5558 glEnable(GL_TEXTURE_GEN_T);
5559 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5560 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5561 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5562 glEnable(GL_TEXTURE_GEN_R);
5563 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5564 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
5565 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)");
5567 break;
5569 case D3DTSS_TCI_CAMERASPACENORMAL:
5571 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5572 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5573 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5574 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5575 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5576 TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n");
5578 glMatrixMode(GL_MODELVIEW);
5579 glPushMatrix();
5580 glLoadIdentity();
5581 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5582 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5583 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5584 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5585 glPopMatrix();
5587 glEnable(GL_TEXTURE_GEN_S);
5588 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5589 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5590 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5591 glEnable(GL_TEXTURE_GEN_T);
5592 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5593 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5594 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5595 glEnable(GL_TEXTURE_GEN_R);
5596 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5597 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV);
5598 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)");
5601 break;
5603 case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
5605 if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) {
5606 float s_plane[] = { 1.0, 0.0, 0.0, 0.0 };
5607 float t_plane[] = { 0.0, 1.0, 0.0, 0.0 };
5608 float r_plane[] = { 0.0, 0.0, 1.0, 0.0 };
5609 float q_plane[] = { 0.0, 0.0, 0.0, 1.0 };
5610 TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n");
5612 glMatrixMode(GL_MODELVIEW);
5613 glPushMatrix();
5614 glLoadIdentity();
5615 glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);
5616 glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);
5617 glTexGenfv(GL_R, GL_EYE_PLANE, r_plane);
5618 glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane);
5619 glPopMatrix();
5621 glEnable(GL_TEXTURE_GEN_S);
5622 checkGLcall("glEnable(GL_TEXTURE_GEN_S);");
5623 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5624 checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5625 glEnable(GL_TEXTURE_GEN_T);
5626 checkGLcall("glEnable(GL_TEXTURE_GEN_T);");
5627 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5628 checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5629 glEnable(GL_TEXTURE_GEN_R);
5630 checkGLcall("glEnable(GL_TEXTURE_GEN_R);");
5631 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
5632 checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)");
5635 break;
5637 /* Unhandled types: */
5638 default:
5639 /* Todo: */
5640 /* ? disable GL_TEXTURE_GEN_n ? */
5641 glDisable(GL_TEXTURE_GEN_S);
5642 glDisable(GL_TEXTURE_GEN_T);
5643 glDisable(GL_TEXTURE_GEN_R);
5644 glDisable(GL_TEXTURE_GEN_Q);
5645 FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %lx\n", Value);
5646 break;
5649 break;
5651 /* Unhandled */
5652 case WINED3DTSS_TEXTURETRANSFORMFLAGS :
5653 set_texture_matrix((float *)&This->stateBlock->transforms[WINED3DTS_TEXTURE0 + Stage].u.m[0][0], Value, (This->stateBlock->textureState[Stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU);
5654 break;
5656 case WINED3DTSS_BUMPENVMAT00 :
5657 case WINED3DTSS_BUMPENVMAT01 :
5658 TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT00, Stage, Type, Value);
5659 break;
5660 case WINED3DTSS_BUMPENVMAT10 :
5661 case WINED3DTSS_BUMPENVMAT11 :
5662 TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - WINED3DTSS_BUMPENVMAT10, Stage, Type, Value);
5663 break;
5665 case WINED3DTSS_BUMPENVLSCALE :
5666 TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5667 break;
5669 case WINED3DTSS_BUMPENVLOFFSET :
5670 TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5671 break;
5673 case WINED3DTSS_RESULTARG :
5674 TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5675 break;
5677 default:
5678 /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */
5679 TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value);
5682 LEAVE_GL();
5684 return;
5687 /*****
5688 * Get / Set Texture Stage States
5689 * TODO: Verify against dx9 definitions
5690 *****/
5691 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5694 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
5696 TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
5698 /* Reject invalid texture units */
5699 if (Stage >= GL_LIMITS(texture_stages)) {
5700 TRACE("Attempt to access invalid texture rejected\n");
5701 return WINED3DERR_INVALIDCALL;
5704 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
5705 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
5706 This->updateStateBlock->textureState[Stage][Type] = Value;
5708 return WINED3D_OK;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
5714 *pValue = This->updateStateBlock->textureState[Stage][Type];
5715 return WINED3D_OK;
5718 /*****
5719 * Get / Set Texture
5720 *****/
5721 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 IWineD3DBaseTexture *oldTexture;
5726 oldTexture = This->updateStateBlock->textures[Stage];
5727 TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture);
5729 #if 0 /* TODO: check so vertex textures */
5730 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
5731 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
5732 return WINED3D_OK;
5734 #endif
5736 /* Reject invalid texture units */
5737 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
5738 WARN("Attempt to access invalid texture rejected\n");
5739 return WINED3DERR_INVALIDCALL;
5742 if(pTexture != NULL) {
5743 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
5745 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
5746 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5747 return WINED3DERR_INVALIDCALL;
5751 oldTexture = This->updateStateBlock->textures[Stage];
5752 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5753 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5755 This->updateStateBlock->set.textures[Stage] = TRUE;
5756 This->updateStateBlock->changed.textures[Stage] = TRUE;
5757 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5758 This->updateStateBlock->textures[Stage] = pTexture;
5760 /* Handle recording of state blocks */
5761 if (This->isRecordingState) {
5762 TRACE("Recording... not performing anything\n");
5763 return WINED3D_OK;
5766 /** NOTE: MSDN says that setTexture increases the reference count,
5767 * and the the application nust set the texture back to null (or have a leaky application),
5768 * This means we should pass the refcount up to the parent
5769 *******************************/
5770 if (NULL != This->updateStateBlock->textures[Stage]) {
5771 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5774 if (NULL != oldTexture) {
5775 IWineD3DBaseTexture_Release(oldTexture);
5778 /* Reset color keying */
5779 if(Stage == 0 && This->stateBlock->renderState[WINED3DRS_COLORKEYENABLE]) {
5780 BOOL enable_ckey = FALSE;
5782 if(pTexture) {
5783 IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)pTexture)->surfaces[0];
5784 if(surf->CKeyFlags & DDSD_CKSRCBLT) enable_ckey = TRUE;
5787 if(enable_ckey) {
5788 glAlphaFunc(GL_NOTEQUAL, 0.0);
5789 checkGLcall("glAlphaFunc");
5793 return WINED3D_OK;
5796 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5798 TRACE("(%p) : (%ld /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
5800 /* Reject invalid texture units */
5801 if (Stage >= GL_LIMITS(sampler_stages)) {
5802 TRACE("Attempt to access invalid texture rejected\n");
5803 return WINED3DERR_INVALIDCALL;
5805 *ppTexture=This->updateStateBlock->textures[Stage];
5806 if (*ppTexture)
5807 IWineD3DBaseTexture_AddRef(*ppTexture);
5808 else
5809 return WINED3DERR_INVALIDCALL;
5810 return WINED3D_OK;
5813 /*****
5814 * Get Back Buffer
5815 *****/
5816 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5817 IWineD3DSurface **ppBackBuffer) {
5818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5819 IWineD3DSwapChain *swapChain;
5820 HRESULT hr;
5822 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5824 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5825 if (hr == WINED3D_OK) {
5826 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5827 IWineD3DSwapChain_Release(swapChain);
5828 } else {
5829 *ppBackBuffer = NULL;
5831 return hr;
5834 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5836 WARN("(%p) : stub, calling idirect3d for now\n", This);
5837 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5840 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 IWineD3DSwapChain *swapChain;
5843 HRESULT hr;
5845 if(iSwapChain > 0) {
5846 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5847 if (hr == WINED3D_OK) {
5848 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5849 IWineD3DSwapChain_Release(swapChain);
5850 } else {
5851 FIXME("(%p) Error getting display mode\n", This);
5853 } else {
5854 /* Don't read the real display mode,
5855 but return the stored mode instead. X11 can't change the color
5856 depth, and some apps are pretty angry if they SetDisplayMode from
5857 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5859 Also don't relay to the swapchain because with ddraw it's possible
5860 that there isn't a swapchain at all */
5861 pMode->Width = This->ddraw_width;
5862 pMode->Height = This->ddraw_height;
5863 pMode->Format = This->ddraw_format;
5864 pMode->RefreshRate = 0;
5865 hr = WINED3D_OK;
5868 return hr;
5871 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
5872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5873 TRACE("(%p)->(%p)\n", This, hWnd);
5875 This->ddraw_window = hWnd;
5876 return WINED3D_OK;
5879 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
5880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5881 TRACE("(%p)->(%p)\n", This, hWnd);
5883 *hWnd = This->ddraw_window;
5884 return WINED3D_OK;
5887 /*****
5888 * Stateblock related functions
5889 *****/
5891 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5893 IWineD3DStateBlockImpl *object;
5894 HRESULT temp_result;
5896 TRACE("(%p)", This);
5898 if (This->isRecordingState) {
5899 return WINED3DERR_INVALIDCALL;
5902 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
5903 if (NULL == object ) {
5904 FIXME("(%p)Error allocating memory for stateblock\n", This);
5905 return E_OUTOFMEMORY;
5907 TRACE("(%p) created object %p\n", This, object);
5908 object->wineD3DDevice= This;
5909 /** FIXME: object->parent = parent; **/
5910 object->parent = NULL;
5911 object->blockType = WINED3DSBT_ALL;
5912 object->ref = 1;
5913 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
5915 temp_result = allocate_shader_constants(object);
5916 if (WINED3D_OK != temp_result)
5917 return temp_result;
5919 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5920 This->updateStateBlock = object;
5921 This->isRecordingState = TRUE;
5923 TRACE("(%p) recording stateblock %p\n",This , object);
5924 return WINED3D_OK;
5927 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 if (!This->isRecordingState) {
5931 FIXME("(%p) not recording! returning error\n", This);
5932 *ppStateBlock = NULL;
5933 return WINED3DERR_INVALIDCALL;
5936 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
5937 This->isRecordingState = FALSE;
5938 This->updateStateBlock = This->stateBlock;
5939 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5940 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5941 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5942 return WINED3D_OK;
5945 /*****
5946 * Scene related functions
5947 *****/
5948 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5949 /* At the moment we have no need for any functionality at the beginning
5950 of a scene */
5951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5952 TRACE("(%p) : stub\n", This);
5953 return WINED3D_OK;
5956 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5958 TRACE("(%p)\n", This);
5959 ENTER_GL();
5960 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5961 glFlush();
5962 checkGLcall("glFlush");
5964 TRACE("End Scene\n");
5965 if(This->renderTarget != NULL) {
5967 /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
5968 IUnknown *targetContainer = NULL;
5969 if (WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DBaseTexture, (void **)&targetContainer)
5970 || WINED3D_OK == IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DDevice, (void **)&targetContainer)) {
5971 TRACE("(%p) : Texture rendertarget %p\n", This ,This->renderTarget);
5972 /** always dirtify for now. we must find a better way to see that surface have been modified
5973 (Modifications should will only occur via draw-primitive, but we do need better locking
5974 switching to render-to-texture should remove the overhead though.
5976 IWineD3DSurface_SetPBufferState(This->renderTarget, TRUE /* inPBuffer */, FALSE /* inTexture */);
5977 IWineD3DSurface_AddDirtyRect(This->renderTarget, NULL);
5978 IWineD3DSurface_PreLoad(This->renderTarget);
5979 IWineD3DSurface_SetPBufferState(This->renderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
5980 IUnknown_Release(targetContainer);
5983 This->sceneEnded = TRUE;
5984 LEAVE_GL();
5985 return WINED3D_OK;
5988 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5989 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5990 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5992 IWineD3DSwapChain *swapChain = NULL;
5993 int i;
5994 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5996 TRACE("(%p) Presenting the frame\n", This);
5998 for(i = 0 ; i < swapchains ; i ++) {
6000 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
6001 TRACE("presentinng chain %d, %p\n", i, swapChain);
6002 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
6003 IWineD3DSwapChain_Release(swapChain);
6006 return WINED3D_OK;
6009 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST D3DRECT* pRects,
6010 DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6013 /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the
6014 render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag
6015 when the depth-buffer format does not contain stencil buffer information, this method fails. */
6016 GLbitfield glMask = 0;
6017 GLboolean old_ztest;
6018 GLfloat old_z_clear_value;
6019 GLint old_stencil_clear_value;
6020 GLfloat old_color_clear_value[4];
6021 unsigned int i;
6022 CONST D3DRECT* curRect;
6024 TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This,
6025 Count, pRects, Flags, Z, Stencil);
6027 ENTER_GL();
6029 glEnable(GL_SCISSOR_TEST);
6030 checkGLcall("glEnable GL_SCISSOR_TEST");
6032 if (Count > 0 && pRects) {
6033 curRect = pRects;
6034 } else {
6035 curRect = NULL;
6038 /* Only set the values up once, as they are not changing */
6039 if (Flags & D3DCLEAR_STENCIL) {
6040 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
6041 glClearStencil(Stencil);
6042 checkGLcall("glClearStencil");
6043 glMask = glMask | GL_STENCIL_BUFFER_BIT;
6044 glStencilMask(0xFFFFFFFF);
6047 if (Flags & D3DCLEAR_ZBUFFER) {
6048 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
6049 glDepthMask(GL_TRUE);
6050 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
6051 glClearDepth(Z);
6052 checkGLcall("glClearDepth");
6053 glMask = glMask | GL_DEPTH_BUFFER_BIT;
6056 if (Flags & D3DCLEAR_TARGET) {
6057 TRACE("Clearing screen with glClear to color %lx\n", Color);
6058 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
6059 glClearColor(D3DCOLOR_R(Color),
6060 D3DCOLOR_G(Color),
6061 D3DCOLOR_B(Color),
6062 D3DCOLOR_A(Color));
6063 checkGLcall("glClearColor");
6065 /* Clear ALL colors! */
6066 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6067 glMask = glMask | GL_COLOR_BUFFER_BIT;
6070 /* Now process each rect in turn */
6071 for (i = 0; i < Count || i == 0; i++) {
6073 if (curRect) {
6074 /* Note gl uses lower left, width/height */
6075 TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect,
6076 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
6077 curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6078 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6079 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height - curRect->y2),
6080 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
6081 checkGLcall("glScissor");
6082 } else {
6083 glScissor(This->stateBlock->viewport.X,
6084 (((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height -
6085 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
6086 This->stateBlock->viewport.Width,
6087 This->stateBlock->viewport.Height);
6088 checkGLcall("glScissor");
6091 /* Clear the selected rectangle (or full screen) */
6092 glClear(glMask);
6093 checkGLcall("glClear");
6095 /* Step to the next rectangle */
6096 if (curRect) curRect = curRect + sizeof(D3DRECT);
6099 /* Restore the old values (why..?) */
6100 if (Flags & D3DCLEAR_STENCIL) {
6101 glClearStencil(old_stencil_clear_value);
6102 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
6104 if (Flags & D3DCLEAR_ZBUFFER) {
6105 glDepthMask(old_ztest);
6106 glClearDepth(old_z_clear_value);
6108 if (Flags & D3DCLEAR_TARGET) {
6109 glClearColor(old_color_clear_value[0],
6110 old_color_clear_value[1],
6111 old_color_clear_value[2],
6112 old_color_clear_value[3]);
6113 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
6114 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
6115 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
6116 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
6119 glDisable(GL_SCISSOR_TEST);
6120 checkGLcall("glDisable");
6121 LEAVE_GL();
6123 return WINED3D_OK;
6126 /*****
6127 * Drawing functions
6128 *****/
6129 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
6130 UINT PrimitiveCount) {
6132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6133 This->stateBlock->streamIsUP = FALSE;
6135 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
6136 debug_d3dprimitivetype(PrimitiveType),
6137 StartVertex, PrimitiveCount);
6138 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
6139 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */, NULL);
6142 return WINED3D_OK;
6145 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
6146 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
6147 D3DPRIMITIVETYPE PrimitiveType,
6148 INT baseVIndex, UINT minIndex,
6149 UINT NumVertices, UINT startIndex, UINT primCount) {
6151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6152 UINT idxStride = 2;
6153 IWineD3DIndexBuffer *pIB;
6154 WINED3DINDEXBUFFER_DESC IdxBufDsc;
6156 pIB = This->stateBlock->pIndexData;
6157 This->stateBlock->streamIsUP = FALSE;
6159 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, baseVidx=%d, countP=%d\n", This,
6160 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6161 minIndex, NumVertices, startIndex, baseVIndex, primCount);
6163 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
6164 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
6165 idxStride = 2;
6166 } else {
6167 idxStride = 4;
6170 drawPrimitive(iface, PrimitiveType, primCount, baseVIndex, NumVertices, startIndex,
6171 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex, NULL);
6173 return WINED3D_OK;
6176 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6177 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
6178 UINT VertexStreamZeroStride) {
6179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6181 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
6182 debug_d3dprimitivetype(PrimitiveType),
6183 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
6185 /* release the stream source */
6186 if (This->stateBlock->streamSource[0] != NULL) {
6187 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6190 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6191 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6192 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6193 This->stateBlock->streamIsUP = TRUE;
6195 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
6196 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */, NULL);
6198 /* MSDN specifies stream zero settings must be set to NULL */
6199 This->stateBlock->streamStride[0] = 0;
6200 This->stateBlock->streamSource[0] = NULL;
6202 /*stream zero settings set to null at end, as per the msdn */
6203 return WINED3D_OK;
6206 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType,
6207 UINT MinVertexIndex, UINT NumVertices,
6208 UINT PrimitiveCount, CONST void* pIndexData,
6209 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
6210 UINT VertexStreamZeroStride) {
6211 int idxStride;
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6214 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
6215 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
6216 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
6217 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
6219 if (IndexDataFormat == WINED3DFMT_INDEX16) {
6220 idxStride = 2;
6221 } else {
6222 idxStride = 4;
6225 /* release the stream and index data */
6226 if (This->stateBlock->streamSource[0] != NULL) {
6227 IWineD3DVertexBuffer_Release(This->stateBlock->streamSource[0]);
6229 if (This->stateBlock->pIndexData) {
6230 IWineD3DIndexBuffer_Release(This->stateBlock->pIndexData);
6233 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
6234 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
6235 This->stateBlock->streamIsUP = TRUE;
6236 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
6238 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex, NULL);
6240 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
6241 This->stateBlock->streamSource[0] = NULL;
6242 This->stateBlock->streamStride[0] = 0;
6243 This->stateBlock->pIndexData = NULL;
6245 return WINED3D_OK;
6248 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
6250 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0, DrawPrimStrideData);
6251 return WINED3D_OK;
6253 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
6254 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
6255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6256 HRESULT hr = WINED3D_OK;
6257 WINED3DRESOURCETYPE sourceType;
6258 WINED3DRESOURCETYPE destinationType;
6259 int i ,levels;
6261 /* TODO: think about moving the code into IWineD3DBaseTexture */
6263 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
6265 /* verify that the source and destination textures aren't NULL */
6266 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
6267 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
6268 This, pSourceTexture, pDestinationTexture);
6269 hr = WINED3DERR_INVALIDCALL;
6272 if (pSourceTexture == pDestinationTexture) {
6273 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
6274 This, pSourceTexture, pDestinationTexture);
6275 hr = WINED3DERR_INVALIDCALL;
6277 /* Verify that the source and destination textures are the same type */
6278 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
6279 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
6281 if (sourceType != destinationType) {
6282 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
6283 This);
6284 hr = WINED3DERR_INVALIDCALL;
6287 /* check that both textures have the identical numbers of levels */
6288 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
6289 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
6290 hr = WINED3DERR_INVALIDCALL;
6293 if (WINED3D_OK == hr) {
6295 /* Make sure that the destination texture is loaded */
6296 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
6298 /* Update every surface level of the texture */
6299 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
6301 switch (sourceType) {
6302 case WINED3DRTYPE_TEXTURE:
6304 IWineD3DSurface *srcSurface;
6305 IWineD3DSurface *destSurface;
6307 for (i = 0 ; i < levels ; ++i) {
6308 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
6309 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
6310 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6311 IWineD3DSurface_Release(srcSurface);
6312 IWineD3DSurface_Release(destSurface);
6313 if (WINED3D_OK != hr) {
6314 WARN("(%p) : Call to update surface failed\n", This);
6315 return hr;
6319 break;
6320 case WINED3DRTYPE_CUBETEXTURE:
6322 IWineD3DSurface *srcSurface;
6323 IWineD3DSurface *destSurface;
6324 WINED3DCUBEMAP_FACES faceType;
6326 for (i = 0 ; i < levels ; ++i) {
6327 /* Update each cube face */
6328 for (faceType = D3DCUBEMAP_FACE_POSITIVE_X; faceType <= D3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
6329 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
6330 if (WINED3D_OK != hr) {
6331 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6332 } else {
6333 TRACE("Got srcSurface %p\n", srcSurface);
6335 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
6336 if (WINED3D_OK != hr) {
6337 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
6338 } else {
6339 TRACE("Got desrSurface %p\n", destSurface);
6341 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
6342 IWineD3DSurface_Release(srcSurface);
6343 IWineD3DSurface_Release(destSurface);
6344 if (WINED3D_OK != hr) {
6345 WARN("(%p) : Call to update surface failed\n", This);
6346 return hr;
6351 break;
6352 #if 0 /* TODO: Add support for volume textures */
6353 case WINED3DRTYPE_VOLUMETEXTURE:
6355 IWineD3DVolume srcVolume = NULL;
6356 IWineD3DSurface destVolume = NULL;
6358 for (i = 0 ; i < levels ; ++i) {
6359 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
6360 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
6361 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
6362 IWineD3DVolume_Release(srcSurface);
6363 IWineD3DVolume_Release(destSurface);
6364 if (WINED3D_OK != hr) {
6365 WARN("(%p) : Call to update volume failed\n", This);
6366 return hr;
6370 break;
6371 #endif
6372 default:
6373 FIXME("(%p) : Unsupported source and destination type\n", This);
6374 hr = WINED3DERR_INVALIDCALL;
6378 return hr;
6381 static HRESULT WINAPI IWineD3DDeviceImpl_StretchRect(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface,
6382 CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface,
6383 CONST RECT* pDestRect, WINED3DTEXTUREFILTERTYPE Filter) {
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 TRACE("(%p) : stub\n", This);
6387 return WINED3D_OK;
6389 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTargetData(IWineD3DDevice *iface, IWineD3DSurface *pRenderTarget, IWineD3DSurface *pSurface) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6391 /** TODO: remove remove casts to IWineD3DSurfaceImpl *
6392 * NOTE It may be best to move the code into surface to occomplish this
6393 ****************************************/
6395 WINED3DSURFACE_DESC surfaceDesc;
6396 unsigned int surfaceWidth, surfaceHeight;
6397 glDescriptor *targetGlDescription = NULL;
6398 glDescriptor *surfaceGlDescription = NULL;
6399 IWineD3DSwapChainImpl *container = NULL;
6401 IWineD3DSurface_GetGlDesc(pRenderTarget, &targetGlDescription);
6402 IWineD3DSurface_GetGlDesc(pSurface, &surfaceGlDescription);
6403 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
6405 surfaceDesc.Width = &surfaceWidth;
6406 surfaceDesc.Height = &surfaceHeight;
6407 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
6408 /* check to see if it's the backbuffer or the frontbuffer being requested (to make sure the data is up to date)*/
6410 /* Ok, I may need to setup some kind of active swapchain reference on the device */
6411 IWineD3DSurface_GetContainer(pRenderTarget, &IID_IWineD3DSwapChain, (void **)&container);
6412 ENTER_GL();
6413 /* TODO: opengl Context switching for swapchains etc... */
6414 if (NULL != container || pRenderTarget == This->renderTarget || pRenderTarget == This->depthStencilBuffer) {
6415 if (NULL != container && (pRenderTarget == container->backBuffer[0])) {
6416 glReadBuffer(GL_BACK);
6417 vcheckGLcall("glReadBuffer(GL_BACK)");
6418 } else if ((NULL != container && (pRenderTarget == container->frontBuffer)) || (pRenderTarget == This->renderTarget)) {
6419 glReadBuffer(GL_FRONT);
6420 vcheckGLcall("glReadBuffer(GL_FRONT)");
6421 } else if (pRenderTarget == This->depthStencilBuffer) {
6422 FIXME("Reading of depthstencil not yet supported\n");
6425 glReadPixels(surfaceGlDescription->target,
6426 surfaceGlDescription->level,
6427 surfaceWidth,
6428 surfaceHeight,
6429 surfaceGlDescription->glFormat,
6430 surfaceGlDescription->glType,
6431 (void *)IWineD3DSurface_GetData(pSurface));
6432 vcheckGLcall("glReadPixels(...)");
6433 if(NULL != container ){
6434 IWineD3DSwapChain_Release((IWineD3DSwapChain*) container);
6436 } else {
6437 IWineD3DBaseTexture *container;
6438 GLenum textureDimensions = GL_TEXTURE_2D;
6440 if (WINED3D_OK == IWineD3DSurface_GetContainer(pSurface, &IID_IWineD3DBaseTexture, (void **)&container)) {
6441 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(container);
6442 IWineD3DBaseTexture_Release(container);
6444 /* TODO: 2D -> Cube surface coppies etc.. */
6445 if (surfaceGlDescription->target != textureDimensions) {
6446 FIXME("(%p) : Texture dimension mismatch\n", This);
6448 glEnable(textureDimensions);
6449 vcheckGLcall("glEnable(GL_TEXTURE_...)");
6450 /* FIXME: this isn't correct, it need to add a dirty rect if nothing else... */
6451 glBindTexture(targetGlDescription->target, targetGlDescription->textureName);
6452 vcheckGLcall("glBindTexture");
6453 glGetTexImage(surfaceGlDescription->target,
6454 surfaceGlDescription->level,
6455 surfaceGlDescription->glFormat,
6456 surfaceGlDescription->glType,
6457 (void *)IWineD3DSurface_GetData(pSurface));
6458 glDisable(textureDimensions);
6459 vcheckGLcall("glDisable(GL_TEXTURE_...)");
6462 LEAVE_GL();
6463 return WINED3D_OK;
6466 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
6467 IWineD3DSwapChain *swapChain;
6468 HRESULT hr;
6469 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6470 if(hr == WINED3D_OK) {
6471 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
6472 IWineD3DSwapChain_Release(swapChain);
6474 return hr;
6477 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
6478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6479 /* return a sensible default */
6480 *pNumPasses = 1;
6481 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
6482 FIXME("(%p) : stub\n", This);
6483 return WINED3D_OK;
6486 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6488 int j;
6489 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6490 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6491 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6492 return WINED3DERR_INVALIDCALL;
6494 for (j = 0; j < 256; ++j) {
6495 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6496 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6497 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6498 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6500 TRACE("(%p) : returning\n", This);
6501 return WINED3D_OK;
6504 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6506 int j;
6507 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6508 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6509 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6510 return WINED3DERR_INVALIDCALL;
6512 for (j = 0; j < 256; ++j) {
6513 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6514 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6515 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6516 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6518 TRACE("(%p) : returning\n", This);
6519 return WINED3D_OK;
6522 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6524 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6525 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
6526 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6527 return WINED3DERR_INVALIDCALL;
6529 /*TODO: stateblocks */
6530 This->currentPalette = PaletteNumber;
6531 TRACE("(%p) : returning\n", This);
6532 return WINED3D_OK;
6535 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6537 if (PaletteNumber == NULL) {
6538 WARN("(%p) : returning Invalid Call\n", This);
6539 return WINED3DERR_INVALIDCALL;
6541 /*TODO: stateblocks */
6542 *PaletteNumber = This->currentPalette;
6543 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6544 return WINED3D_OK;
6547 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6549 static BOOL showFixmes = TRUE;
6550 if (showFixmes) {
6551 FIXME("(%p) : stub\n", This);
6552 showFixmes = FALSE;
6555 This->softwareVertexProcessing = bSoftware;
6556 return WINED3D_OK;
6560 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6562 static BOOL showFixmes = TRUE;
6563 if (showFixmes) {
6564 FIXME("(%p) : stub\n", This);
6565 showFixmes = FALSE;
6567 return This->softwareVertexProcessing;
6571 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6573 IWineD3DSwapChain *swapChain;
6574 HRESULT hr;
6576 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6578 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
6579 if(hr == WINED3D_OK){
6580 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6581 IWineD3DSwapChain_Release(swapChain);
6582 }else{
6583 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6585 return hr;
6589 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6591 static BOOL showfixmes = TRUE;
6592 if(nSegments != 0.0f) {
6593 if( showfixmes) {
6594 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6595 showfixmes = FALSE;
6598 return WINED3D_OK;
6601 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6603 static BOOL showfixmes = TRUE;
6604 if( showfixmes) {
6605 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6606 showfixmes = FALSE;
6608 return 0.0f;
6611 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6613 /** TODO: remove casts to IWineD3DSurfaceImpl
6614 * NOTE: move code to surface to accomplish this
6615 ****************************************/
6616 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6617 int srcWidth, srcHeight;
6618 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6619 WINED3DFORMAT destFormat, srcFormat;
6620 UINT destSize;
6621 int destLeft, destTop;
6622 WINED3DPOOL srcPool, destPool;
6623 int offset = 0;
6624 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6625 glDescriptor *glDescription = NULL;
6626 GLenum textureDimensions = GL_TEXTURE_2D;
6627 IWineD3DBaseTexture *baseTexture;
6629 WINED3DSURFACE_DESC winedesc;
6631 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6632 memset(&winedesc, 0, sizeof(winedesc));
6633 winedesc.Width = &srcSurfaceWidth;
6634 winedesc.Height = &srcSurfaceHeight;
6635 winedesc.Pool = &srcPool;
6636 winedesc.Format = &srcFormat;
6638 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6640 winedesc.Width = &destSurfaceWidth;
6641 winedesc.Height = &destSurfaceHeight;
6642 winedesc.Pool = &destPool;
6643 winedesc.Format = &destFormat;
6644 winedesc.Size = &destSize;
6646 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6648 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6649 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6650 return WINED3DERR_INVALIDCALL;
6653 if (destFormat == WINED3DFMT_UNKNOWN) {
6654 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6655 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6657 /* Get the update surface description */
6658 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6661 /* Make sure the surface is loaded and up to date */
6662 IWineD3DSurface_PreLoad(pDestinationSurface);
6664 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6666 ENTER_GL();
6668 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6669 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6670 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
6671 destLeft = pDestPoint ? pDestPoint->x : 0;
6672 destTop = pDestPoint ? pDestPoint->y : 0;
6675 /* This function doesn't support compressed textures
6676 the pitch is just bytesPerPixel * width */
6677 if(srcWidth != srcSurfaceWidth || (pSourceRect != NULL && pSourceRect->left != 0) ){
6678 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
6679 offset += pSourceRect->left * pSrcSurface->bytesPerPixel;
6680 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6682 /* TODO DXT formats */
6684 if(pSourceRect != NULL && pSourceRect->top != 0){
6685 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
6687 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
6688 ,This
6689 ,glDescription->level
6690 ,destLeft
6691 ,destTop
6692 ,srcWidth
6693 ,srcHeight
6694 ,glDescription->glFormat
6695 ,glDescription->glType
6696 ,IWineD3DSurface_GetData(pSourceSurface)
6699 /* Sanity check */
6700 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6702 /* need to lock the surface to get the data */
6703 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6706 /* TODO: Cube and volume support */
6707 if(rowoffset != 0){
6708 /* not a whole row so we have to do it a line at a time */
6709 int j;
6711 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
6712 unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6714 for(j = destTop ; j < (srcHeight + destTop) ; j++){
6716 glTexSubImage2D(glDescription->target
6717 ,glDescription->level
6718 ,destLeft
6720 ,srcWidth
6722 ,glDescription->glFormat
6723 ,glDescription->glType
6724 ,data /* could be quicker using */
6726 data += rowoffset;
6729 } else { /* Full width, so just write out the whole texture */
6731 if (WINED3DFMT_DXT1 == destFormat ||
6732 WINED3DFMT_DXT2 == destFormat ||
6733 WINED3DFMT_DXT3 == destFormat ||
6734 WINED3DFMT_DXT4 == destFormat ||
6735 WINED3DFMT_DXT5 == destFormat) {
6736 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6737 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6738 /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
6739 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6740 } if (destFormat != srcFormat) {
6741 FIXME("Updating mixed format compressed texture is not curretly support\n");
6742 } else {
6743 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
6744 glDescription->level,
6745 glDescription->glFormatInternal,
6746 srcWidth,
6747 srcHeight,
6749 destSize,
6750 IWineD3DSurface_GetData(pSourceSurface));
6752 } else {
6753 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6757 } else {
6758 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
6760 /* some applications cannot handle odd pitches returned by soft non-power2, so we have
6761 to repack the data from pow2Width/Height to expected Width,Height, this makes the
6762 data returned by GetData non-power2 width/height with hardware non-power2
6763 pow2Width/height are set to surface width height, repacking isn't needed so it
6764 doesn't matter which function gets called. */
6765 glTexSubImage2D(glDescription->target
6766 ,glDescription->level
6767 ,destLeft
6768 ,destTop
6769 ,srcWidth
6770 ,srcHeight
6771 ,glDescription->glFormat
6772 ,glDescription->glType
6773 ,IWineD3DSurface_GetData(pSourceSurface)
6775 } else {
6777 /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */
6778 glTexSubImage2D(glDescription->target
6779 ,glDescription->level
6780 ,destLeft
6781 ,destTop
6782 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width
6783 ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height
6784 ,glDescription->glFormat
6785 ,glDescription->glType
6786 ,IWineD3DSurface_GetData(pSourceSurface)
6792 checkGLcall("glTexSubImage2D");
6793 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
6795 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
6796 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
6797 * surface bigger than it needs to be hmm.. */
6798 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
6799 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
6800 IWineD3DBaseTexture_Release(baseTexture);
6803 glDisable(textureDimensions); /* This needs to be managed better.... */
6804 LEAVE_GL();
6806 return WINED3D_OK;
6809 /* Used by DirectX 8 */
6810 static HRESULT WINAPI IWineD3DDeviceImpl_CopyRects(IWineD3DDevice *iface,
6811 IWineD3DSurface* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects,
6812 IWineD3DSurface* pDestinationSurface, CONST POINT* pDestPointsArray) {
6814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6815 HRESULT hr = WINED3D_OK;
6816 WINED3DFORMAT srcFormat, destFormat;
6817 UINT srcWidth, destWidth;
6818 UINT srcHeight, destHeight;
6819 UINT srcSize;
6820 WINED3DSURFACE_DESC winedesc;
6822 TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This,
6823 pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray);
6826 /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */
6827 memset(&winedesc, 0, sizeof(winedesc));
6829 winedesc.Format = &srcFormat;
6830 winedesc.Width = &srcWidth;
6831 winedesc.Height = &srcHeight;
6832 winedesc.Size = &srcSize;
6833 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6835 winedesc.Format = &destFormat;
6836 winedesc.Width = &destWidth;
6837 winedesc.Height = &destHeight;
6838 winedesc.Size = NULL;
6839 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6841 /* Check that the source and destination formats match */
6842 if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) {
6843 WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", This, pSourceSurface, pDestinationSurface);
6844 return WINED3DERR_INVALIDCALL;
6845 } else if (WINED3DFMT_UNKNOWN == destFormat) {
6846 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6847 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6848 destFormat = srcFormat;
6851 /* Quick if complete copy ... */
6852 if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) {
6854 if (srcWidth == destWidth && srcHeight == destHeight) {
6855 WINED3DLOCKED_RECT lrSrc;
6856 WINED3DLOCKED_RECT lrDst;
6857 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, NULL, WINED3DLOCK_READONLY);
6858 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, NULL, 0L);
6859 TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", srcWidth, srcHeight);
6861 memcpy(lrDst.pBits, lrSrc.pBits, srcSize);
6863 IWineD3DSurface_UnlockRect(pSourceSurface);
6864 IWineD3DSurface_UnlockRect(pDestinationSurface);
6865 TRACE("Unlocked src and dst\n");
6867 } else {
6869 FIXME("Wanted to copy all surfaces but size not compatible, returning WINED3DERR_INVALIDCALL\n");
6870 hr = WINED3DERR_INVALIDCALL;
6873 } else {
6875 if (NULL != pSourceRectsArray && NULL != pDestPointsArray) {
6877 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6878 unsigned int i;
6880 /* Copy rect by rect */
6881 for (i = 0; i < cRects; ++i) {
6882 CONST RECT* r = &pSourceRectsArray[i];
6883 CONST POINT* p = &pDestPointsArray[i];
6884 int copyperline;
6885 int j;
6886 WINED3DLOCKED_RECT lrSrc;
6887 WINED3DLOCKED_RECT lrDst;
6888 RECT dest_rect;
6890 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y);
6891 if (srcFormat == WINED3DFMT_DXT1) {
6892 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6893 } else {
6894 copyperline = ((r->right - r->left) * bytesPerPixel);
6897 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6898 dest_rect.left = p->x;
6899 dest_rect.top = p->y;
6900 dest_rect.right = p->x + (r->right - r->left);
6901 dest_rect.bottom= p->y + (r->bottom - r->top);
6902 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6903 TRACE("Locked src and dst\n");
6905 /* Find where to start */
6906 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6907 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6909 IWineD3DSurface_UnlockRect(pSourceSurface);
6910 IWineD3DSurface_UnlockRect(pDestinationSurface);
6911 TRACE("Unlocked src and dst\n");
6913 } else {
6914 unsigned int i;
6915 int bytesPerPixel = ((IWineD3DSurfaceImpl *) pSourceSurface)->bytesPerPixel;
6916 int copyperline;
6917 int j;
6918 WINED3DLOCKED_RECT lrSrc;
6919 WINED3DLOCKED_RECT lrDst;
6920 RECT dest_rect;
6922 for(i=0; i < cRects; i++) {
6923 CONST RECT* r = &pSourceRectsArray[i];
6925 TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (0, 0)\n", i, r->left, r->top, r->right, r->bottom);
6926 if (srcFormat == WINED3DFMT_DXT1) {
6927 copyperline = ((r->right - r->left) * bytesPerPixel) / 2; /* DXT1 is half byte per pixel */
6928 } else {
6929 copyperline = ((r->right - r->left) * bytesPerPixel);
6931 IWineD3DSurface_LockRect(pSourceSurface, &lrSrc, r, WINED3DLOCK_READONLY);
6932 dest_rect.left = 0;
6933 dest_rect.top = 0;
6934 dest_rect.right = r->right - r->left;
6935 dest_rect.bottom= r->bottom - r->top;
6936 IWineD3DSurface_LockRect(pDestinationSurface, &lrDst, &dest_rect, 0L);
6937 TRACE("Locked src and dst\n");
6938 /* Find where to start */
6939 for (j = 0; j < (r->bottom - r->top - 1); ++j) {
6940 memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline);
6942 IWineD3DSurface_UnlockRect(pSourceSurface);
6943 IWineD3DSurface_UnlockRect(pDestinationSurface);
6944 TRACE("Unlocked src and dst\n");
6949 return hr;
6952 /* Implementation details at http://developer.nvidia.com/attach/6494
6954 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
6955 hmm.. no longer supported use
6956 OpenGL evaluators or tessellate surfaces within your application.
6959 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
6960 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6962 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6963 FIXME("(%p) : Stub\n", This);
6964 return WINED3D_OK;
6968 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
6969 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6971 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6972 FIXME("(%p) : Stub\n", This);
6973 return WINED3D_OK;
6976 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6978 TRACE("(%p) Handle(%d)\n", This, Handle);
6979 FIXME("(%p) : Stub\n", This);
6980 return WINED3D_OK;
6983 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST D3DRECT* pRect, D3DCOLOR color) {
6984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6985 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6986 DDBLTFX BltFx;
6987 TRACE("(%p) Colour fill Surface: %p rect: %p color: %ld\n", This, pSurface, pRect, color);
6989 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6990 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6991 return WINED3DERR_INVALIDCALL;
6994 /* Just forward this to the DirectDraw blitting engine */
6995 memset(&BltFx, 0, sizeof(BltFx));
6996 BltFx.dwSize = sizeof(BltFx);
6997 BltFx.u5.dwFillColor = color;
6998 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
7001 /* rendertarget and deptth stencil functions */
7002 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
7003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7005 /* FIXME: Implelent RenderTargetIndex >0 */
7006 if(RenderTargetIndex > 0)
7007 FIXME("(%p) : RenderTargetIndex %ld >0 not currently supported\n", This, RenderTargetIndex);
7009 *ppRenderTarget = This->renderTarget;
7010 TRACE("(%p) : RenderTarget %ld Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
7011 /* Note inc ref on returned surface */
7012 if(*ppRenderTarget != NULL)
7013 IWineD3DSurface_AddRef(*ppRenderTarget);
7014 return WINED3D_OK;
7017 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
7018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7019 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
7020 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
7021 IWineD3DSwapChainImpl *Swapchain;
7022 HRESULT hr;
7024 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
7026 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
7027 if(hr != WINED3D_OK) {
7028 ERR("Can't get the swapchain\n");
7029 return hr;
7032 /* Make sure to release the swapchain */
7033 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
7035 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
7036 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7037 return WINED3DERR_INVALIDCALL;
7039 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7040 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
7041 return WINED3DERR_INVALIDCALL;
7044 if(Swapchain->frontBuffer != Front) {
7045 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
7047 if(Swapchain->frontBuffer)
7048 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
7049 Swapchain->frontBuffer = Front;
7051 if(Swapchain->frontBuffer) {
7052 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
7056 if(Back && !Swapchain->backBuffer) {
7057 /* We need memory for the back buffer array - only one back buffer this way */
7058 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
7059 if(!Swapchain->backBuffer) {
7060 ERR("Out of memory\n");
7061 return E_OUTOFMEMORY;
7065 if(Swapchain->backBuffer[0] != Back) {
7066 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
7067 ENTER_GL();
7068 if(!Swapchain->backBuffer[0]) {
7069 /* GL was told to draw to the front buffer at creation,
7070 * undo that
7072 glDrawBuffer(GL_BACK);
7073 checkGLcall("glDrawBuffer(GL_BACK)");
7074 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
7075 Swapchain->presentParms.BackBufferCount = 1;
7076 } else if (!Back) {
7077 /* That makes problems - disable for now */
7078 /* glDrawBuffer(GL_FRONT); */
7079 checkGLcall("glDrawBuffer(GL_FRONT)");
7080 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
7081 Swapchain->presentParms.BackBufferCount = 0;
7083 LEAVE_GL();
7085 if(Swapchain->backBuffer[0])
7086 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
7087 Swapchain->backBuffer[0] = Back;
7089 if(Swapchain->backBuffer[0]) {
7090 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
7091 } else {
7092 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
7097 return WINED3D_OK;
7100 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
7101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7102 *ppZStencilSurface = This->depthStencilBuffer;
7103 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
7105 if(*ppZStencilSurface != NULL) {
7106 /* Note inc ref on returned surface */
7107 IWineD3DSurface_AddRef(*ppZStencilSurface);
7109 return WINED3D_OK;
7112 /* internal static helper functions */
7113 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7114 IWineD3DSurface *RenderSurface);
7116 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7118 HRESULT hr = WINED3D_OK;
7119 WINED3DVIEWPORT viewport;
7121 TRACE("(%p) Swapping rendertarget\n",This);
7122 if (RenderTargetIndex > 0) {
7123 FIXME("(%p) Render targets other than the first are not supported\n",This);
7124 RenderTargetIndex = 0;
7127 /* MSDN says that null disables the render target
7128 but a device must always be associated with a render target
7129 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7131 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
7132 for more details
7134 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7135 FIXME("Trying to set render target 0 to NULL\n");
7136 return WINED3DERR_INVALIDCALL;
7138 /* TODO: replace Impl* usage with interface usage */
7139 if (!((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
7140 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);
7141 return WINED3DERR_INVALIDCALL;
7143 /** TODO: check that the depth stencil format matches the render target, this is only done in debug
7144 * builds, but I think wine counts as a 'debug' build for now.
7145 ******************************/
7146 /* If we are trying to set what we already have, don't bother */
7147 if (pRenderTarget == This->renderTarget) {
7148 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7149 } else {
7150 /* Otherwise, set the render target up */
7152 if (!This->sceneEnded) {
7153 IWineD3DDevice_EndScene(iface);
7155 TRACE("clearing renderer\n");
7156 /* IWineD3DDeviceImpl_CleanRender(iface); */
7157 /* OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7158 depending on the renter target implementation being used.
7159 A shared context implementation will share all buffers between all rendertargets (including swapchains),
7160 implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7161 stencil buffer and incure an extra memory overhead */
7162 hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
7165 if (SUCCEEDED(hr)) {
7166 /* Finally, reset the viewport as the MSDN states. */
7167 /* TODO: Replace impl usage */
7168 viewport.Height = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Height;
7169 viewport.Width = ((IWineD3DSurfaceImpl *)This->renderTarget)->currentDesc.Width;
7170 viewport.X = 0;
7171 viewport.Y = 0;
7172 viewport.MaxZ = 1.0f;
7173 viewport.MinZ = 0.0f;
7174 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7175 } else {
7176 FIXME("Unknown error setting the render target\n");
7178 This->sceneEnded = FALSE;
7179 return hr;
7182 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7184 HRESULT hr = WINED3D_OK;
7185 IWineD3DSurface *tmp;
7187 TRACE("(%p) Swapping z-buffer\n",This);
7189 if (pNewZStencil == This->stencilBufferTarget) {
7190 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7191 } else {
7192 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
7193 * depending on the renter target implementation being used.
7194 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7195 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7196 * stencil buffer and incure an extra memory overhead
7197 ******************************************************/
7200 tmp = This->stencilBufferTarget;
7201 This->stencilBufferTarget = pNewZStencil;
7202 /* should we be calling the parent or the wined3d surface? */
7203 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7204 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7205 hr = WINED3D_OK;
7206 /** TODO: glEnable/glDisable on depth/stencil depending on
7207 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
7208 **********************************************************/
7211 return hr;
7215 #ifdef GL_VERSION_1_3
7216 /* Internal functions not in DirectX */
7217 /** TODO: move this off to the opengl context manager
7218 *(the swapchain doesn't need to know anything about offscreen rendering!)
7219 ****************************************************/
7221 static HRESULT WINAPI IWineD3DDeviceImpl_CleanRender(IWineD3DDevice* iface, IWineD3DSwapChainImpl *swapchain)
7223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7225 TRACE("(%p), %p\n", This, swapchain);
7227 if (swapchain->win != swapchain->drawable) {
7228 /* Set everything back the way it ws */
7229 swapchain->render_ctx = swapchain->glCtx;
7230 swapchain->drawable = swapchain->win;
7232 return WINED3D_OK;
7235 /* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
7236 static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
7237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7238 int i;
7239 unsigned int width;
7240 unsigned int height;
7241 WINED3DFORMAT format;
7242 WINED3DSURFACE_DESC surfaceDesc;
7243 memset(&surfaceDesc, 0, sizeof(surfaceDesc));
7244 surfaceDesc.Width = &width;
7245 surfaceDesc.Height = &height;
7246 surfaceDesc.Format = &format;
7247 IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
7248 *context = NULL;
7249 /* I need a get width/height function (and should do something with the format) */
7250 for (i = 0; i < CONTEXT_CACHE; ++i) {
7251 /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
7252 ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
7253 the pSurface can be set to 0 allowing it to be reused from cache **/
7254 if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
7255 && (!pbuffer_per_surface || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
7256 *context = &This->contextCache[i];
7257 break;
7259 if (This->contextCache[i].Width == 0) {
7260 This->contextCache[i].pSurface = pSurface;
7261 This->contextCache[i].Width = width;
7262 This->contextCache[i].Height = height;
7263 *context = &This->contextCache[i];
7264 break;
7267 if (i == CONTEXT_CACHE) {
7268 int minUsage = 0x7FFFFFFF; /* MAX_INT */
7269 glContext *dropContext = 0;
7270 for (i = 0; i < CONTEXT_CACHE; i++) {
7271 if (This->contextCache[i].usedcount < minUsage) {
7272 dropContext = &This->contextCache[i];
7273 minUsage = This->contextCache[i].usedcount;
7276 /* clean up the context (this doesn't work for ATI at the moment */
7277 #if 0
7278 glXDestroyContext(swapchain->display, dropContext->context);
7279 glXDestroyPbuffer(swapchain->display, dropContext->drawable);
7280 #endif
7281 FIXME("Leak\n");
7282 dropContext->Width = 0;
7283 dropContext->pSurface = pSurface;
7284 *context = dropContext;
7285 } else {
7286 if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
7287 for (i = 0; i < CONTEXT_CACHE; i++) {
7288 This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
7292 if (*context != NULL)
7293 return WINED3D_OK;
7294 else
7295 return E_OUTOFMEMORY;
7297 #endif
7299 /* Reapply the device stateblock */
7300 static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
7302 BOOL oldRecording;
7303 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7305 /* Disable recording */
7306 oldUpdateStateBlock = This->updateStateBlock;
7307 oldRecording= This->isRecordingState;
7308 This->isRecordingState = FALSE;
7309 This->updateStateBlock = This->stateBlock;
7311 /* Reapply the state block */
7312 IWineD3DStateBlock_Apply((IWineD3DStateBlock *)This->stateBlock);
7314 /* Restore recording */
7315 This->isRecordingState = oldRecording;
7316 This->updateStateBlock = oldUpdateStateBlock;
7319 /* Set the device to render to a texture, or not.
7320 * This involves changing renderUpsideDown */
7322 static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
7324 DWORD cullMode;
7325 BOOL oldRecording;
7326 IWineD3DStateBlockImpl *oldUpdateStateBlock;
7328 /* Disable recording */
7329 oldUpdateStateBlock = This->updateStateBlock;
7330 oldRecording= This->isRecordingState;
7331 This->isRecordingState = FALSE;
7332 This->updateStateBlock = This->stateBlock;
7334 /* Set upside-down rendering, and update the cull mode */
7335 /* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
7336 This->renderUpsideDown = isTexture;
7337 This->last_was_rhw = FALSE;
7338 This->proj_valid = FALSE;
7339 IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
7340 IWineD3DDevice_SetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, cullMode);
7342 /* Restore recording */
7343 This->isRecordingState = oldRecording;
7344 This->updateStateBlock = oldUpdateStateBlock;
7347 /* Returns an array of compatible FBconfig(s).
7348 * The array must be freed with XFree. Requires ENTER_GL() */
7350 static GLXFBConfig* device_find_fbconfigs(
7351 IWineD3DDeviceImpl* This,
7352 IWineD3DSwapChainImpl* implicitSwapchainImpl,
7353 IWineD3DSurface* RenderSurface) {
7355 GLXFBConfig* cfgs = NULL;
7356 int nCfgs = 0;
7357 int attribs[256];
7358 int nAttribs = 0;
7360 IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
7361 D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
7362 D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
7364 /**TODO:
7365 if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
7366 it StencilSurface != NULL && zBufferTarget == NULL switch it on
7369 #define PUSH1(att) attribs[nAttribs++] = (att);
7370 #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value);
7372 /* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
7374 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
7375 PUSH2(GLX_X_RENDERABLE, TRUE);
7376 PUSH2(GLX_DOUBLEBUFFER, TRUE);
7377 TRACE("calling makeglcfg\n");
7378 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
7379 PUSH1(None);
7380 TRACE("calling chooseFGConfig\n");
7381 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7382 DefaultScreen(implicitSwapchainImpl->display),
7383 attribs, &nCfgs);
7384 if (cfgs == NULL) {
7385 /* OK we didn't find the exact config, so use any reasonable match */
7386 /* TODO: fill in the 'requested' and 'current' depths, and make sure that's
7387 why we failed. */
7388 static BOOL show_message = TRUE;
7389 if (show_message) {
7390 ERR("Failed to find exact match, finding alternative but you may "
7391 "suffer performance issues, try changing xfree's depth to match the requested depth\n");
7392 show_message = FALSE;
7394 nAttribs = 0;
7395 PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
7396 /* PUSH2(GLX_X_RENDERABLE, TRUE); */
7397 PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
7398 PUSH2(GLX_DOUBLEBUFFER, FALSE);
7399 TRACE("calling makeglcfg\n");
7400 D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
7401 PUSH1(None);
7402 cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
7403 DefaultScreen(implicitSwapchainImpl->display),
7404 attribs, &nCfgs);
7407 if (cfgs == NULL) {
7408 ERR("Could not get a valid FBConfig for (%u,%s)/(%u,%s)\n",
7409 BackBufferFormat, debug_d3dformat(BackBufferFormat),
7410 StencilBufferFormat, debug_d3dformat(StencilBufferFormat));
7411 } else {
7412 #ifdef EXTRA_TRACES
7413 int i;
7414 for (i = 0; i < nCfgs; ++i) {
7415 TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat,
7416 debug_d3dformat(BackBufferFormat), StencilBufferFormat,
7417 debug_d3dformat(StencilBufferFormat), i, cfgs[i]);
7419 if (NULL != This->renderTarget) {
7420 glFlush();
7421 vcheckGLcall("glFlush");
7422 /** This is only useful if the old render target was a swapchain,
7423 * we need to supercede this with a function that displays
7424 * the current buffer on the screen. This is easy to do in glx1.3 but
7425 * we need to do copy-write pixels in glx 1.2.
7426 ************************************************/
7427 glXSwapBuffers(implicitSwapChainImpl->display,
7428 implicitSwapChainImpl->drawable);
7429 printf("Hit Enter to get next frame ...\n");
7430 getchar();
7432 #endif
7434 #undef PUSH1
7435 #undef PUSH2
7437 return cfgs;
7440 /** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
7441 * the functionality needs splitting up so that we don't do more than we should do.
7442 * this only seems to impact performance a little.
7443 ******************************/
7444 static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
7445 IWineD3DSurface *RenderSurface) {
7448 * Currently only active for GLX >= 1.3
7449 * for others versions we'll have to use GLXPixmaps
7451 * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
7452 * as they implement GLX 1.3 but only define GLX_VERSION_1_2
7453 * so only check OpenGL version
7454 * ..........................
7455 * I don't believe that it is a problem with NVidia headers,
7456 * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
7457 * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
7458 * ATI Note:
7459 * Your application will report GLX version 1.2 on glXQueryVersion.
7460 * However, it is safe to call the GLX 1.3 functions as described below.
7462 #if defined(GL_VERSION_1_3)
7464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7465 GLXFBConfig* cfgs = NULL;
7466 IWineD3DSwapChain *currentSwapchain;
7467 IWineD3DSwapChainImpl *currentSwapchainImpl;
7468 IWineD3DSwapChain *implicitSwapchain;
7469 IWineD3DSwapChainImpl *implicitSwapchainImpl;
7470 IWineD3DSwapChain *renderSurfaceSwapchain;
7471 IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
7473 /* Obtain a reference to the device implicit swapchain,
7474 * the swapchain of the current render target,
7475 * and the swapchain of the new render target.
7476 * Fallback to device implicit swapchain if the current render target doesn't have one */
7477 IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
7478 IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
7479 IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&currentSwapchain);
7480 if (currentSwapchain == NULL)
7481 IWineD3DDevice_GetSwapChain(iface, 0, &currentSwapchain);
7483 currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
7484 implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
7485 renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
7487 ENTER_GL();
7490 * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
7491 * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
7492 **********************************************************************/
7493 if (renderSurfaceSwapchain != NULL) {
7495 /* We also need to make sure that the lights &co are also in the context of the swapchains */
7496 /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
7497 TRACE("making swapchain active\n");
7498 if (RenderSurface != This->renderTarget) {
7499 BOOL backbuf = FALSE;
7500 int i;
7502 for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
7503 if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
7504 backbuf = TRUE;
7505 break;
7509 if (backbuf) {
7510 } else {
7511 /* This could be flagged so that some operations work directly with the front buffer */
7512 FIXME("Attempting to set the renderTarget to the frontBuffer\n");
7514 if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
7515 renderSurfaceSwapchainImpl->win,
7516 renderSurfaceSwapchainImpl->glCtx) == False) {
7518 TRACE("Error in setting current context: context %p drawable %ld !\n",
7519 implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
7521 checkGLcall("glXMakeContextCurrent");
7523 /* Clean up the old context */
7524 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7526 /* Reapply the stateblock, and set the device not to render to texture */
7527 device_reapply_stateblock(This);
7528 device_render_to_texture(This, FALSE);
7531 /* Offscreen rendering: PBuffers (currently disabled).
7532 * Also note that this path is never reached if FBOs are supported */
7533 } else if (pbuffer_support &&
7534 (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
7536 /** ********************************************************************
7537 * This is a quickly hacked out implementation of offscreen textures.
7538 * It will work in most cases but there may be problems if the client
7539 * modifies the texture directly, or expects the contents of the rendertarget
7540 * to be persistent.
7542 * There are some real speed vs compatibility issues here:
7543 * we should really use a new context for every texture, but that eats ram.
7544 * we should also be restoring the texture to the pbuffer but that eats CPU
7545 * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
7546 * but if this means reusing the display backbuffer then we need to make sure that
7547 * states are correctly preserved.
7548 * In many cases I would expect that we can 'skip' some functions, such as preserving states,
7549 * and gain a good performance increase at the cost of compatibility.
7550 * I would suggest that, when this is the case, a user configurable flag be made
7551 * available, allowing the user to choose the best emulated experience for them.
7552 *********************************************************************/
7554 XVisualInfo *visinfo;
7555 glContext *newContext;
7557 /* Here were using a shared context model */
7558 if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
7559 FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7562 /* If the context doesn't exist then create a new one */
7563 /* TODO: This should really be part of findGlContext */
7564 if (NULL == newContext->context) {
7566 int attribs[256];
7567 int nAttribs = 0;
7569 TRACE("making new buffer\n");
7570 attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
7571 attribs[nAttribs++] = newContext->Width;
7572 attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
7573 attribs[nAttribs++] = newContext->Height;
7574 attribs[nAttribs++] = None;
7576 newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
7578 /** ****************************************
7579 *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
7580 *they note:
7581 * In future releases, we may provide the calls glXCreateNewContext,
7582 * glXQueryDrawable and glXMakeContextCurrent.
7583 * so until then we have to use glXGetVisualFromFBConfig &co..
7584 ********************************************/
7586 visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
7587 if (!visinfo) {
7588 ERR("Error: couldn't get an RGBA, double-buffered visual\n");
7589 } else {
7590 newContext->context = glXCreateContext(
7591 implicitSwapchainImpl->display, visinfo,
7592 implicitSwapchainImpl->glCtx, GL_TRUE);
7594 XFree(visinfo);
7597 if (NULL == newContext || NULL == newContext->context) {
7598 ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
7599 } else {
7600 /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
7601 if (glXMakeCurrent(implicitSwapchainImpl->display,
7602 newContext->drawable, newContext->context) == False) {
7604 TRACE("Error in setting current context: context %p drawable %ld\n",
7605 newContext->context, newContext->drawable);
7607 checkGLcall("glXMakeContextCurrent");
7609 /* Clean up the old context */
7610 IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
7612 /* Reapply stateblock, and set device to render to a texture */
7613 device_reapply_stateblock(This);
7614 device_render_to_texture(This, TRUE);
7616 /* Set the current context of the swapchain to the new context */
7617 implicitSwapchainImpl->drawable = newContext->drawable;
7618 implicitSwapchainImpl->render_ctx = newContext->context;
7620 } else {
7621 /* Same context, but update renderUpsideDown and cull mode */
7622 device_render_to_texture(This, TRUE);
7625 /* Replace the render target */
7626 if (This->renderTarget != RenderSurface) {
7627 IWineD3DSurface_Release(This->renderTarget);
7628 This->renderTarget = RenderSurface;
7629 IWineD3DSurface_AddRef(RenderSurface);
7632 if (cfgs != NULL) XFree(cfgs);
7633 if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
7634 if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
7635 if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
7636 LEAVE_GL();
7637 #endif
7638 return WINED3D_OK;
7641 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7642 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7644 /* TODO: the use of Impl is deprecated. */
7645 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7647 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7649 /* some basic validation checks */
7650 if(This->cursorTexture) {
7651 ENTER_GL();
7652 glDeleteTextures(1, &This->cursorTexture);
7653 LEAVE_GL();
7654 This->cursorTexture = 0;
7657 if(pCursorBitmap) {
7658 /* MSDN: Cursor must be A8R8G8B8 */
7659 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
7660 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7661 return WINED3DERR_INVALIDCALL;
7664 /* MSDN: Cursor must be smaller than the display mode */
7665 if(pSur->currentDesc.Width > This->ddraw_width ||
7666 pSur->currentDesc.Height > This->ddraw_height) {
7667 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %ldx%ld\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
7668 return WINED3DERR_INVALIDCALL;
7671 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7672 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
7673 * Texture and Blitting code to draw the cursor
7675 pSur->Flags |= SFLAG_FORCELOAD;
7676 IWineD3DSurface_PreLoad(pCursorBitmap);
7677 pSur->Flags &= ~SFLAG_FORCELOAD;
7678 /* Do not store the surface's pointer because the application may release
7679 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
7680 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
7682 This->cursorTexture = pSur->glDescription.textureName;
7683 This->cursorWidth = pSur->currentDesc.Width;
7684 This->cursorHeight = pSur->currentDesc.Height;
7685 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
7688 This->xHotSpot = XHotSpot;
7689 This->yHotSpot = YHotSpot;
7690 return WINED3D_OK;
7693 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7695 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7697 This->xScreenSpace = XScreenSpace;
7698 This->yScreenSpace = YScreenSpace;
7700 return;
7704 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7706 BOOL oldVisible = This->bCursorVisible;
7707 TRACE("(%p) : visible(%d)\n", This, bShow);
7709 if(This->cursorTexture)
7710 This->bCursorVisible = bShow;
7712 return oldVisible;
7715 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7717 TRACE("(%p) : state (%lu)\n", This, This->state);
7718 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
7719 switch (This->state) {
7720 case WINED3D_OK:
7721 return WINED3D_OK;
7722 case WINED3DERR_DEVICELOST:
7724 ResourceList *resourceList = This->resources;
7725 while (NULL != resourceList) {
7726 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
7727 return WINED3DERR_DEVICENOTRESET;
7728 resourceList = resourceList->next;
7730 return WINED3DERR_DEVICELOST;
7732 case WINED3DERR_DRIVERINTERNALERROR:
7733 return WINED3DERR_DRIVERINTERNALERROR;
7736 /* Unknown state */
7737 return WINED3DERR_DRIVERINTERNALERROR;
7741 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7743 /** FIXME: Resource tracking needs to be done,
7744 * The closes we can do to this is set the priorities of all managed textures low
7745 * and then reset them.
7746 ***********************************************************/
7747 FIXME("(%p) : stub\n", This);
7748 return WINED3D_OK;
7751 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7753 /** FIXME: Resource trascking needs to be done.
7754 * in effect this pulls all non only default
7755 * textures out of video memory and deletes all glTextures (glDeleteTextures)
7756 * and should clear down the context and set it up according to pPresentationParameters
7757 ***********************************************************/
7758 FIXME("(%p) : stub\n", This);
7759 return WINED3D_OK;
7762 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7764 /** FIXME: always true at the moment **/
7765 if(!bEnableDialogs) {
7766 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7768 return WINED3D_OK;
7772 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7774 TRACE("(%p) : pParameters %p\n", This, pParameters);
7776 *pParameters = This->createParms;
7777 return WINED3D_OK;
7780 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7781 IWineD3DSwapChain *swapchain;
7782 HRESULT hrc = WINED3D_OK;
7784 TRACE("Relaying to swapchain\n");
7786 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7787 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7788 IWineD3DSwapChain_Release(swapchain);
7790 return;
7793 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7794 IWineD3DSwapChain *swapchain;
7795 HRESULT hrc = WINED3D_OK;
7797 TRACE("Relaying to swapchain\n");
7799 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7800 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7801 IWineD3DSwapChain_Release(swapchain);
7803 return;
7807 /** ********************************************************
7808 * Notification functions
7809 ** ********************************************************/
7810 /** This function must be called in the release of a resource when ref == 0,
7811 * the contents of resource must still be correct,
7812 * any handels to other resource held by the caller must be closed
7813 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7814 *****************************************************/
7815 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7817 ResourceList* resourceList;
7819 TRACE("(%p) : resource %p\n", This, resource);
7820 #if 0
7821 EnterCriticalSection(&resourceStoreCriticalSection);
7822 #endif
7823 /* add a new texture to the frot of the linked list */
7824 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
7825 resourceList->resource = resource;
7827 /* Get the old head */
7828 resourceList->next = This->resources;
7830 This->resources = resourceList;
7831 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
7833 #if 0
7834 LeaveCriticalSection(&resourceStoreCriticalSection);
7835 #endif
7836 return;
7839 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7841 ResourceList* resourceList = NULL;
7842 ResourceList* previousResourceList = NULL;
7844 TRACE("(%p) : resource %p\n", This, resource);
7846 #if 0
7847 EnterCriticalSection(&resourceStoreCriticalSection);
7848 #endif
7849 resourceList = This->resources;
7851 while (resourceList != NULL) {
7852 if(resourceList->resource == resource) break;
7853 previousResourceList = resourceList;
7854 resourceList = resourceList->next;
7857 if (resourceList == NULL) {
7858 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
7859 #if 0
7860 LeaveCriticalSection(&resourceStoreCriticalSection);
7861 #endif
7862 return;
7863 } else {
7864 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
7866 /* make sure we don't leave a hole in the list */
7867 if (previousResourceList != NULL) {
7868 previousResourceList->next = resourceList->next;
7869 } else {
7870 This->resources = resourceList->next;
7873 #if 0
7874 LeaveCriticalSection(&resourceStoreCriticalSection);
7875 #endif
7876 return;
7880 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7882 int counter;
7884 TRACE("(%p) : resource %p\n", This, resource);
7885 switch(IWineD3DResource_GetType(resource)){
7886 case WINED3DRTYPE_SURFACE:
7887 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7888 break;
7889 case WINED3DRTYPE_TEXTURE:
7890 case WINED3DRTYPE_CUBETEXTURE:
7891 case WINED3DRTYPE_VOLUMETEXTURE:
7892 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
7893 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7894 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7895 This->stateBlock->textures[counter] = NULL;
7897 if (This->updateStateBlock != This->stateBlock ){
7898 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7899 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7900 This->updateStateBlock->textures[counter] = NULL;
7904 break;
7905 case WINED3DRTYPE_VOLUME:
7906 /* TODO: nothing really? */
7907 break;
7908 case WINED3DRTYPE_VERTEXBUFFER:
7909 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7911 int streamNumber;
7912 TRACE("Cleaning up stream pointers\n");
7914 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7915 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7916 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7918 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7919 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7920 FIXME("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7921 This->updateStateBlock->streamSource[streamNumber] = 0;
7922 /* Set changed flag? */
7925 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) */
7926 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7927 TRACE("Vertex buffer released whlst bound to a state block stream %d\n", streamNumber);
7928 This->stateBlock->streamSource[streamNumber] = 0;
7931 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7932 else { /* This shouldn't happen */
7933 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7935 #endif
7939 break;
7940 case WINED3DRTYPE_INDEXBUFFER:
7941 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7942 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7943 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7944 This->updateStateBlock->pIndexData = NULL;
7947 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7948 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7949 This->stateBlock->pIndexData = NULL;
7953 break;
7954 default:
7955 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7956 break;
7960 /* Remove the resoruce from the resourceStore */
7961 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7963 TRACE("Resource released\n");
7967 /**********************************************************
7968 * IWineD3DDevice VTbl follows
7969 **********************************************************/
7971 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7973 /*** IUnknown methods ***/
7974 IWineD3DDeviceImpl_QueryInterface,
7975 IWineD3DDeviceImpl_AddRef,
7976 IWineD3DDeviceImpl_Release,
7977 /*** IWineD3DDevice methods ***/
7978 IWineD3DDeviceImpl_GetParent,
7979 /*** Creation methods**/
7980 IWineD3DDeviceImpl_CreateVertexBuffer,
7981 IWineD3DDeviceImpl_CreateIndexBuffer,
7982 IWineD3DDeviceImpl_CreateStateBlock,
7983 IWineD3DDeviceImpl_CreateSurface,
7984 IWineD3DDeviceImpl_CreateTexture,
7985 IWineD3DDeviceImpl_CreateVolumeTexture,
7986 IWineD3DDeviceImpl_CreateVolume,
7987 IWineD3DDeviceImpl_CreateCubeTexture,
7988 IWineD3DDeviceImpl_CreateQuery,
7989 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7990 IWineD3DDeviceImpl_CreateVertexDeclaration,
7991 IWineD3DDeviceImpl_CreateVertexShader,
7992 IWineD3DDeviceImpl_CreatePixelShader,
7993 IWineD3DDeviceImpl_CreatePalette,
7994 /*** Odd functions **/
7995 IWineD3DDeviceImpl_Init3D,
7996 IWineD3DDeviceImpl_Uninit3D,
7997 IWineD3DDeviceImpl_SetFullscreen,
7998 IWineD3DDeviceImpl_EnumDisplayModes,
7999 IWineD3DDeviceImpl_EvictManagedResources,
8000 IWineD3DDeviceImpl_GetAvailableTextureMem,
8001 IWineD3DDeviceImpl_GetBackBuffer,
8002 IWineD3DDeviceImpl_GetCreationParameters,
8003 IWineD3DDeviceImpl_GetDeviceCaps,
8004 IWineD3DDeviceImpl_GetDirect3D,
8005 IWineD3DDeviceImpl_GetDisplayMode,
8006 IWineD3DDeviceImpl_SetDisplayMode,
8007 IWineD3DDeviceImpl_GetHWND,
8008 IWineD3DDeviceImpl_SetHWND,
8009 IWineD3DDeviceImpl_GetNumberOfSwapChains,
8010 IWineD3DDeviceImpl_GetRasterStatus,
8011 IWineD3DDeviceImpl_GetSwapChain,
8012 IWineD3DDeviceImpl_Reset,
8013 IWineD3DDeviceImpl_SetDialogBoxMode,
8014 IWineD3DDeviceImpl_SetCursorProperties,
8015 IWineD3DDeviceImpl_SetCursorPosition,
8016 IWineD3DDeviceImpl_ShowCursor,
8017 IWineD3DDeviceImpl_TestCooperativeLevel,
8018 /*** Getters and setters **/
8019 IWineD3DDeviceImpl_SetClipPlane,
8020 IWineD3DDeviceImpl_GetClipPlane,
8021 IWineD3DDeviceImpl_SetClipStatus,
8022 IWineD3DDeviceImpl_GetClipStatus,
8023 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8024 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8025 IWineD3DDeviceImpl_SetDepthStencilSurface,
8026 IWineD3DDeviceImpl_GetDepthStencilSurface,
8027 IWineD3DDeviceImpl_SetFVF,
8028 IWineD3DDeviceImpl_GetFVF,
8029 IWineD3DDeviceImpl_SetGammaRamp,
8030 IWineD3DDeviceImpl_GetGammaRamp,
8031 IWineD3DDeviceImpl_SetIndices,
8032 IWineD3DDeviceImpl_GetIndices,
8033 IWineD3DDeviceImpl_SetLight,
8034 IWineD3DDeviceImpl_GetLight,
8035 IWineD3DDeviceImpl_SetLightEnable,
8036 IWineD3DDeviceImpl_GetLightEnable,
8037 IWineD3DDeviceImpl_SetMaterial,
8038 IWineD3DDeviceImpl_GetMaterial,
8039 IWineD3DDeviceImpl_SetNPatchMode,
8040 IWineD3DDeviceImpl_GetNPatchMode,
8041 IWineD3DDeviceImpl_SetPaletteEntries,
8042 IWineD3DDeviceImpl_GetPaletteEntries,
8043 IWineD3DDeviceImpl_SetPixelShader,
8044 IWineD3DDeviceImpl_GetPixelShader,
8045 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8046 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8047 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8048 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8049 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8050 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8051 IWineD3DDeviceImpl_SetRenderState,
8052 IWineD3DDeviceImpl_GetRenderState,
8053 IWineD3DDeviceImpl_SetRenderTarget,
8054 IWineD3DDeviceImpl_GetRenderTarget,
8055 IWineD3DDeviceImpl_SetFrontBackBuffers,
8056 IWineD3DDeviceImpl_SetSamplerState,
8057 IWineD3DDeviceImpl_GetSamplerState,
8058 IWineD3DDeviceImpl_SetScissorRect,
8059 IWineD3DDeviceImpl_GetScissorRect,
8060 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8061 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8062 IWineD3DDeviceImpl_SetStreamSource,
8063 IWineD3DDeviceImpl_GetStreamSource,
8064 IWineD3DDeviceImpl_SetStreamSourceFreq,
8065 IWineD3DDeviceImpl_GetStreamSourceFreq,
8066 IWineD3DDeviceImpl_SetTexture,
8067 IWineD3DDeviceImpl_GetTexture,
8068 IWineD3DDeviceImpl_SetTextureStageState,
8069 IWineD3DDeviceImpl_GetTextureStageState,
8070 IWineD3DDeviceImpl_SetTransform,
8071 IWineD3DDeviceImpl_GetTransform,
8072 IWineD3DDeviceImpl_SetVertexDeclaration,
8073 IWineD3DDeviceImpl_GetVertexDeclaration,
8074 IWineD3DDeviceImpl_SetVertexShader,
8075 IWineD3DDeviceImpl_GetVertexShader,
8076 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8077 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8078 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8079 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8080 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8081 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8082 IWineD3DDeviceImpl_SetViewport,
8083 IWineD3DDeviceImpl_GetViewport,
8084 IWineD3DDeviceImpl_MultiplyTransform,
8085 IWineD3DDeviceImpl_ValidateDevice,
8086 IWineD3DDeviceImpl_ProcessVertices,
8087 /*** State block ***/
8088 IWineD3DDeviceImpl_BeginStateBlock,
8089 IWineD3DDeviceImpl_EndStateBlock,
8090 /*** Scene management ***/
8091 IWineD3DDeviceImpl_BeginScene,
8092 IWineD3DDeviceImpl_EndScene,
8093 IWineD3DDeviceImpl_Present,
8094 IWineD3DDeviceImpl_Clear,
8095 /*** Drawing ***/
8096 IWineD3DDeviceImpl_DrawPrimitive,
8097 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8098 IWineD3DDeviceImpl_DrawPrimitiveUP,
8099 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8100 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8101 IWineD3DDeviceImpl_DrawRectPatch,
8102 IWineD3DDeviceImpl_DrawTriPatch,
8103 IWineD3DDeviceImpl_DeletePatch,
8104 IWineD3DDeviceImpl_ColorFill,
8105 IWineD3DDeviceImpl_UpdateTexture,
8106 IWineD3DDeviceImpl_UpdateSurface,
8107 IWineD3DDeviceImpl_CopyRects,
8108 IWineD3DDeviceImpl_StretchRect,
8109 IWineD3DDeviceImpl_GetRenderTargetData,
8110 IWineD3DDeviceImpl_GetFrontBufferData,
8111 /*** Internal use IWineD3DDevice methods ***/
8112 IWineD3DDeviceImpl_SetupTextureStates,
8113 /*** object tracking ***/
8114 IWineD3DDeviceImpl_ResourceReleased
8118 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8119 WINED3DRS_ALPHABLENDENABLE ,
8120 WINED3DRS_ALPHAFUNC ,
8121 WINED3DRS_ALPHAREF ,
8122 WINED3DRS_ALPHATESTENABLE ,
8123 WINED3DRS_BLENDOP ,
8124 WINED3DRS_COLORWRITEENABLE ,
8125 WINED3DRS_DESTBLEND ,
8126 WINED3DRS_DITHERENABLE ,
8127 WINED3DRS_FILLMODE ,
8128 WINED3DRS_FOGDENSITY ,
8129 WINED3DRS_FOGEND ,
8130 WINED3DRS_FOGSTART ,
8131 WINED3DRS_LASTPIXEL ,
8132 WINED3DRS_SHADEMODE ,
8133 WINED3DRS_SRCBLEND ,
8134 WINED3DRS_STENCILENABLE ,
8135 WINED3DRS_STENCILFAIL ,
8136 WINED3DRS_STENCILFUNC ,
8137 WINED3DRS_STENCILMASK ,
8138 WINED3DRS_STENCILPASS ,
8139 WINED3DRS_STENCILREF ,
8140 WINED3DRS_STENCILWRITEMASK ,
8141 WINED3DRS_STENCILZFAIL ,
8142 WINED3DRS_TEXTUREFACTOR ,
8143 WINED3DRS_WRAP0 ,
8144 WINED3DRS_WRAP1 ,
8145 WINED3DRS_WRAP2 ,
8146 WINED3DRS_WRAP3 ,
8147 WINED3DRS_WRAP4 ,
8148 WINED3DRS_WRAP5 ,
8149 WINED3DRS_WRAP6 ,
8150 WINED3DRS_WRAP7 ,
8151 WINED3DRS_ZENABLE ,
8152 WINED3DRS_ZFUNC ,
8153 WINED3DRS_ZWRITEENABLE
8156 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8157 WINED3DTSS_ADDRESSW ,
8158 WINED3DTSS_ALPHAARG0 ,
8159 WINED3DTSS_ALPHAARG1 ,
8160 WINED3DTSS_ALPHAARG2 ,
8161 WINED3DTSS_ALPHAOP ,
8162 WINED3DTSS_BUMPENVLOFFSET ,
8163 WINED3DTSS_BUMPENVLSCALE ,
8164 WINED3DTSS_BUMPENVMAT00 ,
8165 WINED3DTSS_BUMPENVMAT01 ,
8166 WINED3DTSS_BUMPENVMAT10 ,
8167 WINED3DTSS_BUMPENVMAT11 ,
8168 WINED3DTSS_COLORARG0 ,
8169 WINED3DTSS_COLORARG1 ,
8170 WINED3DTSS_COLORARG2 ,
8171 WINED3DTSS_COLOROP ,
8172 WINED3DTSS_RESULTARG ,
8173 WINED3DTSS_TEXCOORDINDEX ,
8174 WINED3DTSS_TEXTURETRANSFORMFLAGS
8177 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8178 WINED3DSAMP_ADDRESSU ,
8179 WINED3DSAMP_ADDRESSV ,
8180 WINED3DSAMP_ADDRESSW ,
8181 WINED3DSAMP_BORDERCOLOR ,
8182 WINED3DSAMP_MAGFILTER ,
8183 WINED3DSAMP_MINFILTER ,
8184 WINED3DSAMP_MIPFILTER ,
8185 WINED3DSAMP_MIPMAPLODBIAS ,
8186 WINED3DSAMP_MAXMIPLEVEL ,
8187 WINED3DSAMP_MAXANISOTROPY ,
8188 WINED3DSAMP_SRGBTEXTURE ,
8189 WINED3DSAMP_ELEMENTINDEX
8192 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8193 WINED3DRS_AMBIENT ,
8194 WINED3DRS_AMBIENTMATERIALSOURCE ,
8195 WINED3DRS_CLIPPING ,
8196 WINED3DRS_CLIPPLANEENABLE ,
8197 WINED3DRS_COLORVERTEX ,
8198 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8199 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8200 WINED3DRS_FOGDENSITY ,
8201 WINED3DRS_FOGEND ,
8202 WINED3DRS_FOGSTART ,
8203 WINED3DRS_FOGTABLEMODE ,
8204 WINED3DRS_FOGVERTEXMODE ,
8205 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8206 WINED3DRS_LIGHTING ,
8207 WINED3DRS_LOCALVIEWER ,
8208 WINED3DRS_MULTISAMPLEANTIALIAS ,
8209 WINED3DRS_MULTISAMPLEMASK ,
8210 WINED3DRS_NORMALIZENORMALS ,
8211 WINED3DRS_PATCHEDGESTYLE ,
8212 WINED3DRS_POINTSCALE_A ,
8213 WINED3DRS_POINTSCALE_B ,
8214 WINED3DRS_POINTSCALE_C ,
8215 WINED3DRS_POINTSCALEENABLE ,
8216 WINED3DRS_POINTSIZE ,
8217 WINED3DRS_POINTSIZE_MAX ,
8218 WINED3DRS_POINTSIZE_MIN ,
8219 WINED3DRS_POINTSPRITEENABLE ,
8220 WINED3DRS_RANGEFOGENABLE ,
8221 WINED3DRS_SPECULARMATERIALSOURCE ,
8222 WINED3DRS_TWEENFACTOR ,
8223 WINED3DRS_VERTEXBLEND
8226 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8227 WINED3DTSS_TEXCOORDINDEX ,
8228 WINED3DTSS_TEXTURETRANSFORMFLAGS
8231 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8232 WINED3DSAMP_DMAPOFFSET